简体   繁体   English

奇怪的行为问题

[英]python - strange behavior question

>>> 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

Why, in this example, is sx a method, but also an integer? 在此示例中,为什么sx是方法,但又是整数? It seems to me that self.x = 1 should replace the def x(self): declaration of the attribute x during instantiation. 在我看来, self.x = 1应该在实例化期间替换属性xdef x(self):声明。 Why is it that I can get and call, resulting in an integer and a method, respectively, the same attribute? 为什么我可以获取和调用,分别导致整数和方法具有相同的属性? My guess is that the variable look-up pattern in new-style classes is duck typed, so as to return the most relevant result to the caller. 我的猜测是,新样式类中的变量查找模式是鸭子类型的,以便将最相关的结果返回给调用者。 I would love to hear the whole story. 我很想听听整个故事。

Python doesn't use separate spaces for callable and non-callable objects: a name is a name is a name. Python不会为可调用和不可调用对象使用单独的空格:名称是名称就是名称。 sx , by Python rules, must refer to exactly the same object, whether you're going to call it or not. 根据Python规则, sx 必须引用完全相同的对象,无论您是否要调用它。 Another way of putting it: assuming that _aux is a name not otherwise used, 另一种表达方式:假设_aux是未使用的名称,

_aux = self.x
_aux()

and

self.x()

must have absolutely identical semantics in Python, the fact that in the former the intermediate value self.x is being bound to a name and called later notwithstanding. 必须在Python中具有绝对相同的语义,尽管前一个中间值self.x已绑定到名称并随后被调用,这一事实。

Having single, "unified" namespaces for callables and non-callables has a huge number of advantages -- it makes name-lookup rules (for each of bare and qualified names) enormously simpler, for example, by decoupling them totally from the purpose to which the name being looked up is going to be put (be it immediately after the lookup's result, or later still), and also from the type (callable or non-callable) of whatever object turns up to be first referenced according to the lookup rules. 具有可调用和不可调用的单个“统一”名称空间具有许多优点-例如,通过将名称与目标完全脱钩,从而使名称查找规则(对于裸名和合格名中的每一个)变得非常简单。所要查找的名称将被放置(无论是在查找结果之后还是稍后),以及根据查找首先被引用的对象的类型 (可调用或不可调用)规则。

Especially considering how many different callable types Python has (functions, classes, instances of classes which define __call__ , special types such as staticmethod and classmethod , ...!-), any other rule could only lead to total chaos. 特别是考虑到Python有多少种不同的可调用类型(函数,类,定义__call__的类实例,特殊类型(例如staticmethodclassmethod ,...!-)),任何其他规则都只会导致整个混乱。 (Note also, for example, that even C++, a language which definitely is not afraid by complexity but which also lets class-instances be callable [[if the class overloads operator() ]], uses a similar unified-namespace rule -- again, discriminating between callables and non-callables would be a totally unwarranted nightmare, were the rules any different in this regard!-). (例如,还要注意,即使C ++,一种绝对不怕复杂性但允许类实例可调用的语言[[如果类重载operator() ]],也使用类似的统一命名空间规则-同样,如果规则在这方面有任何不同,则区分可调用对象和不可调用对象将是完全没有根据的噩梦!

It looks like you're having a misunderstanding of the error you're seeing. 您似乎对所看到的错误有误解。 When your s object is instantiated, its constructor replaces the method x by an integer, so in the s object, x is an integer, not a function. 实例化s对象时,其构造函数将方法x替换为整数,因此在s对象中, x是整数,而不是函数。 Trying to call it as a method results in an exception being thrown. 尝试将其作为方法调用会导致引发异常。

Python is duck-typed in the sense that method calls are resolved at runtime - the compiler has no problem with sx() because x might have been created as a method dynamically. 从方法调用在运行时解决的意义上说,Python是鸭子类型的-编译器对sx()没问题,因为x可能是作为方法动态创建的。 However, when the interpreter actually calls x as a method, it notices x is an integer and can't be called, hence the TypeError . 但是,当解释器实际将x作为方法调用时,它会注意到x是一个整数并且无法调用,因此TypeError

I'm not sure what you think is going on, but there's nothing that tricky happening. 我不确定您的想法,但没有任何棘手的事情发生。 When you assign self.x = 1 , the method x is no longer accessible. 当您分配self.x = 1 ,方法x将不再可用。 From that point forward, sx is only an integer -- attempts to call it as a method result in an exception, as you saw. 从那时起, sx只是一个整数-如您所见,尝试将其作为方法调用会导致异常。

It seems that the x property is defined as a method in the class definition. 似乎x属性在类定义中定义为方法。 However, actually instantiating an object overwrites that name with an integer - hence, the behavior observed. 但是,实际上实例化一个对象会使用整数覆盖该名称-因此,会观察到行为。 It's never actually two at once. 实际上从来没有一次两个。 So, this is basically some faulty code. 因此,这基本上是一些错误的代码。

This is what your code is doing: 这是您的代码正在执行的操作:

  1. Create a class named S with 2 methods, __init__ and x 使用__init__x 2种方法创建名为S的类
  2. Create an instance of S and name it s 创建S的实例并将其命名为s
    1. Call S.__init__ with s as parameter s为参数调用S.__init__
      1. Set sx with the value 1 sx设置为值1
  3. Print sx 打印sx
  4. Print the result of calling sx 打印调用sx的结果

Now, if you look in 2.1.1 you will see that you have overrided the method x with an integer, which means that you cannot call that again withing s (but it stills in S class) 现在,如果您在2.1.1中查看,您将看到您已经用整数覆盖了方法x ,这意味着您无法使用s再次调用它(但它仍然在S类中)

If you have done that, and yet, need call x function, try it: 如果您已经做到了,但是仍然需要调用x函数,请尝试:

>>> class S(object):
...     def __init__(self):
...         self.x = 1
...     def x(self):
...         return self.x
... 
>>> s = S()
>>> s.x
1
>>> S.x(s)
1
>>> 

I just did it so you understand why you are losing the x as method, do it in the right way and avoid to have instances variables with the same name as class methods 我只是这样做了,所以您了解了为什么会丢失x as方法,以正确的方式进行操作并避免实例变量与类方法具有相同的名称

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM