【问题标题】:Why is the __dict__ attribute of this function an empty dictionary?为什么这个函数的 __dict__ 属性是一个空字典?
【发布时间】:2020-12-09 13:17:45
【问题描述】:

我在一个函数上测试预定义的 dict 属性,我得到了一个我没想到的结果。考虑以下代码:

>>> def func():
       x = 7
       a = 0
       print(func.__dict__)

    
>>> func()
{}

毕竟,我确实在函数的命名空间中定义了两个变量。那么为什么这些名字没有出现在函数的 dict 属性中呢?

【问题讨论】:

  • 为什么应该 每个函数调用的局部变量在single函数对象的字典中?如果函数被调用两次,您希望 func.__dict__ 包含什么,例如通过嵌套还是并发?
  • 因为func 是一个带有__call__ 方法的对象。您可以致电dir(func) 进行检查。在被调用之前,它对自己的身体一无所知。
  • 函数执行过程中的本地命名空间不是函数实例命名空间。否则,你可以做func.a,但你不能。无论如何,这是没有意义的,因为a 在函数未执行时不存在

标签: python function dictionary scope namespaces


【解决方案1】:

函数的__dict__ 包含属性,而不是局部变量。局部变量特定于函数的每次执行,而不是函数本身,因此您无法通过检查函数来获取局部变量值。

如果你分配了一个属性:

func.blah = 3

这将显示在__dict__

__dict__ 不包含所有属性 - 还有其他方法可以创建属性,这就是为什么 __dict__ 本身不会出现在 __dict__ 中的原因。)

【讨论】:

  • 但是如果我在一个类中定义一个类变量,那么该变量将出现在该类的 dict 属性中。这与在函数中声明 x=7 之类的变量有什么不同?
  • @spiritedExit0:正如 MisterMiyagi 所说,函数和类是具有不同行为的不同事物。
【解决方案2】:

函数对象的__dict__ 属性存储分配给函数对象的属性

>>> def foo():
...     a = 2
...     return a
...
>>> foo.bar = 12
>>> foo.__dict__
{'bar': 12}

函数object的属性与函数调用过程中存在的局部变量无关。前者是唯一的(每个函数对象有一个__dict__),而后者不是(一个函数可以使用单独的局部变量多次调用)。

>>> def nfoo(n: int):
...     print(f'level {n} before:', locals())
...     if n > 0:
...        nfoo(n - 1)
...     print(f'level {n} after: ', locals())
...
>>> nfoo(2)
level 2 before: {'n': 2}
level 1 before: {'n': 1}
level 0 before: {'n': 0}
level 0 after:  {'n': 0}
level 1 after:  {'n': 1}
level 2 after:  {'n': 2}

注意每个级别的locals 如何同时存在,但对于同一个名称保存不同的值。

【讨论】:

  • 但是如果我在一个类中定义一个类变量,那么该变量将出现在该类的 dict 属性中。这与在函数中声明像 x=7 这样的变量有什么不同?
  • 函数不是类。两者兼备的全部意义在于这些不同的。尽管考虑到可以看到函数调用类似于(不等同于!)类实例化。函数调用的变量(局部变量)与函数对象是分开的,就像类实例化的变量(属性)与类对象是分开的一样。
【解决方案3】:

__dict__ 用于支持函数属性,它不是名称空间,也不是函数体范围的符号表。您可以阅读PEP-232 了解有关函数属性的更多信息。

【讨论】:

    猜你喜欢
    • 2011-06-20
    • 2017-12-31
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多