Що таке "класичні методи" та "методи екземпляра" в Python?


37

У чаті було обговорено питання, яке стосується питання (саме питання до цього не має значення), що виявило, що я, можливо, не знаю Python.

На мій погляд, хоча термінологія відрізняється між мовами, ми можемо загалом класифікувати функції як:

  • [вільні] функції
  • статичні методи / функції статичних членів
  • нестатичні методи / нестатичні функції членів

Мабуть, у Python є ще один вид функції, яка не вписується у вищевказані категорії, та це метод, але "не знає свого класу".

Що таке "класичні методи" та "методи екземпляра" в Python?


1
Якщо когось цікавить дискусія в чаті, починайте тут: chat.stackexchange.com/transcript/message/26479002#26479002
yannis

1
ІМ краща відповідь надаються іншим веб - сайт stackexchange: stackoverflow.com/questions/136097 / ...
Trevor Boyd Smith

FYI посилання надається внизу прийнятого ... але я думаю, що багато людей пропустять посилання або ніколи не потраплять на нього, тому я скопіював його сюди.
Тревор Бойд Сміт

Відповіді:


49

Коротка відповідь

  • метод екземпляра знає його примірник (і з цього його клас)
  • метод класу знає свій клас
  • статичний метод не знає свого класу чи екземпляра

Довга відповідь

Методи класу

А класу - це той, який належить класу в цілому. Для цього не потрібен примірник. Натомість клас автоматично буде надісланий як перший аргумент. Метод класу оголошено @classmethodдекоратором.

Наприклад:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Методи екземплярів

З іншого боку, метод екземпляра вимагає екземпляра, щоб викликати його, і не вимагає декоратора. Це, безумовно, найпоширеніший тип методу.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(зверніть увагу: вищезазначено з python3; з python2 ви отримаєте дещо іншу помилку)

Статичні методи

Статичний метод схожий на метод класу, але не отримаєте об'єкт класу в якості автоматичного параметра. Він створюється за допомогою @staticmethodдекоратора.

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Посилання на документацію

Ось посилання на відповідний документальний фільм python3:

Документація щодо моделі даних говорить про різницю між методами класу та статичними методами:

Об'єкти статичного методу Об'єкти статичного методу забезпечують перемогу перетворення об'єктів функції на об'єкти методу, описані вище. Об'єкт статичного методу - обгортка навколо будь-якого іншого об'єкта, як правило, визначеного користувачем методу. Коли об'єкт статичного методу витягується з класу або екземпляра класу, фактично повернутий об'єкт є обгорнутим об'єктом, який не підлягає подальшому перетворенню. Об'єкти статичного методу самі по собі не можна називати, хоча об'єкти, якими вони обертаються, зазвичай є. Об'єкти статичного методу створюються вбудованим конструктором staticmethod ().

Об'єкти методу класу Об'єкт методу класу, як і об'єкт статичного методу, - це обгортка навколо іншого об'єкта, який змінює спосіб отримання цього об'єкта з класів та екземплярів класу. Поведінка об'єктів методів класу при такому пошуку описано вище, у розділі "Методи, визначені користувачем". Об'єкти методу класу створюються вбудованим конструктором classmethod ().

Пов'язані питання


4
@LightnessRacesinOrbit: Я не думаю, що статичні методи особливо часто використовуються в python. Використовуючи мою систему як випадкову вибірку, коли я шукаю всі встановлені нами пакети, лише близько 1% всіх методів є статичними методами (що, чесно кажучи, було більше, ніж я очікував).
Брайан Оуклі

1
"Статичні методи" зазвичай мають кодовий запах і відлякують їх, наприклад, посібник зі стилю Gogole Python.
9000

3
Я думаю, що відповідь буде кращим, якби вона звернула увагу на підкласи, саме там класові методи отримують певну корисність.
Вінстон Еверт

1
@ user2357112: Я просто порахував усі екземпляри "^ def(", а потім порахував усі екземпляри @staticmethod. Дуже ненаукове, але, ймовірно, було в межах бального парку.
Брайан Оуклі

2
@Kashyap: TL; DR застосовується до першого пункту. Я думаю, що це працює краще вгорі, ніж внизу.
Брайан Оуклі

8

Що таке "класичні методи" та "методи екземпляра" в Python?

  • "Метод екземпляра" використовує інформацію, що міститься в екземплярі, щоб визначити, яке значення повернути (або який побічний ефект зробити). Вони дуже поширені.

  • "Метод класу" використовує інформацію про клас (а не екземпляр цього класу) для впливу на те, що він робить (вони зазвичай використовуються для створення нових екземплярів як альтернативних конструкторів, і тому не є надзвичайно поширеними).

  • "Статичний метод" не використовує жодної інформації про клас чи екземпляр для обчислення того, що він робить. Зазвичай це просто в класі для зручності. (Як такі, вони теж не дуже поширені.)

Функція X

Запам'ятайте математичний клас, "у - це функція х f(x),?" Застосуємо це у коді:

y = function(x)

Наголошене на тому, що оскільки xможе змінюватися, yможе змінюватися і при xзміні. Це мається на увазі, коли ми говоримо, що " yє функцією x"

Що буде, yколи zє 1? 2? 'FooBarBaz'?

