python - 奇怪的行为问题

时间:2010-09-06 03:44:51

标签: python scope instantiation

>>> 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}}声明。为什么我可以得到并调用,导致整数和方法分别具有相同的属性?我的猜测是新式类中的变量查找模式是鸭子类型,以便将最相关的结果返回给调用者。我很想听听整个故事。

5 个答案:

答案 0 :(得分:3)

Python不为可调用和不可调用的对象使用单独的空格:名称是名称。 s.x,根据Python规则,必须引用完全相同的对象,无论您是否打算调用它。另一种方式:假设_aux是一个未使用的名称,

_aux = self.x
_aux()

self.x()

必须在Python中具有绝对相同的语义,事实上,在前者中,中间值self.x被绑定到名称并尽管稍后调用。

为callables和non-callables提供单一的“统一”命名空间有很多优点 - 它使名称查找规则(对于每个裸名称和限定名称)非常简单,例如,通过将它们从完全解耦将要查找正在查找的名称的目的(无论是在查找结果之后,还是稍后),以及类型(可调用或不可调用的任何对象根据查找规则首先被引用。

特别是考虑到Python有多少不同的可调用类型(函数,类,定义__call__的类的实例),特殊类型,如staticmethodclassmethod,......! - ) ,任何其他规则只会导致完全混乱。 (另请注意,例如,即使是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)

这是您的代码正在做的事情:

  1. 使用2种方法创建名为S的类__init__x
  2. 创建S的实例并将其命名为s
    1. S.__init__为参数调用s
      1. 使用值s.x
      2. 设置1
  3. 打印s.x
  4. 打印调用s.x
  5. 的结果

    现在,如果你查看2.1.1,你会发现你已经用一个整数覆盖了方法x,这意味着你不能再用s来调用它(但它仍然在{ {1}}类)

    如果您已经这样做了,但需要调用S函数,请尝试:

    x

    我刚刚这样做,所以你理解为什么你丢失x作为方法,以正确的方式做,并避免让实例变量与类方法同名

相关问题