Overriding special methods on an instance

后端 未结 5 1773
独厮守ぢ
独厮守ぢ 2020-11-22 03:36

I hope someone can answer this that has a good deep understanding of Python :)

Consider the following code:

>>> class A(object):
...     pas         


        
5条回答
  •  耶瑟儿~
    2020-11-22 04:03

    TLDR: It is impossible to define proper, unbound methods on instances; this applies to special methods as well. Since bound methods are first-class objects, in certain circumstances the difference is not noticeable. However, special methods are always looked up as proper, unbound methods by Python when needed.

    You can always manually fall back to a special method that uses the more generic attribute access. Attribute access covers both bound methods stored as attributes as well as unbound methods that are bound as needed. This is similar to how __repr__ or other methods would use attributes to define their output.

    class A:
        def __init__(self, name):
            self.name = name
    
        def __repr__(self):
            # call attribute to derive __repr__
            return self.__representation__()
    
        def __representation__(self):
            return f'{self.__class__.__name__}({self.name})'
    
        def __str__(self):
            # return attribute to derive __str__
            return self.name
    

    Unbound versus Bound Methods

    There are two meanings to a method in Python: unbound methods of a class and bound methods of an instance of that class.

    An unbound method is a regular function on a class or one of its base classes. It can be defined either during class definition, or added later on.

    >>> class Foo:
    ...     def bar(self): print('bar on', self)
    ...
    >>> Foo.bar
    
    

    An unbound method exists only once on the class - it is the same for all instances.

    A bound method is an unbound method which has been bound to a specific instance. This usually means the method was looked up through the instance, which invokes the function's __get__ method.

    >>> foo = Foo()
    >>> # lookup through instance
    >>> foo.bar
    >
    >>> # explicit descriptor invokation
    >>> type(foo).bar.__get__(foo, type(Foo))
    >
    

    As far as Python is concerned, "a method" generally means an unbound method that is bound to its instance as required. When Python needs a special method, it directly invokes the descriptor protocol for the unbound method. In consequence, the method is looked up on the class; an attribute on the instance is ignored.


    Bound Methods on Objects

    A bound method is created anew every time it is fetched from its instance. The result is a first-class object that has identity, can be stored and passed around, and be called later on.

    >>> foo.bar is foo.bar  # binding happens on every lookup
    False
    >>> foo_bar = foo.bar   # bound methods can be stored
    >>> foo_bar()           # stored bound methods can be called later
    bar on <__main__.Foo object at 0x10c3b6390>
    >>> foo_bar()
    bar on <__main__.Foo object at 0x10c3b6390>
    

    Being able to store bound methods means they can also be stored as attributes. Storing a bound method on its bound instance makes it appear similar to an unbound method. But in fact a stored bound method behaves subtly different and can be stored on any object that allows attributes.

    >>> foo.qux = foo.bar
    >>> foo.qux
    >
    >>> foo.qux is foo.qux  # binding is not repeated on every lookup!
    True
    >>> too = Foo()
    >>> too.qux = foo.qux   # bound methods can be stored on other instances!
    >>> too.qux             # ...but are still bound to the original instance!
    >
    >>> import builtins
    >>> builtins.qux = foo.qux  # bound methods can be stored...
    >>> qux                     # ... *anywhere* that supports attributes
    >
    

    As far as Python is concerned, bound methods are just regular, callable objects. Just as it has no way of knowing whether too.qux is a method of too, it cannot deduce whether too.__repr__ is a method either.

提交回复
热议问题