简体   繁体   中英

Lookup of magic methods on old-style Python classes

I know old-style Python classes aren't recommended anymore, especially since Python 3 removes them. However, I'd still like to understand what is happening here:

class MyClass:
  pass

my_instance = MyClass()
str(my_instance)

This snippet prints the following:

'< main .MyClass instance at 0x108ec4290>'

So, I don't have any explicit inheritance and I didn't overload the str method. However, this doesn't raise an exception for the supposedly missing method. Why?

I know that old-style classes have the concept of an 'instance' and a 'type' and that new-style classes aim to unify these concepts. So is Python finding and calling the str method on the 'instance' type that my instance is implicitly connected to?

Here are some clues:

dir(my_instance) - Returns:

['__doc__', '__module__']

type(my_instance) - Returns:

<type 'instance'>

dir(type(my_instance)) - Returns:

['__abs__', '__add__', '__and__', '__call__', '__class__', '__cmp__', '__coerce__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__div__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', '__index__', '__init__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', 'next']

Can anyone explain exactly the relationship between classes and types in old-style classes and what is happening here?

I am sure other people can give you more concrete reasons that this, but there is a quote from a similar discussion located here: old-style class

object is the base class that is at the top of any inheritance tree. The purpose of insisting on the base class, I believe, is to unify object behavior without requiring too much 'magic.' That is, prior to new-style classes, objects just magically had properties like __doc__ and __str__ ; now, they have them for a reason: because they inherited them from the base class.

That part about the "magic" I believe is just that... black-box magic. Obviously the MRO (method resolution order) of old style classes was much more magical, in that it probably had to check both explicit definitions on the instance object, as well as on the type . Either that, or part of the mechanics of an old style class is to always provide a default __str__ method when one cannot be located.

It would be less magical now with new-style classes, because due to the inheritance, the methods are really right there on the instance.

Here is another site with some good quotes and examples: Principle of Biggest Surprise

For old-style classes all lookup is done in the instance.

For instances of new-style classes, all special method lookup that is done implicitely is done in the class struct

New-style:

class Foo(object):
    def __str__(self):
        return "old str"

foo = Foo()
foo.__str__ = lambda: "new str"

print str(foo)
print foo.__str__()

# old str
# new str

Old-Style:

class Foo:
    def __str__(self):
        return "old str"

foo = Foo()
foo.__str__ = lambda: "new str"

print str(foo)
print foo.__str__()

# new str
# new str

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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