Що таке "метод" у Python?


75

Хто-небудь, будь ласка, може пояснити мені дуже простими словами, що таке "метод" у Python?

Річ у тому, що у багатьох підручниках з Python для початківців це слово вживається таким чином, ніби початківець вже знав, що таке метод у контексті Python. Хоча я, звичайно, знайомий із загальним значенням цього слова, я не маю уявлення, що означає цей термін у Python. Тож, будь ласка, поясніть мені, про що йдеться у методі "Pythonian".

Деякі дуже прості приклади коду були б дуже вдячні, оскільки картинка коштує тисячі слів.


1
"багато підручників з Python"? Про які конкретні навчальні посібники ви говорите? Ми не можемо рекомендувати інший, якщо ми не знаємо, що ви зараз читаєте.
S.Lott

5
Метод - загальний термін, він не має іншого значення в Python, тому, мабуть, тому він використовується настільки недбалий. Дивіться en.wikipedia.org/wiki/Method_(computer_science)
Йохен Рітцель

@ S.Lott: Мені шкода, можливо, я був надто абсолютистичним, висловлюючи своє судження щодо підручників з Python.
блискучий

1
Я не скаржуся. "багато" може бути правдою. Але я задаю питання. Про які конкретні навчальні посібники ви говорите?
S.Lott

Відповіді:


85

Це функція, яка є членом класу:

class C:
    def my_method(self):
        print("I am a C")

c = C()
c.my_method()  # Prints("I am a C")

Просто як це!

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


8
Тут варто зауважити, що екземпляр повинен передаватися вручну в метод, і за домовленістю він передається як self.
Skilldrick

7
@Silldrick: Ви, мабуть, маєте на увазі правильну річ, але ваш коментар таким, як є, передбачає щось неправильне. Екземпляр не потрібно передавати явно / вручну під час виклику методу на ньому. Але метод повинен отримувати його явно, тобто вам потрібно вручну додати параметр для екземпляра (який, так, називається selfза згодою).

4
@delnan - Так, дякую за роз'яснення - коли я кажу, що вручну передано те, що я насправді маю на увазі, це має бути явно отримане як параметр, але воно передається неявно.
Skilldrick

5
@AaronMcSmooth: Відповідь AndiDog, безумовно, є більш повною. Мені було б цікаво дізнатись, чи вважає @brilliant "кращим" чи занадто повним. Іноді краща проста відповідь. (Оскільки мені не подобається, коли мене звинувачують у
повторному блуді

2
@brilliant. не дозволяйте спрощеній відповіді вас бентежити. Тут (трохи) більше, ніж "метод є функцією", але різниця є абсолютно важливою. Подивіться на іншу відповідь і розмістіть нові запитання щодо будь-чого, що вам цього не зрозуміло.
aaronasterling

41

Метод - це функція, яка приймає екземпляр класу як перший параметр. Методи є членами класів.

class C:
    def method(self, possibly, other, arguments):
        pass # do something here

Оскільки ви хотіли знати, що це конкретно означає в Python, можна розрізнити зв’язані та незв’язані методи. У Python усі функції (і як такі також методи) є об'єктами, які можна передавати та "грати з ними". Тож різниця між незв’язаними та зв’язаними методами полягає в:

1) Фіксовані методи

# Create an instance of C and call method()
instance = C()

print instance.method # prints '<bound method C.method of <__main__.C instance at 0x00FC50F8>>'
instance.method(1, 2, 3) # normal method call

f = instance.method
f(1, 2, 3) # method call without using the variable 'instance' explicitly

Зв’язані методи - це методи, що належать до екземплярів класу. У цьому прикладі instance.methodприв'язується до екземпляра, що викликається instance. Щоразу, коли викликається цей зв’язаний метод, екземпляр передається як перший параметр автоматично - що викликається selfза домовленістю.

2) Незв’язані методи

