>>> class S(object):
... def __init__(self):
... self.x = 1
... def x(self):
... return self.x
...
>>> s = S()
>>> s.x
1
>>> s.x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
为什么在这个例子中,s.x
是一个方法,但也是一个整数?在我看来,self.x = 1
应该在实例化期间替换属性def x(self):
的{{1}}声明。为什么我可以得到并调用,导致整数和方法分别具有相同的属性?我的猜测是新式类中的变量查找模式是鸭子类型,以便将最相关的结果返回给调用者。我很想听听整个故事。
答案 0 :(得分:3)
Python不为可调用和不可调用的对象使用单独的空格:名称是名称。 s.x
,根据Python规则,必须引用完全相同的对象,无论您是否打算调用它。另一种方式:假设_aux
是一个未使用的名称,
_aux = self.x
_aux()
和
self.x()
必须在Python中具有绝对相同的语义,事实上,在前者中,中间值self.x
被绑定到名称并尽管稍后调用。
为callables和non-callables提供单一的“统一”命名空间有很多优点 - 它使名称查找规则(对于每个裸名称和限定名称)非常简单,例如,通过将它们从完全解耦将要查找正在查找的名称的目的(无论是在查找结果之后,还是稍后),以及类型(可调用或不可调用的任何对象根据查找规则首先被引用。
特别是考虑到Python有多少不同的可调用类型(函数,类,定义__call__
的类的实例),特殊类型,如staticmethod
和classmethod
,......! - ) ,任何其他规则只会导致完全混乱。 (另请注意,例如,即使是C ++,这种语言肯定不会受到复杂性的影响,但也允许类实例可以调用[[如果类重载operator()
]],使用类似的统一命名空间规则 - 再次,区分callables和non-callables将是一个完全没有根据的噩梦,这方面的规则是不同的! - 。)。
答案 1 :(得分:2)
看起来你对你所看到的错误有误解。当您的s
对象被实例化时,其构造函数将方法x
替换为整数,因此在s
对象中,x
是整数,而不是函数。尝试将其作为方法调用会导致抛出异常。
Python是鸭子类型,因为方法调用在运行时被解析 - 编译器对s.x()
没有问题,因为x
可能是动态创建的方法。但是,当解释器实际调用x
作为方法时,它通知x
是一个整数且无法调用,因此TypeError
。
答案 2 :(得分:1)
我不确定你的想法是什么,但没有任何棘手的事情发生。分配self.x = 1
时,无法再访问方法x
。从那时起,s.x
只是一个整数 - 尝试将其称为方法导致异常,如您所见。
答案 3 :(得分:0)
似乎x属性被定义为类定义中的方法。但是,实际实例化一个对象会用整数覆盖该名称 - 因此,观察到的行为。它实际上从来不是两个。所以,这基本上是一些错误的代码。
答案 4 :(得分:0)
这是您的代码正在做的事情:
S
的类__init__
和x
S
的实例并将其命名为s
S.__init__
为参数调用s
s.x
1
s.x
s.x
现在,如果你查看2.1.1,你会发现你已经用一个整数覆盖了方法x
,这意味着你不能再用s
来调用它(但它仍然在{ {1}}类)
如果您已经这样做了,但需要调用S
函数,请尝试:
x
我刚刚这样做,所以你理解为什么你丢失x作为方法,以正确的方式做,并避免让实例变量与类方法同名