Issue1066490
Created on 2004-11-15 06:46 by kquick, last changed 2005-12-26 17:21 by arigo.
| File name |
Uploaded |
Description |
Edit |
Remove |
|
newclass.py
|
kquick,
2004-11-15 06:46
|
newclassprob.py |
|
|
|
msg23127 - (view) |
Author: Kevin Quick (kquick) |
Date: 2004-11-15 06:46 |
|
This *may* be a duplicate of 729913, but there's either additional
info here, or this is actually different.
The issue is that any special method (e.g. __call__, __str__, etc.)
defined for a new-style (i.e. object-based) class seems to be static
(i.e. unchangeable) with some special lookup applied for that method,
but this doesn't seem to be the case for regular methods.
class A:
def foo(self): return 1
def __call__(self): return 2
def bar(self): return 3
def adjust(self):
self.foo = self.bar
self.__call__ = self.bar
a = A()
print a.foo(), a()
a.adjust()
print a.foo(), a()
Will print:
1 2
3 3
But if the A is turned into a new-style class by changing the
first line:
class A(object):
then the printed results are:
1 2
3 2
To the best of my understanding of the migration from classic classes
to new-style classes (and metaclassing), this shouldn't occur. I have
also tried various name munging for the special method (e.g. setting
_B__call__, using setattr, etc.), but I haven't found the special trick
yet.
The attached script shows the example in more detail.
|
|
msg23128 - (view) |
Author: Michael Hudson (mwh) |
Date: 2004-11-15 07:16 |
|
Logged In: YES
user_id=6656
The change you are observing is that special methods are now
only looked up on the *class* of the object concerned. This, or
something like this is actually unavoidable -- in
>>> repr(o)
what do you do if both o and the type of o define a __repr__
method?
There are articles on new-style classes out there that should
explain this in more depth. It probably could/should be
documented better in the core -- there are bugs open to that
effect already.
Closing.
|
|
msg23129 - (view) |
Author: Kevin Quick (kquick) |
Date: 2004-11-15 14:29 |
|
Logged In: YES
user_id=6133
OK, I didn't find anything documenting this change anywhere (obviously).
I read Guido's description of new-classes (www.python.org/2.2/descrintro.py)
and the various documentation, but either I overlooked it therein or it's talked
about somewhere else.
I'm curious as to why special methods are treated specially in regards to this
lookup. Specifically for your example, why wouldn't you just use the
__repr__ attribute of o if it exists, instead of o's class, just like it does for
non-special methods? Can you briefly explain this or provide me with a
reference?
Leaving this closed is OK with me since it's apparently known and expected...
I'd just like to understand it a bit better. Sorry for the bandwidth, and Thanks!
|
|
msg23130 - (view) |
Author: Michael Hudson (mwh) |
Date: 2004-11-16 08:22 |
|
Logged In: YES
user_id=6656
Oh, sorry, I think I got that a bit wrong. The issue is more with
bound/unbound methods -- given
class O(object):
def __repr__(self):
...
should O.__repr__ be a bound method (O is an instance of type)
or an unbound method so O.__repr__(O()) does what you expect?
Python chooses the latter, but this means that you can't implement
the builtin function repr as
def repr(o):
return o.__repr__()
Hope this helps, a little at least.
|
|
msg23131 - (view) |
Author: Kevin Quick (kquick) |
Date: 2004-12-22 19:00 |
|
Logged In: YES
user_id=6133
Thanks for the clarifcation. However IMHO it is wrong to have different
behavior for different methods.
To wit, if I defined a method, it is a bound method, and ergo a "self" initial
argument is automatically supplied. However, a __repr__, even though I
define it, acts as an unbound method, with the self argument having a default
of the current instance but overrideable if an argument is supplied on the call.
This means that the argument evaluation/passing is different for these types
of builtins as opposed to other methods, both of which I have defined myself.
This just doesn't seem right to me, which is why I'm re-opening this bug
report... sorry to be annoying, but this definitely seems inconsistent and a
better explanation.
My current workaround is to do the following:
class foo:
def __str__(self):
return my_str()
def my_str(self):
return 'something'
So that I can do "foo.my_str = lambda self: return 'something else'".
When what I should be able to do is:
class foo:
def __str__(self):
return 'something'
...
foo.__str__ = lambda self: return 'something else'
|
|
msg23132 - (view) |
Author: Georg Brandl (georg.brandl) |
Date: 2005-06-26 20:55 |
|
Logged In: YES
user_id=1188172
It is not the case that the methods are unchangeable. See
this example:
class A(object):
def __repr__(self): return 'repr'
def new_repr(self): return 'new_repr'
a = A()
a.__repr__ = a.new_repr
print a.__repr__()
=> prints "new_repr"
print repr(a)
=> prints "repr"
|
|
msg23133 - (view) |
Author: Armin Rigo (arigo) |
Date: 2005-12-26 17:21 |
|
Logged In: YES
user_id=4771
Re-closing. This is a known documentation bug: all this is
expected, but just under-documented. 'str(x)' issues a
special method call to '__str__' on 'x', but the real
definition of "calling a special method" on an object 'x' is
as follows: look up the name "__str__" in the dict of
type(x), then in the dict of the parent types in MRO order.
It's really not the same thing as an attribute lookup.
The reason for this, to put Michael's argument differently,
is that if 'str(x)' would really work like 'x.__str__()',
then this is what would occur:
>>> class X(object):
... def __repr__(self):
... return "hello"
...
>>> X()
hello
>>> X
TypeError: __repr__() takes exactly 1 argument (0 given)
because X.__repr__() is just an unbound method call with a
missing argument. There is no such thing as "default values
for self" in Python.
|
|
| Date |
User |
Action |
Args |
| 2004-11-15 06:46:24 | kquick | create | |
|