print C.method # prints '<unbound method C.method>'
instance = C()
C.method(instance, 1, 2, 3) # this call is the same as...
f = C.method
f(instance, 1, 2, 3) # ..this one...

instance.method(1, 2, 3) # and the same as calling the bound method as you would usually do

Коли ви отримуєте доступ C.method(метод всередині класу, а не всередині екземпляра), ви отримуєте незв'язаний метод. Якщо ви хочете викликати його, вам потрібно передати екземпляр як перший параметр, оскільки метод не є прив'язаний до жодного екземпляра.

Знаючи цю різницю, ви можете використовувати функції / методи як об'єкти, наприклад, передавати методи навколо. Як приклад використання, уявіть API, який дозволяє визначити функцію зворотного виклику, але ви хочете надати метод як функцію зворотного виклику. Немає проблем, просто передайте self.myCallbackMethodяк зворотний виклик, і він буде автоматично викликаний з екземпляром як перший аргумент. Це неможливо в статичних мовах, таких як C ++ (або лише при обманах).

Сподіваюся, ви зрозуміли суть;) Я думаю, що це все, що ви повинні знати про основи методів. Ви також можете прочитати більше про декоратори classmethodта staticmethodдекоратори, але це вже інша тема.


Супер цікаво, дякую за пояснення. Виглядає як незвично агресивна умова для python (переходити до всіх наступних аргументів, коли він викликається крапковими позначеннями в екземплярі класу), але, безумовно, має сенс.
Luke Davis

Це не дуже незвично: єдиний синтаксис виклику функції був запропонований / реалізований вже на багатьох мовах.
AndiDog

25

У Python метод - це функція, яка доступна для даного об'єкта через тип об'єкта .

Наприклад, якщо ви створюєте my_list = [1, 2, 3], то appendметод може бути застосований до , my_listтому що це список Python: my_list.append(4). Усі списки мають appendметод просто тому, що вони є списками.

В якості іншого прикладу, якщо ви створюєте my_string = 'some lowercase text', то upperметод може бути застосований до my_stringпросто тому , що це рядок Python: my_string.upper().

Списки не мають upperметоду, а рядки не мають appendметоду. Чому? Оскільки методи існують лише для певного об’єкта, якщо вони були чітко визначені для цього типу об’єкта , і розробники Python (до цього часу) вирішили, що ці конкретні методи не потрібні для цих конкретних об'єктів.

Для виклику методу використовується формат object_name.method_name(), і всі аргументи методу перераховані в дужках. Метод неявно діє на іменований об'єкт, і, отже, деякі методи не мають жодних заявлених аргументів, оскільки сам об'єкт є єдиним необхідним аргументом. Наприклад, my_string.upper()не має яких - небудь перерахованих аргументів , тому що єдиний обов'язковий аргумент є сам об'єкт, my_string.

Один загальний момент плутанини стосується наступного:

import math
math.sqrt(81)

Це sqrtметод mathоб'єкта? Ні. Так ви викликаєте sqrtфункцію з mathмодуля. Формат, який використовується module_name.function_name(), замість object_name.method_name(). Загалом, єдиний спосіб розрізняти два формати (візуально), щоб дивитися в іншій частині коду і подивитися , якщо частина до періоду ( math, my_list, my_string) визначається як об'єкт або модуль.


4

Вибачте, але - на мій погляд - РічіХіндл абсолютно правий, кажучи цей метод ...

Це функція, яка є членом класу.

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

>>> class C:
...     pass
...
>>> def func(self):
...     print 'func called'
...
>>> func('whatever')
func called

Тепер ми додаємо член до Cкласу, який є посиланням на функцію. Після цього ми можемо створити екземпляр класу і викликати його метод так, ніби він був визначений всередині класу:

>>> C.func = func
>>> o = C()
>>> o.func()
func called

Ми також можемо використати альтернативний спосіб виклику методу:

>>> C.func(o)
func called

