it-swarm-eu.dev

Proč argument explicitně argument „self“ do metody Python?

Když definujete metodu ve třídě v Pythonu, vypadá to takto:

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

Ale v některých jiných jazycích, například C #, máte odkaz na objekt, ke kterému je metoda vázána klíčovým slovem "this", aniž by byl deklarován jako argument v prototypu metody. 

Bylo to v jazyce Python úmyslné rozhodnutí o jazykovém návrhu nebo existují nějaké implementační detaily, které vyžadují, aby byl argument „self“ jako argument?

180
Readonly

Rád cituji Petersův Zen z Pythonu. "Explicitní je lepší než implicitní."

V jazyce Java a C++ lze odvodit 'this.', s výjimkou případů, kdy máte názvy proměnných, které znemožňují odvodit. Takže to někdy potřebujete a někdy ne.

Python se rozhodl, že bude dělat takovéto věci spíše explicitně než na základě pravidla. 

Navíc, protože není nic naznačeno nebo předpokládáno, jsou části implementace vystaveny. self.__class__, self.__dict__ a další "vnitřní" struktury jsou k dispozici zřetelným způsobem.

88
S.Lott

Je to minimalizovat rozdíl mezi metodami a funkcemi. To vám umožní snadno vytvářet metody v metaclasses, nebo přidat metody za běhu do pre-existující třídy.

např.

>>> 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!
>>>

Také (pokud vím) usnadňuje implementaci běhového prostředí python.

55
Ryan

Navrhuji, abyste si přečetli na blogu Guida van Rossum na toto téma - Proč musí explicitní já zůstat .

Když je definice metody dekorována, nevíme, zda ji automaticky dáme parametru „self“ nebo ne: decorator by mohl funkci převést na statickou metodu (která nemá „self“) nebo metodu třídy (která má legrační druh sebe, který odkazuje na třídu namísto instance), nebo to může udělat něco úplně jiného (je to triviální psát dekoratér, který implementuje '@ classmethod' nebo '@ staticmethod' v čistém Pythonu). Neexistuje žádný způsob, aniž bychom věděli, co dekoratér dělá, zda má být metoda definována s implicitním argumentem „self“ nebo ne.

Odmítám hacky, jako je speciální @classmethod 'a' @ staticmethod '.

51
bhadra

Python vás nevynucuje používat "self". Můžete mu dát to, co chcete. Stačí si uvědomit, že první argument v hlavičce definice metody je odkazem na objekt.

16
Victor Noagbodji

Také to umožňuje: (zkrátka, vyvolání Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) se vrátí 12, ale bude to dělat v nejbláznivějších způsobech.

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

To je samozřejmě těžší představit v jazycích jako Java a C #. Tím, že učiníte sebevědomý odkaz, můžete se odkazovat na jakýkoli objekt tím, že tento odkaz na sebe. Také takový způsob hraní s třídami za běhu je těžší dělat ve více statických jazycích - ne to je nutně dobré nebo špatné. Je to jen to, že explicitní já dovolí existenci tohoto šílenství.

Představte si to: Chtěli bychom přizpůsobit chování metod (pro profilování, nebo nějaké šílené černé kouzlo). To nás může vést k zamyšlení: co kdybychom měli třídu Method, jejíž chování bychom mohli potlačit nebo ovládat?

Tady to je:

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()

A teď: InnocentClass().magic_method() se bude chovat jako očekávané. Metoda bude vázána parametrem innocent_self na InnocentClass a pomocí magic_self na instanci MagicMethod. Divné co? Je to jako mít 2 klíčová slova this1 a this2 v jazycích jako Java a C #. Magie takhle umožňuje rámcům dělat věci, které by jinak byly mnohem podrobnější.

Opět nechci komentovat Etiku této věci. Chtěl jsem jen ukázat věci, které by bylo obtížnější udělat bez výslovného vlastního odkazu.

6
vlad-ardelean

Myslím si, že skutečným důvodem kromě "Zen Pythonu" je, že funkce jsou v Pythonu prvotřídními občany. 

Což je v podstatě dělá objektem. Základním problémem je, zda jsou vaše funkce také objektové, pak v objektově orientovaném paradigmatu, jak byste posílali zprávy objektům, když samotné zprávy jsou objekty? 

Vypadá to jako problém s kuřecím vajíčkem, aby se tento paradox zmenšil, jedinou možnou cestou je buď předat kontext provádění metodám nebo je odhalit. Vzhledem k tomu, že python může mít vnořené funkce, nebylo by to možné, protože kontext provádění by se změnil pro vnitřní funkce. 

To znamená, že jediným možným řešením je výslovně projít „já“ (kontext provádění).

Domnívám se, že je to problém s implementací, kdy Zen přišel mnohem později.

2
pankajdoharey

Myslím, že to souvisí s PEP 227:

Názvy v oboru třídy nejsou přístupné. Jména se řeší v nejvnitřnějším ohraničujícím prostoru funkce . Pokud definice třídy nastane v řetězci Vnořených oborů, proces rozlišení přeskočí definice třídy . Toto pravidlo zabraňuje lichým interakcím mezi atributy třídy A přístupem k místní proměnné. Pokud v definici třídy dojde k operaci pojmenování , Vytvoří na výsledném objektu třídy Atribut. Pro přístup k této proměnné v metodě, nebo ve funkci Vnořené v rámci metody, musí být použit odkaz na atribut, buď přes vlastní nebo přes název třídy.

2
daole

Jak je vysvětleno v self v Python, Demystified

něco jako obj.meth (args) se stane Class.meth (obj, args). Proces volání je automatický, zatímco přijímací proces není (jeho explicitní). To je důvod, proč první parametr funkce ve třídě musí být samotný objekt. 

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

    def distance(self):
        """Find distance from Origin"""
        return (self.x**2 + self.y**2) ** 0.5

Invocations:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () definuje tři parametry, ale právě jsme prošli dva (6 a 8). Podobně vzdálenost () vyžaduje jeden, ale nulové argumenty byly předány. 

Proč si Python nestěžuje na toto číslo argumentu nesouhlasí?

Obecně platí, že když zavoláme metodu s některými argumenty, vyvolá se odpovídající funkce třídy umístěním objektu metody před první argument. Takže cokoliv jako obj.meth (args) se stane Class.meth (obj, args). Volání je automatické, zatímco přijímací proces není (jeho explicitní).

Toto je důvod, proč první parametr funkce ve třídě musí být samotný objekt. Psaní tohoto parametru jako self je pouze konvence. Není to klíčové slovo a nemá v Pythonu žádný zvláštní význam. Mohli bychom použít jiné názvy (jako je tento), ale důrazně vám doporučuji, abyste to neudělali. Používání jiných názvů než self je na většinu vývojářů zamyšleno a zhoršuje čitelnost kódu ("Čtení").
...
První příklad self.x je atribut instance, zatímco x je lokální proměnná. Nejsou stejné a leží v různých jmenných prostorech.

Já je tady k pobytu

Mnozí z nich navrhli, aby aby se toto klíčové slovo stalo v Pythonu, jako je tomu v C++ a Java. Tím by se eliminovalo nadbytečné používání explicitního self z formálního seznamu parametrů v metodách.stát se. Alespoň ne v blízké budoucnosti. Hlavním důvodem je zpětná kompatibilita. Zde je blog od samotného tvůrce Pythonu, který vysvětluje, proč musí explicitní já zůstat.

0
mon