Python Class Members inicializace

hlasů
37

Právě jsem v poslední době bojoval chybu v Python. Byla to jedna z těch hloupých začátečnických chyb, ale to mě přemýšlet o mechanismech Python (jsem dávno C ++ programátor, nový Python). Budu vyložit buggy kódu a vysvětlit, co jsem udělal, aby to opravit, a pak mám pár otázek ...

Scénář: Mám třídu s názvem A, která má slovník datový člen, následující je jeho kód (to je zjednodušení samozřejmě):

class A:
    dict1={}

    def add_stuff_to_1(self, k, v):
        self.dict1[k]=v

    def print_stuff(self):
        print(self.dict1)

Třída pomocí tohoto kódu je třída B:

class B:

    def do_something_with_a1(self):
        a_instance = A()
        a_instance.print_stuff()        
        a_instance.add_stuff_to_1('a', 1)
        a_instance.add_stuff_to_1('b', 2)    
        a_instance.print_stuff()

    def do_something_with_a2(self):
        a_instance = A()    
        a_instance.print_stuff()            
        a_instance.add_stuff_to_1('c', 1)
        a_instance.add_stuff_to_1('d', 2)    
        a_instance.print_stuff()

    def do_something_with_a3(self):
        a_instance = A()    
        a_instance.print_stuff()            
        a_instance.add_stuff_to_1('e', 1)
        a_instance.add_stuff_to_1('f', 2)    
        a_instance.print_stuff()

    def __init__(self):
        self.do_something_with_a1()
        print(---)
        self.do_something_with_a2()
        print(---)
        self.do_something_with_a3()

Všimněte si, že každé volání do_something_with_aX()inicializuje novou „čistou“ instance třídy A, a vytiskne slovník před a po přidání.

Chyba (v případě, že jste na to přišel ještě):

>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}

Ve druhém inicializaci třídy A, slovníky nejsou prázdné, ale začít s obsahem poslední inicializace, a tak dále. Očekával jsem, že jim start „čerstvá“.

Co řeší tato „chyba“ je samozřejmě dodává:

self.dict1 = {}

V __init__konstruktoru třídy A. Nicméně, to mi udělal zázrak:

  1. Jaký je význam „dict1 = {}“ inicializace v okamžiku prohlášení dict1 lidové (první linie ve třídě A)? Je nesmyslné?
  2. Jaký je mechanismus instance, který způsobuje kopírování referenci od posledního inicializaci?
  3. Pokud přidám „self.dict1 = {}“ v konstruktoru (nebo jakýkoli jiný datový člen), jak to vliv na slovník člen dříve inicializaci instancí?

EDIT: Po odpovědi I nyní pochopili, že tím, že deklaruje datový člen a ne odkazovat se na to v __init__či někde jinde as self.dict1, jsem prakticky definuje, co se nazývá v jazyce C ++ / Java statický datový člen. Tím, že volá to self.dict1 Dělám to „instance vázaný“.

Položena 15/05/2009 v 07:17
zdroj uživatelem
V jiných jazycích...                            


5 odpovědí

hlasů
50

Co si udržet na mysli jako chybu je dokumentována , standardní chování tříd Python.

Deklarování dict venku __init__, jak si původně udělal, je deklarování proměnné s třídou úrovně. Je tvořena pouze jednou na první pohled, kdykoli budete vytvářet nové objekty to bude znovu použít stejný dict. Chcete-li vytvořit instance proměnné deklarovat jim selfv __init__; jeho tak jednoduché, jak to.

Odpovězeno 15/05/2009 v 07:19
zdroj uživatelem

hlasů
2

@Matthew: Zkontrolujte rozdíl mezi členem třídy a členem objektu v objektově orientovaného programování. Tento problém se stane, protože z prohlášení původního dict dělá to členem skupiny, a není členem objekt (jak tomu bylo v původním autorem záměr.) V důsledku toho existuje pouze jednou (je sdílena accross) všechny instance třídy (tj jakmile pro třídy samotné, jako člen třídy objektu samotného), takže chování je naprosto správné.

Odpovězeno 09/10/2009 v 09:21
zdroj uživatelem

hlasů
1

Při přístupu k atributu Například, řekněme, self.foo, python bude nejprve najít ‚foo‘ v self.__dict__. Pokud tomu tak není nalezen, bude python najít ‚foo‘ vTheClass.__dict__

Ve vašem případě dict1je třída A, nikoliv např.

Odpovězeno 15/05/2009 v 07:23
zdroj uživatelem

hlasů
0

Pokud je to váš kód:

class ClassA:
    dict1 = {}
a = ClassA()

Pak jste asi očekávali, že se to stalo v Pythonu:

class ClassA:
    __defaults__['dict1'] = {}

a = instance(ClassA)
# a bit of pseudo-code here:
for name, value in ClassA.__defaults__:
    a.<name> = value

Co se týče můžu říct, že je to, co se stane, kromě toho, že dictmá svůj ukazatel kopírován, namísto hodnoty, což je výchozí chování všude v Pythonu. Podívejte se na tento kód:

a = {}
b = a
a['foo'] = 'bar'
print b
Odpovězeno 15/05/2009 v 08:06
zdroj uživatelem

hlasů
0

deklarace třídy Pythons jsou provedeny jako kódový blok a všech lokálních proměnných definic (jehož definice funkce jsou speciální druh), jsou uloženy v postavené instance třídy. Vzhledem k atributu způsobem vyhledávat díla v jazyce Python, pokud je atribut nebyl nalezen u instance je použita hodnota na třídě.

Is zajímavý článek o syntaxi třídy o historii Pythonu blogu.

Odpovězeno 15/05/2009 v 07:27
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more