Python: Re-bind function as int



我有一个测试类:

class TestClass:
    def someFunction(self, someInt):
        self.i = someInt
        return self.i

并正在使用:

进行测试
x = MyClass()
x.someFunction = 3
print(x.someFunction)
x.someFunction(4)

但是,这导致TypeError: 'int' object is not callable。我了解为什么我会遇到这个错误 - 功反弹到整数(在这种情况下为3),而且,整数不是一个函数,因此某些功能不再可调用。但是我想知道允许成员函数的背后原因是什么,就像是数据成员一样?似乎很容易出现意外错误。我刚开始学习Python,觉得我缺少Python的基本方面,这种行为适合。

这是允许的,因为属性查找在Python中的工作方式,这是设计。在Python中,允许在其他语言中灰心,禁止或不可能的许多事情来利用您的用例(如果明智地使用)。当然,更多的权力意味着更多的责任。

毕竟,我们都在这里同意成年人。

属性分辨率的一些背景信息

类实例从存储所有对象属性的空 __dict__属性开始。通过访问x.someFunction,您正在隐式尝试x.__dict__['someFunction']。如果x.__dict__中不存在'someFunction',则对x的类,即type(x).someFunction或更好的type(x).__dict__['someFunction']

当您通过x.someFunction = 3编写CC_11时,实际上发生的是x.__dict__['someFunction'] = 3,无论阅读属性访问可能返回什么。

在方法调用期间,唯一的真实(?)魔术发生在自动提供self的情况下,即x.someFunction(4)解决至type(x).__dict__['someFunction'](x, 4)而不是type(x).__dict__['someFunction'](4)x.__dict__['someFunction'](4)。这与属性访问有关,并可能引起混乱。

因此,您实际上不是"重新启用"该功能,而是用x的实例属性someFunction隐藏类属性someFunction。如果您这样做

print(MyClass.someFunction)
print(MyClass().someFunction)

您会看到该方法仍然存在。您甚至可以使用

恢复初始状态
del x.__dict__['someFunction']

注意:我描述的分辨率说明了概念。实际上,Python的内部运作可能更加微妙或更复杂,但是它们会产生相同的效果。例如,在Python 2中,在存储在类词典中之前,方法已被称为 Unbound方法。这已在Python 3中删除,其中类词典包含普通函数。

请在python shell中执行您的演示代码:

>>> class TestClass:
...     def someFunction(self, someInt):
...         self.i = someInt
...         return self.i
...
>>> x = TestClass()
>>> x.someFunction = 3
>>> print(x.someFunction)
3
>>> x.someFunction(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable

请参阅以下内容:

>>> type(x.someFunction)
<type 'instancemethod'>
>>> x.someFunction = 3
>>> type(x.someFunction)
<type 'int'>

如果尝试x.someFunction = 3,则 instancemethod 平静x.someFunction将转换为 int

in python

  • 函数被威胁为一流对象
  • 和变量未键入。

或只是python中的"一切都是对象"。因此,包含整数与包含函数的变量的变量没有基本差异。一流的功能和未型变量都具有自己的优点和缺点,但允许您进行例如只需制作包含整数,字符串,其他对象以及功能的列表。

您可以将任何内容分配给函数变量的原因是因为它们是作为对象实现的。这使您能够返回函数并将函数作为参数,与C中不同。

此功能的有用性远远超过了"意外错误"。

例如,您可以做这样的事情:

# some code
def sum(a, b):
    return a+b
def product(a, b):
    return a*b
def ret_func(str):
    if str=='add':
        func = sum
    elif str=='multiply':
        func = product
    return func
addition_result = ret_func('add')(x, y)
multiplication_result = ret_func('multiply')(x, y)
# some more code

最新更新