Nauka Pythona i ma kilka podstawowych wątpliwości.
1.Widziałem deklarację zmiennej (tutaj ścieżka) jako
class writer:
path = ""
czasami bez jawnej deklaracji, ale inicjalizuj za pośrednictwem __init__
.
def __init__(self, name):
self.name = name
Rozumiem cel __init__
, ale czy wskazane jest deklarowanie zmiennej w innych funkcjach.
2.Jak mogę stworzyć zmienną do przechowywania niestandardowego typu?
class writer:
path = "" # string value
customObj = ??
__name__
atrybutem mają „nazwę”. Nie wszystkie obiekty mają__name__
atrybut, ale nadal możesz mieć do nich odniesienia. Jeśli zaczniemy nazywać „odniesienie” „imieniem”, początkującym wyrządzimy krzywdę na tym torze.Odpowiedzi:
Dobra, najpierw najważniejsze.
W Pythonie nie ma czegoś takiego jak „deklaracja zmiennej” czy „inicjalizacja zmiennej”.
Istnieje po prostu coś, co nazywamy „przypisaniem”, ale prawdopodobnie powinno to być po prostu nazwane „nazewnictwem”.
Przypisanie oznacza „ta nazwa po lewej stronie odnosi się teraz do wyniku oceny prawej strony, niezależnie od tego, do czego się odnosiło wcześniej (jeśli cokolwiek)”.
foo = 'bar' # the name 'foo' is now a name for the string 'bar' foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar', # and starts being a name for the integer 6, resulting from the multiplication
Jako takie, nazwy Pythona (prawdopodobnie lepsze określenie niż „zmienne”) nie mają skojarzonych typów; wartości tak. Możesz ponownie zastosować tę samą nazwę do wszystkiego, niezależnie od jego typu, ale rzecz nadal zachowuje się zależnie od jej typu. Nazwa jest po prostu sposobem na odwołanie się do wartości (obiektu). To odpowiada na twoje drugie pytanie: nie tworzysz zmiennych do przechowywania niestandardowego typu. Nie tworzysz zmiennych do przechowywania określonego typu. W ogóle nie „tworzysz” zmiennych. Nadajesz nazwy przedmiotom.
Druga uwaga: Python kieruje się bardzo prostą zasadą, jeśli chodzi o klasy, która jest w rzeczywistości znacznie bardziej spójna niż to, co robią języki takie jak Java, C ++ i C #: wszystko zadeklarowane wewnątrz
class
bloku jest częścią klasy . Tak więcdef
napisane tutaj funkcje ( ) są metodami, tj. Częścią obiektu klasy (nie są przechowywane dla poszczególnych instancji), podobnie jak w Javie, C ++ i C #; ale inne nazwiska tutaj również są częścią klasy. Nazwy są po prostu nazwami i nie mają powiązanych typów, a funkcje są również obiektami w Pythonie. A zatem:class Example: data = 42 def method(self): pass
Klasy też są obiektami w Pythonie.
Więc teraz stworzyliśmy obiekt o nazwie
Example
, który reprezentuje klasę wszystkich rzeczy, które sąExample
s. Ten obiekt ma dwa atrybuty dostarczane przez użytkownika (w C ++ „składowe”; w C # „pola, właściwości lub metody”; w języku Java „pola lub metody”). Jeden z nich ma nazwędata
i przechowuje wartość całkowitą42
. Drugi nazywa sięmethod
i przechowuje obiekt funkcji. (Istnieje kilka innych atrybutów, które Python dodaje automatycznie).Jednak te atrybuty nadal nie są częścią obiektu. Zasadniczo obiekt jest tylko zbiorem większej liczby nazw (nazw atrybutów), dopóki nie przejdziesz do rzeczy, których nie można już podzielić. W ten sposób wartości mogą być współużytkowane między różnymi instancjami klasy, a nawet między obiektami różnych klas, jeśli celowo to ustawisz.
Utwórzmy instancję:
Teraz mamy oddzielny obiekt o nazwie
x
, który jest instancjąExample
.data
Imethod
faktycznie nie jest częścią obiektu, ale nadal możemy szukać ich poprzezx
powodu jakiejś magii, że Python robi za kulisami. Wmethod
szczególności, gdy spojrzymy w górę , zamiast tego otrzymamy „metodę powiązaną” (kiedy ją wywołasz,x
zostanie przekazana automatycznie jakoself
parametr, co nie może się zdarzyć, jeśli spojrzymyExample.method
bezpośrednio w górę ).Co się dzieje, gdy próbujemy użyć
x.data
?Kiedy go badamy, najpierw znajduje się w obiekcie. Jeśli nie zostanie znaleziony w obiekcie, Python szuka w klasie.
Jednak kiedy przypiszemy do
x.data
, Python utworzy atrybut na obiekcie. To będzie nie zastąpi atrybut class'.To pozwala nam na inicjalizację obiektów . Python automatycznie wywoła
__init__
metodę klasy w nowych instancjach, gdy zostaną utworzone, jeśli są obecne. W tej metodzie możemy po prostu przypisać do atrybutów, aby ustawić wartości początkowe dla tego atrybutu na każdym obiekcie:class Example: name = "Ignored" def __init__(self, name): self.name = name # rest as before
Teraz musimy określić,
name
kiedy tworzymyExample
, a każda instancja ma swoją własnąname
. Python zignoruje atrybut classExample.name
za każdym razem, gdy wyszukamy.name
instancję, ponieważ atrybut instancji zostanie znaleziony jako pierwszy.Ostatnie zastrzeżenie: modyfikacja (mutacja) i przypisanie to dwie różne rzeczy!
W Pythonie ciągi znaków są niezmienne. Nie można ich modyfikować. Kiedy robisz:
a = 'hi ' b = a a += 'mom'
Nie zmieniasz oryginalnego ciągu „cześć”. To niemożliwe w Pythonie. Zamiast tego tworzysz nowy łańcuch
'hi mom'
i powodujesz,a
że przestajesz być nazwą dla'hi '
, a'hi mom'
zamiast tego zaczynasz być nazwą . Stworzyliśmyb
również nazwę dla'hi '
, a po ponownym zastosowaniua
nazwyb
nadal jest nazwą dla'hi '
, ponieważ'hi '
nadal istnieje i nie została zmieniona.Ale listy można zmienić:
a = [1, 2, 3] b = a a += [4]
Teraz
b
jest również [1, 2, 3, 4], ponieważ nadaliśmyb
nazwę tej samej rzeczy, która zostałaa
nazwana, a potem ją zmieniliśmy. Nie utworzyliśmy nowej listy dlaa
do nazwania, ponieważ Python po prostu traktuje+=
listy inaczej.Ma to znaczenie dla obiektów, ponieważ gdybyś miał listę jako atrybut klasy i używał instancji do modyfikowania listy, wtedy zmiana byłaby „widoczna” we wszystkich innych instancjach. Dzieje się tak, ponieważ (a) dane są w rzeczywistości częścią obiektu klasy, a nie obiektu instancji; (b) ponieważ modyfikowałeś listę i nie wykonywałeś prostego przypisania, nie utworzyłeś nowego atrybutu instancji, który ukrywałby atrybut klasy.
źródło
To może być opóźnione o 6 lat, ale w Pythonie 3.5 i nowszych deklarujesz typ zmiennej, taki jak ten:
albo to:
variable_name # type: shinyType
Więc w twoim przypadku (jeśli masz
CustomObject
zdefiniowaną klasę), możesz zrobić:Zobacz to czy tamto, aby uzyskać więcej informacji.
źródło
Nie ma potrzeby deklarowania nowych zmiennych w Pythonie. Jeśli mówimy o zmiennych w funkcjach lub modułach, nie jest potrzebna żadna deklaracja. Wystarczy przypisać wartość do nazwy, gdzie jest to potrzebne:
mymagic = "Magic"
. Zmienne w Pythonie mogą przechowywać wartości dowolnego typu i nie można tego ograniczyć.Twoje pytanie dotyczy jednak klas, obiektów i zmiennych instancji. Idiomatyczny sposób tworzenia zmiennych instancji znajduje się w
__init__
metodzie i nigdzie indziej - podczas gdy można tworzyć nowe zmienne instancji w innych metodach lub nawet w niepowiązanym kodzie, to po prostu zły pomysł. Sprawi to, że Twój kod będzie trudny do zrozumienia lub utrzymania.Na przykład:
class Thing(object): def __init__(self, magic): self.magic = magic
Łatwy. Teraz instancje tej klasy mają
magic
atrybut:thingo = Thing("More magic") # thingo.magic is now "More magic"
Tworzenie zmiennych w przestrzeni nazw samej klasy prowadzi do zupełnie innego zachowania. Funkcjonalnie jest inny i powinieneś to robić tylko wtedy, gdy masz do tego konkretny powód. Na przykład:
class Thing(object): magic = "Magic" def __init__(self): pass
Spróbuj teraz:
thingo = Thing() Thing.magic = 1 # thingo.magic is now 1
Lub:
class Thing(object): magic = ["More", "magic"] def __init__(self): pass thing1 = Thing() thing2 = Thing() thing1.magic.append("here") # thing1.magic AND thing2.magic is now ["More", "magic", "here"]
Dzieje się tak, ponieważ przestrzeń nazw samej klasy różni się od przestrzeni nazw utworzonych z niej obiektów. Zostawię ci trochę więcej badań.
Wiadomość do domu jest taka, że idiomatyczny Python ma (a) inicjować atrybuty obiektów w Twojej
__init__
metodzie i (b) dokumentować zachowanie Twojej klasy zgodnie z potrzebami. Nie musisz kłopotać się pełną dokumentacją na poziomie Sfinksa dla wszystkiego, co kiedykolwiek napiszesz, ale przynajmniej kilka komentarzy na temat wszelkich szczegółów, których ty lub ktoś inny może potrzebować, aby ją odebrać.źródło
W celu określenia zakresu używam:
custom_object = None
źródło
Zmienne mają zakres, więc tak, warto mieć zmienne, które są specyficzne dla twojej funkcji. Nie zawsze musisz jasno określać ich definicję; zwykle możesz ich po prostu użyć. Tylko jeśli chcesz zrobić coś specyficznego dla typu zmiennej, np. Dołączyć do listy, musisz je zdefiniować przed rozpoczęciem ich używania. Typowy tego przykład.
list = [] for i in stuff: list.append(i)
Nawiasem mówiąc, to nie jest dobry sposób na ustawienie listy. Lepiej byłoby powiedzieć:
list = [i for i in stuff] # list comprehension
... ale błądzę.
Twoje inne pytanie. Obiekt niestandardowy powinien być klasą.
class CustomObject(): # always capitalize the class name...this is not syntax, just style. pass customObj = CustomObject()
źródło