python - Python 实例方法目录中的 __func__ 属性的用途是什么?
问题描述
当创建一个类的实例时,对于类定义中的每个函数,该实例的目录中都会有一个与函数同名的属性。这个“函数属性”,假设函数是类方法或实例/绑定方法,将有另一个目录作为其值,其中包括除__func__
和之外的函数对象中的所有属性__self__
。__func__
包含另一个目录——在类本身中找到的函数的目录——它当然包含在函数对象中找到的所有属性(例如,在__func__
指向与类函数目录中同名属性相同的对象)。据推测,当从实例调用函数时,实例的函数目录中的属性会遵循在目录中找到的相同属性__func__
(并且当从实例调用函数时,实例的方法的__call__
属性会遵循__func__.__call__
)。那么为什么实例仍然创建这个__func__
属性呢?为什么不让直接实例函数目录属性直接指向类函数目录属性,就像静态方法操作一样?似乎实例使用的内存超出了它们的需要。
为了使这种差异更加清楚:
class Solution:
def maxArea(self, height):
pass
@staticmethod
def i_am_static():
pass
@classmethod
def i_am_a_class_method():
pass
s = Solution()
print("\n\nDirectory of Instance Method:")
print(dir(s.maxArea))
print("\n\nDirectory of Instance Method __func__ attribute:")
print(dir(s.maxArea.__func__))
print("\n\nEqualities:")
print("s.maxArea.__func__.__call__== Solution.maxArea.__call__? ",
s.maxArea.__func__.__call__ == Solution.maxArea.__call__)
print("s.maxArea.__call__ == Solution.maxArea.__call__? ",
s.maxArea.__call__ == Solution.maxArea.__call__)
print("\n\nDirectory of Static Method:")
print(dir(s.i_am_static))
print("\nInstance Method has these other methods:")
for i in dir(s.maxArea):
if i not in dir(s.i_am_static):
print(i)
print("\nStatic Method has these other methods:")
for i in dir(s.i_am_static):
if i not in dir(s.maxArea):
print(i)
印刷:
Directory of Instance Method:
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Directory of Instance Method __func__ attribute:
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Equalities:
s.maxArea.__func__.__call__ == Solution.maxArea.__call__? True
s.maxArea.__call__ == Solution.maxArea.__call__? False
Directory of Static Method:
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Instance Method has these other methods:
__func__
__self__
Static Method has these other methods:
__annotations__
__closure__
__code__
__defaults__
__dict__
__globals__
__kwdefaults__
__module__
__name__
__qualname__
查看等式,我们可以看到属性__func__
引用了类本身创建的同一个对象。但是,不在__func__
(例如__call__
)中的属性不引用同一个对象,但它们可能会调用该对象。__func__
为什么要费心在简单地调用这些属性之外重新创建这些属性__func__
?为什么不将属性转储到__func__
dir(s.maxArea) 中,该__self__
属性将表示该方法应作为实例方法调用?
解决方案
它用于保存函数在内存中的位置。
一个示例类:
>>> class Test(object):
... a = 'world'
... def test_method(self, b='hello'):
... print(b, self.a)
...
工作示例:
>>> c = Test()
>>> c.test_method()
hello world
有与设置、各种内部变量、参数、关键字参数( 、 等)相关的代码,__defaults__
因此__kwdefaults__
当调用该方法时,它具有有关如何调用它的信息。(参见bound
方法示例,还请注意这里有 python2/3 的警告,请参见method-wrapper
下面的链接说明)
默认 kwarg 示例b
:
>>> print(c.test_method.__defaults__)
('hello',)
地点Test
和地点Test.test_method
:
>>> print(c)
<__main__.Test object at 0x7fd274115550>
>>> print(c.test_method)
<bound method Test.test_method of <__main__.Test object at 0x7fd274115550>>
位于何处__func__
:
>>> print(c.test_method.__func__)
<function Test.test_method at 0x7fd274113598>
>>> c.test_method.__func__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test_method() missing 1 required positional argument: 'self'
它被调用时的外观如何Test.test_method
,或多或少看起来像:
>>> c.test_method.__func__(c)
hello world
怎么样__call__
?这是method-wrapper
一个__func__
:
- 方法包装器解释这里是绑定/未绑定和之间的解释
method-wrapper
>>> print(c.test_method.__func__.__call__)
<method-wrapper '__call__' of function object at 0x7fd274113598>
>>> c.test_method.__func__.__call__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test_method() missing 1 required positional argument: 'self'
>>> c.test_method.__func__.__call__(c)
hello world
所以目的__func__
是设置模块和类如何查找函数,如果它是类内部的方法,它有一些额外的东西在幕后工作来设置上下文,所以它可以访问self.a
,或其他类类中的方法。
函数在类之外的示例:
>>> def test_method(cls, b='hello'):
... print(b, cls.a)
...
>>> class Test(object):
... a = 'world'
...
>>> c = Test()
>>> test_method(c)
hello world
>>> print(test_method)
<function test_method at 0x7fd274113400>
>>> print(test_method.__func__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '__func__'
>>> print(test_method.__defaults__)
('hello',)
>>> test_method.__call__(c)
hello world
另见:
推荐阅读
- c - 验证 c 中数字的输入
- c# - 在 DevExpress LookupEdit 上配置或禁用验证?
- node.js - 如何修复 npm ERR!每次我在命令行中输入 npm start 时得到的代码
- python - 从 .msg 文件中提取 .xlsx 附件
- pandas - 根据数据框的大小动态选择行
- python - Pandas DataFrame:按列分组、按日期时间排序和按条件截断分组
- pandas - 一个函数,它将返回数据框中每列中 3 个最高条目的索引
- ios - 与桌面应用程序一样在登录时获取用户 ID 选择屏幕,而不是每次都输入用户 ID
- javascript - 仅在选中单选按钮时运行 javascript
- javascript - 如何在 Web 上保存 Firestore 数据库请求以减少调用次数