[ python-Bugs-1066490 ] special methods become static

SourceForge.net noreply at sourceforge.net
Mon Dec 26 18:21:41 CET 2005


Bugs item #1066490, was opened at 2004-11-15 06:46
Message generated for change (Comment added) made by arigo
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1066490&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Type/class unification
Group: Python 2.3
>Status: Closed
Resolution: Invalid
Priority: 5
Submitted By: Kevin Quick (kquick)
Assigned to: Michael Hudson (mwh)
Summary: special methods become static

Initial Comment:
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.


----------------------------------------------------------------------

>Comment By: Armin Rigo (arigo)
Date: 2005-12-26 17:21

Message:
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.

----------------------------------------------------------------------

Comment By: Reinhold Birkenfeld (birkenfeld)
Date: 2005-06-26 20:55

Message:
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"



----------------------------------------------------------------------

Comment By: Kevin Quick (kquick)
Date: 2004-12-22 19:00

Message:
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'


----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2004-11-16 08:22

Message:
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.

----------------------------------------------------------------------

Comment By: Kevin Quick (kquick)
Date: 2004-11-15 14:29

Message:
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!


----------------------------------------------------------------------

Comment By: Michael Hudson (mwh)
Date: 2004-11-15 07:16

Message:
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.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1066490&group_id=5470


More information about the Python-bugs-list mailing list