>>> 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: 'in开发者_开发问答t' object is not callable
Why, in this example, is s.x
a method, but also an integer? It seems to me that self.x = 1
should replace the def x(self):
declaration of the attribute x
during instantiation. 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. s.x
, by Python rules, must refer to exactly the same object, whether you're going to call it or not. Another way of putting it: assuming that _aux
is a name not otherwise used,
_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.
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. (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!-).
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. 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 s.x()
because x
might have been created as a method dynamically. However, when the interpreter actually calls x
as a method, it notices x
is an integer and can't be called, hence the 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. From that point forward, s.x
is only an integer -- attempts to call it as a method result in an exception, as you saw.
It seems that the x property is defined as a method in the class definition. 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:
- Create a class named
S
with 2 methods,__init__
andx
- Create an instance of
S
and name its
- Call
S.__init__
withs
as parameter- Set
s.x
with the value1
- Set
- Call
- Print
s.x
- Print the result of calling
s.x
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)
If you have done that, and yet, need call x
function, try it:
>>> 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
精彩评论