Dlaczego musisz mieć jawnie argument "self" w metodzie Pythona?

Podczas definiowania metody na klasie w Pythonie wygląda to mniej więcej tak:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

Ale w niektórych innych językach, takich jak C#, masz odniesienie do obiektu, do którego metoda jest powiązana ze słowem kluczowym "this", bez deklarowania go jako argumentu w prototypie metody.

Czy była to zamierzona decyzja o projektowaniu języka w Pythonie, czy też są jakieś szczegóły implementacji, które wymagają podania " ja " jako argumentu?

 176
Author: Readonly, 2008-09-16

8 answers

Lubię cytować Zen Pythona Petersa. "Explicit jest lepszy niż implicit."

W Javie i C++ 'this. ' można wydedukować, z wyjątkiem sytuacji, gdy masz nazwy zmiennych, które uniemożliwiają wydedukowanie. Więc czasami tego potrzebujesz, a czasami nie.

Python wybiera, aby takie rzeczy były jednoznaczne, a nie oparte na regułach.

Dodatkowo, ponieważ nic nie jest domniemane lub domniemane, części implementacji są ujawnione. self.__class__, self.__dict__ i inne struktury "wewnętrzne" to dostępne w oczywisty sposób.

 84
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-08 11:35:10

Ma na celu zminimalizowanie różnicy między metodami i funkcjami. Pozwala na łatwe generowanie metod w metaklasach lub dodawanie metod w czasie wykonywania do wcześniej istniejących klas.

Np.

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

To również (o ile wiem) ułatwia implementację środowiska uruchomieniowego Pythona.

 54
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 00:47:18

Proponuję przeczytać blog Guido van Rossuma na ten temat - Dlaczego jawne ja musi zostać.

Kiedy definicja metody jest dekorowana, nie wiemy, czy automatycznie nadać jej parametr "self", czy nie: dekorator może przekształcić funkcję w statyczną metodę (która nie ma "self"), czy metodę klasy (która ma zabawny rodzaj "self", który odnosi się do klasy zamiast instancji), lub może zrobić coś zupełnie innego (jest to "self"). trywialne jest napisanie dekoratora implementującego ' @ classmethod 'lub' @staticmethod ' w czystym Pythonie). Nie ma mowy, nie wiedząc, co robi dekorator, czy nadać metodzie zdefiniowanej ukrytym argumentem "ja", czy nie.

Odrzucam hacki typu special-casing '@classmethod ' i '@staticmethod'.

 50
Author: bhadra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-16 19:58:50

Python nie zmusza cię do używania "ja". Możesz nadać mu dowolne imię. Trzeba tylko pamiętać, że pierwszy argument w nagłówku definicji metody jest odniesieniem do obiektu.

 16
Author: Victor Noagbodji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 01:15:16

Pozwala również na to: (w skrócie, wywołanie Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) zwróci 12, ale zrobi to w najbardziej szalony sposób.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Oczywiście trudniej to sobie wyobrazić w językach takich jak Java i C#. Poprzez wyraźne odniesienie do siebie, możesz swobodnie odnosić się do dowolnego obiektu za pomocą tego odniesienia. Ponadto, taki sposób grania klasami w czasie wykonywania jest trudniejszy do zrobienia w bardziej statycznych językach - nie to, że jest to koniecznie dobre lub złe. Tylko, że Jawna jaźń pozwala na to wszystko szaleństwo istnienia.

Co więcej, wyobraź sobie to: chcielibyśmy dostosować zachowanie metod (do profilowania, lub jakiejś szalonej czarnej magii). Może to prowadzić nas do myślenia: co by było, gdybyśmy mieli klasę Method, której zachowanie moglibyśmy nadpisać lub kontrolować?

No to jest:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

And now: InnocentClass().magic_method() will act like expected. Metoda zostanie powiązana z parametrem innocent_self do InnocentClass, a z magic_self do instancji MagicMethod. Dziwne, co? To tak jakby mieć 2 słowa kluczowe this1 i this2 w językach takich jak Java i C#. Magia taka jak ta pozwala frameworkom robić rzeczy, które w przeciwnym razie byłyby znacznie bardziej gadatliwe.

Ponownie, nie chcę komentować etyki tych rzeczy. Chciałem tylko pokazać rzeczy, które byłyby trudniejsze do zrobienia bez wyraźnego odniesienia do siebie.

 5
Author: vlad-ardelean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-12 11:18:06

Myślę, że prawdziwym powodem oprócz "Zen Pythona" jest to, że funkcje są obywatelami pierwszej klasy w Pythonie.

Co zasadniczo czyni je obiektem. Teraz podstawową kwestią jest, jeśli twoje funkcje są również obiektowe, to w paradygmacie zorientowanym obiektowo, Jak wysyłasz wiadomości do obiektów, gdy same wiadomości są obiektami ?

Wygląda na problem jaj kurzych, aby zmniejszyć ten paradoks, jedynym możliwym sposobem jest albo przekazanie kontekstu wykonania metodom, albo Wykryj to. Ale ponieważ python może mieć zagnieżdżone funkcje, nie byłoby to możliwe, ponieważ kontekst wykonania zmieniłby się dla funkcji wewnętrznych.

Oznacza to, że jedynym możliwym rozwiązaniem jest jawne przekazanie "self" (kontekstu wykonania).

Więc uważam, że jest to problem implementacji Zen przyszedł znacznie później.

 2
Author: pankajdoharey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-01 16:01:06

Myślę, że ma to związek z PEP 227:

Nazwy w zakresie klas nie są dostępne. Nazwy są rozwiązywane w najskrytszy domknięty zakres funkcji. Jeśli definicja klasy występuje w łańcuch zagnieżdżonych zakresów, proces rozdzielczości pomija klasę definicje. Reguła ta zapobiega dziwnym interakcjom między klasami atrybuty i dostęp do zmiennych lokalnych. Jeśli operacja wiążąca nazwę występuje w definicji klasy, tworzy atrybut na wynikowym obiekt klasy. Aby uzyskać dostęp tej zmiennej w metodzie lub w funkcji zagnieżdżone w metodzie, musi być użyte odniesienie do atrybutu, albo poprzez self lub poprzez nazwę klasy.

 1
Author: daole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-10 10:45:22

Jest jeszcze jedna bardzo prosta odpowiedź: zgodnie z zen Pythona, "explicit is better than implicit".

 -3
Author: Flávio Amieiro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 00:49:26