我可以在Python中的任何地方定义范围吗?

2024-04-30 01:56:27 发布

您现在位置:Python中文网/ 问答频道 /正文

有时我发现我不得不在几行代码中使用长名称的函数,例如os.path.abspath和{}alot。我不认为在全局名称空间中使用这样的函数是不值得的,但是能够在我需要这些函数的行周围定义一个范围将是非常有用的。作为一个例子,这将是完美的:

import os, sys

closure:
    abspath = os.path.abspath
    dirname = os.path.dirname

    # 15 lines of heavy usage of those functions

# Can't access abspath or dirname here

我很想知道这是否可行


Tags: ofpath函数代码import名称定义os
3条回答

简短的回答是“不”。在

Python有三个作用域。它有功能范围、全局(又名模块)范围和内置范围。不能声明其他作用域。在

一个class声明看起来有点像一个作用域,但它不是。它基本上是在一个对象上分配一组字段的简写。该类中的函数在不经过定义它们的对象的情况下无法访问这些字段。在

这听起来有点限制。在Python中,还可以嵌套函数定义。嵌套函数定义获得对外部作用域的只读访问权。这是动态的。在定义函数之前不必提及名称。下面是一个例子:

def joe(x):
    def bar():
        return y
    def baz(z):
        y = x + 20
        return x
    y = x+5
    return bar, baz

>>> a, b = joe(5)
>>> b(20)
5
>>> a()
10

因此,通过定义一个嵌套函数来创建所需的值、使用它们并返回结果,就可以在不牺牲太多局部性的情况下获得这种效果。在

我记得,在学习Python时,习惯于相当奇怪的作用域规则是比较困难的部分之一。在我看来,当嵌套函数被引入时,由于外部作用域的只读语义和闭包的动态作用域,它们使得作用域规则变得更加陌生。在

显然,在Python3中有一种使用nonlocal关键字(类似于global关键字)从封闭范围“导入”一个变量,这样您就可以在读/写上下文中使用它:

^{pr2}$

否则,每当Python在=符号的左侧看到一个变量,它就假定您正在创建一个新的局部变量。globalnonlocal关键字表示您打算修改不在函数范围内的变量。在

Python没有像Lisp或Scheme中的let这样的临时命名空间工具。在

Python中常用的技术是将名称放入当前名称空间,然后在处理完这些名称后将其取出。此技术在标准库中大量使用:

abspath = os.path.abspath
dirname = os.path.dirname
# 15 lines of heavy usage of those functions
a = abspath(somepath)
d = dirname(somepath)
...
del abspath, dirname

减少键入工作量的另一种方法是缩短重复出现的前缀:

^{pr2}$

标准库中常用的另一种技术是不必担心会污染模块名称空间,而只需依赖\uu all_u列出您打算公开的名称。在docs for the import statement中讨论了的作用。在

当然,您也可以通过将名称存储在字典中来创建自己的命名空间(尽管此解决方案并不常见):

d = dict(abspath = os.path.abspath,
         dirname = os.path.dirname)
...
a = d['abspath'](somepath)
d = d['dirname'](somepath)

最后,您可以将所有代码放在一个函数中(它有自己的本地命名空间),但这有许多缺点:

  • 设置很尴尬(函数的非典型和神秘用法)
  • 您需要将要执行的任何非临时任务声明为global。在
  • 除非调用函数,否则代码不会运行
 def temp():                        # disadvantage 1: awkward setup
    global a, d                     # disadvantage 2: global declarations
    abspath = os.path.abspath
    dirname = os.path.dirname
    # 15 lines of heavy usage of those functions
    a = abspath(somepath)
    d = dirname(somepath)
 temp()                             # disadvantage 3: invoking the code

这是你想要的,但是你必须重复名字

try:
    abspath = os.path.abspath
    dirname = os.path.dirname
    # fifteen lines of code
finally:
    del abspath
    del dirname

这避免了在以下情况下出现异常时污染命名空间

^{pr2}$

相关问题 更多 >