Członkowie Klasy Python
Dopiero uczę się Pythona i pochodzę z języka C, więc proszę dać mi znać, jeśli będę miał jakieś zamieszanie / pomieszanie między obydwoma.
Załóżmy, że mam następującą klasę:
class Node(object):
def __init__(self, element):
self.element = element
self.left = self.right = None
@classmethod
def tree(cls, element, left, right):
node = cls(element)
node.left = left
node.right = right
return node
Jest to klasa o nazwie Node
, która przeciąża konstruktor, aby móc obsługiwać różne argumenty w razie potrzeby.
Jaka jest różnica między definiowaniem self.element
tylko w __init__
(Jak pokazano powyżej), a nie wykonywaniem następujących czynności:
class Node(object):
element, left, right = None
def __init__(self, element):
self.element = element
self.left = self.right = None
Isn ' t self.element
in __init__
the same as the class ' S element
variable defined? Czy to nie nadpisałoby element
z None
na element
wartość przekazaną do __init__
?
6 answers
Jeden jest atrybutem klasy, podczas gdy drugi jest atrybutem instancji. Są różne, ale są ze sobą blisko spokrewnione w taki sposób, że czasami wyglądają tak samo.
Ma to związek ze sposobem, w jaki python wyszukuje atrybuty. Jest hierarchia. W prostych przypadkach może to wyglądać tak:
instance -> Subclass -> Superclass -> object (built-in type)
Gdy szukasz atrybutu na instance
w ten sposób...
`instance.val`
...tak naprawdę to pierwszy , Python szuka val
w sama instancja. Następnie, jeśli nie znajdzie val
, szuka w swojej klasie, Subclass
. Następnie, jeśli nie znajdzie val
tam, zagląda do rodzica Subclass
, Superclass
. Oznacza to, że kiedy to robisz...
>>> class Foo():
foovar = 10
def __init__(self, val):
self.selfvar = val
...wszystkie instancje Foo
podziel się foovar
, ale mają swoje własne odrębne selfvar
s. Oto prosty, konkretny przykład tego, jak to działa: {]}
>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10
Jeśli nie dotykamy foovar
, to jest to samo dla f
i Foo
. Ale jeśli zmienimy f.foovar
...
>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10
...dodajemy atrybut instancji, który skutecznie maskuje wartość Foo.foovar
. Jeśli zmienimy Foo.foovar
bezpośrednio, nie wpłynie to na naszą instancję foo
:
>>> Foo.foovar = 7
>>> f.foovar
5
Ale to wpływa na nową instancjęfoo
:
>>> Foo(5).foovar
7
Należy również pamiętać, że zmienne obiekty dodają kolejną warstwę indrection (jak przypomniał mi mgilson). Tutaj f.foovar
odnosi się do tego samego obiektu co Foo.foovar
, więc kiedy zmienisz obiekt, zmiany są propagowane w hierarchii:
>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
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
2012-09-13 16:00:27
W Pythonie możliwe jest posiadanie zmiennych klasowych i zmiennych instancji o tej samej nazwie. Znajdują się one oddzielnie w pamięci i są dostępne zupełnie inaczej.
W kodzie:
class Node(object):
element, left, right = None
def __init__(self, element):
self.element = element
self.left = self.right = None
Pierwszy zbiór zmiennych (poza funkcją __init__
) nazywa się zmiennymi klasy. Następnie można uzyskać do nich dostęp za pomocą Node.element
, itd. Są one równoważne ze statycznymi zmiennymi składowymi w C++ i są współdzielone przez wszystkie instancje klasy.
Drugi zestaw zmienne (wewnątrz funkcji __init__
) nazywane są zmiennymi instancji. Są one dostępne przez obiekt self
, np. self.element
, lub przez nazwę instancji, np. myNode.element
poza klasą.
Ważne jest, aby pamiętać, że musisz użyć formularza self.variable
lub Node.variable
, aby uzyskać dostęp do jednej z nich z poziomu funkcji Członkowskich. Po prostu dostęp do {[9] } będzie próbował uzyskać dostęp do zmiennej lokalnej o nazwie variable
.
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
2012-09-13 15:42:46
Self.element wewnątrz konstruktora jest zmienną instancyjną (jeśli obiekt węzła modyfikuje swoją wartość, zmienia się tylko dla tego obiektu), gdzie ten w drugiej wersji jest zmienną klasy (więc jeśli jeden obiekt węzła modyfikuje swoją wartość, zmieni się dla wszystkich obiektów węzła).
Analogia w C++ byłaby nie-statyczna względem statycznych zmiennych członkowskich w twojej klasie.
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
2012-09-13 15:29:03
Self.element w init jest zmienną instancyjną, można ją uzyskać / ustawić w dowolnej innej funkcji członkowskiej, wpisując self.element. element zadeklarowany w klasie jest zmienną klasy, można ją uzyskać / ustawić wpisując Node.element.
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
2012-09-13 15:35:25
Ważną częścią jest argument self
do __init__
. W rzeczywistości, wdowolnej metodzie instancji , będzie to pierwszy argument. W Pythonie dostęp do instancji jest możliwy tylko podczas wywoływania metod i jest on pokazywany jawnie z argumentem self
.
Kiedy jesteś wewnątrz definicji class
, nie masz jeszcze żadnych instancji, więc tak naprawdę modyfikujesz samą klasę. Tak więc, jeśli zdefiniujesz atrybuty na poziomie klasy, to naprawdę stają się atrybutami klasy, a nie instancją.
Porównując go do C (++), można prawdopodobnie powiedzieć, że "klasy" w tych językach są w zasadzie schematami dla obiektów, które reprezentują. "Obiekty te posiadają atrybuty foo
i bar
, a ponadto następujące metody."W Pythonie, jednak klasy są same w sobie obiektami, a ich główną siłą jest to, że mogą tworzyć kopie (instancje) samych siebie, które również korzystają z metod klasy. Więc to bardziej podobnie jak " będziesz miał foo
i bar
jako atrybuty klasy, a ponadto następującą metodę, której użyjesz do tworzenia instancji."
Więc zamiast planu, to bardziej krok po kroku jak to zrobić.
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
2012-09-13 15:41:09
Kiedy próbujesz uzyskać dostęp do zmiennej z klasą, wygląda ona tylko
cls.__dict__
Ale gdy próbujesz uzyskać dostęp do zmiennej z instancją, wygląda ona najpierw
self.__dict__
If find then return or if can ' t find then it also looks in
cls.__dict__
Tutaj cls jest klasą
class Test:
temp_1=10
temp_2=20
def __init__(self):
self.test_1=10
self.test_2=20
@classmethod
def c_test(cls):
pass
def t_method(self):
pass
print Test.__dict__
print Test().__dict__
Wyjście :
{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}
{'test_2': 20, 'test_1': 10}
Dla detali class special attribute
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
2017-07-30 07:36:54