#python #overriding #class-method #instance-methods
#python #переопределение #class-method #методы экземпляра
Вопрос:
Смотрите код ниже:
class MyClass:
# instance method.
def printline(self):
print('This is an instance method!')
@classmethod
def printline(cls):
print('This is a class method!')
# class MyClass ends.
obj = MyClass()
obj.printline()
Вывод:
This is a class method!
Итак, почему метод класса переопределяет метод экземпляра? Игнорируя тот факт, что мы можем просто изменить имя одного из методов, как получить доступ к методу экземпляра в приведенном выше коде?
Комментарии:
1. Потому что вы переопределяете его.
2. Как методы класса, так и методы экземпляра являются обычными атрибутами класса. У вас не может быть двух атрибутов с одинаковым именем.
Ответ №1:
Последнее определение функции будет маскировать предыдущее. Если бы метод экземпляра был определен как во 2-м примере ниже, вы бы вызывали его:
In [1]: class MyClass:
...:
...: # instance method.
...: def printline(self):
...: print('This is an instance method!')
...:
...: @classmethod
...: def printline(cls):
...: print('This is a class method!')
...:
In [2]: m = MyClass()
In [3]: m.printline()
This is a class method!
In [4]: class MyClass1:
...:
...: @classmethod
...: def printline(cls):
...: print('This is a class method!')
...:
...: # instance method.
...: def printline(self):
...: print('This is an instance method!')
In [5]: m1 = MyClass1()
In [6]: m1.printline()
This is an instance method!
Ответ №2:
Потому что вы определили printline
дважды, и выигрывает более позднее определение. Методы класса и методы экземпляра — это просто функции в классе, у них нет отдельных пространств имен, поэтому в области видимости может быть только одна функция с заданным именем.
Комментарии:
1. Итак, методы класса и методы экземпляра не имеют отдельных пространств имен, но переменные класса и переменные экземпляра имеют?
2. @ChinmayGhule Да. Все методы являются атрибутами класса; разница между методом экземпляра и методом класса заключается в том, что возвращает
__get__
метод каждого из них. (Все методы реализованы через протокол дескриптора; см. docs.python.org/3/howto/descriptor.html для получения дополнительной информации.)
Ответ №3:
Вы могли бы получить более четкое представление, если бы заглянули в словарь классов MyClass
:
>>> pp(MyClass.__dict__)
mappingproxy({'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'printline': <classmethod object at 0x109d67dd0>})
Здесь вы увидите, что существует только одна ссылка на метод printline
. Это потому, что вы переборщили с ним — как и со словарем, ключи a MappingProxy
уникальны. Обратите внимание на classmethod
значение, придаваемое этому, если бы вы сделали то, что предложили @hobbs и @Arun, вы бы увидели это:
>>> MyClass.__dict__['printline']
<function MyClass.printline at 0x10979a710>
Ответ №4:
Определения функций класса всегда размещаются в самом объекте класса. Декораторы — это на самом деле просто быстрый способ переназначить объект с именованным дескриптором переменной. Более длинный способ написания вашего кода — это
class MyClass:
# instance method.
def printline(self):
print('This is an instance method!')
# make classmethod manually instead of using @classmethod
def printline(cls):
print('This is a class method!')
printline = classmethod(printline)
obj = MyClass()
obj.printline()
Второй printline
перезаписал первый printline
в объекте класса после того, как стал classmethod
дескриптором функции.