yне є функцією z, тому zможе бути що завгодно і не впливати на результат функції, припускаючи, що наша functionє чистою функцією. (Якщо вона має доступ zдо глобальної змінної, то це не є чистою функцією - саме це розуміється під функціональною чистотою.)

Пам’ятайте про вищезазначене, читаючи такі описи:

Методи екземплярів

Метод примірника є функцією , яка є функцією від примірника . Функція приймає екземпляр неявно як аргумент йому, а екземпляр використовується функцією для визначення виходу функції.

Вбудований приклад методу екземпляра str.lower:

>>> 'ABC'.lower()
'abc'

str.lower викликається екземпляром рядка, і він використовує інформацію, що міститься в екземплярі, щоб з'ясувати, яку нову рядок повернути.

Методи занять:

Пам'ятайте, в Python все є об'єктом. Це означає, що клас є об'єктом, і його можна передавати як аргумент функції.

Метод класу є функцією , яка є функцією від класу . Він приймає клас як аргумент до нього.

Приклад вбудованого dict.fromkeys:

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

Функція неявно знає власний клас, функція використовує клас для впливу на вихід функції, і вона створює новий із цього класу з ітерабельного. OrdersDict демонструє це, використовуючи той самий метод:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

Метод класу використовує інформацію про клас (а не екземпляр цього класу), щоб впливати на тип класу для повернення.

Статичні методи

Ви згадуєте метод, який "не знає свого класу" - це статичний метод в Python. Він просто приєднаний для зручності до об’єкта класу. При необхідності це може бути окрема функція в іншому модулі, але його підпис дзвінка був би таким же.

Статичний метод - це функція ні класу, ні об'єкта.

Вбудований приклад статичного методу - це str.maketrans з Python 3.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

Враховуючи пару аргументів, він складає словник, який не є функцією його класу.

Це зручно, оскільки strвін завжди доступний у глобальному просторі імен, тому ви можете легко використовувати його за допомогою функції перекладу:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

У Python 2 ви маєте доступ до нього з stringмодуля:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Приклад

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Давайте поміркуємо:

>>> instance = AClass()

Тепер екземпляр може викликати всі методи:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Але зазвичай клас не призначений для виклику методу екземпляра, хоча, як очікується, викликає інші:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Вам потрібно буде явно передати екземпляр, щоб викликати метод екземпляра:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)

"Це статичний метод в Python. Він просто приєднаний для зручності до об'єкта класу. Це може бути необов'язково окремою функцією в іншому модулі, але його підпис виклику був би таким же." Здається більш заплутаним, ніж зручним. Навіщо ви додавати функцію до класу, якщо його тіло не матиме поняття про цей клас.
Гонки легкості з Монікою

@LightnessRacesinOrbit Я детально розповідав про кожну точку
Аарон Хол

Особисто я завжди на це дивився на те, що метод екземпляра - це операція на певному екземплярі, метод класу - це свого роду конструктор (для зручності - нічого подібного, MyClass(1,2,3)а не як, наприклад MyClass.get_special(1,2,3)) і статичний метод просто будучи нормальною функцією, яка в будь-якому випадку могла стояти окремо.
Zizouz212

Так, класичні методи зазвичай використовуються для альтернативних конструкторів (див. Мій приклад dict.fromkeys, див. Також вихідний код pandas.DataFrame), але це не є визначальною характеристикою. Мені іноді просто потрібно отримати доступ до даних, що зберігаються на рівні класу, з методу, без доступу до екземпляра. Якщо ви викликаєте type (self) (або ще гірше, self .__ class__), а не використовуєте self безпосередньо в методі екземпляра, це хороший знак, що ви повинні вважати це методом class. Оскільки классоди не потребують екземплярів, це полегшує їх тестування.
Аарон Холл

4
  • "Метод екземпляра" - це метод, який передається об'єкту екземпляра як його перший параметр, який за умовою називається self. Це за замовчуванням.

  • "Статичний метод" - це метод без початкового selfпараметра. Це реалізовано за допомогою декоратора @staticmethod .

  • "Метод класу" - це метод, коли початковий параметр є не об'єктом екземпляра, а об'єктом класу ( див. Цю частину документів Python щодо того, що таке "об'єкт класу"), який за умовою називається cls. Це реалізовано за допомогою декоратора @classmethod .

Типове використання терміна "статичний метод" у C / C ++ / тощо застосовується як до "статичних", так і до "класових" методів Python, оскільки обидва ці методи не мають посилання на екземпляр. У C / C ++ / тощо методи, як правило, мають неявний доступ до всіх членів / методів класу, які не є екземплярами, тому, ймовірно, це відмінність існує лише у таких мовах, як Python / Ruby / тощо.


Чи має статичний метод в C / C ++ посилання на об’єкт класу? Або просто "члени" класу? Чи можуть вони створити нових членів класу? :)
Аарон Холл

3
@AaronHall У C / C ++ немає такого поняття, як об’єкт класу, і вам не потрібно посилання на нього для виклику статичних методів. Ви просто пишете, Class::staticMethod()і це все (до тих пір, поки вам не заборонено дзвонити, оскільки staticMethod()це приватне або щось таке).
Іксрек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.