У o.funcнавіть проявляється точно так же , як метод класу:

>>> o.func
<bound method C.func of <__main__.C instance at 0x000000000229ACC8>>

І ми можемо спробувати зворотний підхід. Давайте визначимо клас і викрадемо його метод як функцію:

>>> class A:
...     def func(self):
...         print 'aaa'
...
>>> a = A()
>>> a.func
<bound method A.func of <__main__.A instance at 0x000000000229AD08>>
>>> a.func()
aaa

Поки це виглядає однаково. Тепер функція викрадення:

>>> afunc = A.func
>>> afunc(a)
aaa    

Істина полягає в тому, що метод не приймає аргументу "що б то не було":

>>> afunc('whatever')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method func() must be called with A instance as first 
  argument (got str instance instead)

IMHO, це не аргумент проти методу - це функція, яка є членом класу .

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


У delnan: Ви писали: "Екземпляр не потрібно передавати явно / вручну, коли викликається метод на ньому". Насправді, ви повинні передавати це явно. Єдина синтаксична різниця полягає в тому, що ви не пишете його як перший аргумент у дужках. Розміщення його перед назвою методу (розділене крапкою) та пропускання ідентифікатора класу насправді є синактичним цукром.
pepr

0

http://docs.python.org/2/tutorial/classes.html#method-objects

Зазвичай метод викликається відразу після його прив’язки:

x.f()

У прикладі MyClass це поверне рядок "hello world". Однак не потрібно викликати метод відразу: xf є об'єктом методу, і його можна зберегти і викликати пізніше. Наприклад:

xf = x.f
while True:
    print xf()

продовжуватиме друкувати привіт світ до кінця часів.

Що саме відбувається, коли викликається метод? Можливо, ви помітили, що xf () було викликано без аргументу вище, хоча визначення функції для f () вказало аргумент. Що сталося із суперечкою? Звичайно, Python викликає виняток, коли функція, яка вимагає аргумент, викликається без будь-якого - навіть якщо аргумент насправді не використовується ...

Насправді, ви, можливо, здогадалися з відповіді: особливість методів полягає в тому, що об’єкт передається як перший аргумент функції. У нашому прикладі виклик xf () точно еквівалентний MyClass.f (x). Загалом, виклик методу зі списком з n аргументів еквівалентний виклику відповідної функції зі списком аргументів, який створюється шляхом вставки об'єкта методу перед першим аргументом.

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


0

Якщо ви думаєте, що об’єкт схожий на іменник, то метод схожий на дієслово. Використовуйте метод відразу після об’єкта (тобто рядка або списку), щоб застосувати до нього дію методу.


0

Щоб зрозуміти методи, спочатку слід подумати з точки зору об’єктно-орієнтованого програмування: Візьмемо машину як клас. Всі автомобілі мають спільні речі та речі, які роблять їх унікальними, наприклад, у всіх автомобілів є 4 колеса, двері, кермо .... але Ваш індивідуальний автомобіль (давайте назвемо це, my_toyota) червоний, починаючи з 0-60 в 5.6s Далі машина зараз знаходиться у мене вдома, двері заблоковані, багажник порожній ... Все це властивості екземпляра my_toyota. твоя_хонда може бути в дорозі, багажник багатий продуктами ...

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

як псевдокод ви зробите:

my_toyota.drive(shop)

змінити місце розташування з мого будинку на магазин чи

my_toyota.load([milk, butter, bread]

цим багажник тепер завантажений [молоком, маслом, хлібом].

Як такий метод є практично функцією, яка діє як частина об'єкта:

class Car(vehicle)
    n_wheels = 4

    load(self, stuff):
    '''this is a method, to load stuff into the trunk of the car'''
        self.open_trunk
        self.trunk.append(stuff)
        self.close_trunk

код тоді буде:

my_toyota = Car(red)
my_shopping = [milk, butter, bread]
my_toyota.load(my_shopping)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.