Jaka jest różnica między klasami starego i nowego stylu w Pythonie? Kiedy powinienem użyć jednego lub drugiego?
Z klas w nowym stylu i klasycznych :
Do Pythona 2.1 klasy w starym stylu były jedynym dostępnym smakiem dla użytkownika.
Pojęcie klasy (w starym stylu) nie jest powiązane z pojęciem typu: jeśli
x
jest instancją klasy w starym stylu,x.__class__
oznacza klasęx
, aletype(x)
zawsze jest<type 'instance'>
.Odzwierciedla to fakt, że wszystkie instancje w starym stylu, niezależnie od ich klasy, są implementowane za pomocą jednego wbudowanego typu, zwanego instancją.
Klasy nowego stylu zostały wprowadzone w Pythonie 2.2, aby ujednolicić pojęcia klasy i typu . Klasa nowego stylu jest po prostu typem zdefiniowanym przez użytkownika, nie więcej, nie mniej.
Jeśli x jest instancją klasy nowego stylu,
type(x)
to zwykle jest takie samo jakx.__class__
(chociaż nie jest to gwarantowane - instancja klasy nowego stylu może zastąpić zwracaną wartośćx.__class__
).Główną motywacją do wprowadzenia klas w nowym stylu jest zapewnienie zunifikowanego modelu obiektowego z pełnym meta-modelem .
Ma również szereg natychmiastowych korzyści, takich jak możliwość podklasowania większości typów wbudowanych lub wprowadzenie „deskryptorów”, które umożliwiają obliczanie właściwości.
Ze względu na kompatybilność klasy są nadal domyślnie w starym stylu .
Klasy nowego stylu są tworzone przez określenie innej klasy nowego stylu (tj. Typu) jako klasy nadrzędnej lub obiektu „typu najwyższego poziomu”, jeśli nie jest potrzebny żaden inny element nadrzędny.
Zachowanie klas w nowym stylu różni się od zachowania klas w starym stylu wieloma ważnymi szczegółami oprócz tego, jaki typ zwraca.
Niektóre z tych zmian są fundamentalne dla nowego modelu obiektowego, na przykład sposób wywoływania specjalnych metod. Inne to „poprawki”, których wcześniej nie można było wdrożyć z powodów związanych ze zgodnością, na przykład kolejność rozwiązywania metod w przypadku wielokrotnego dziedziczenia.
Python 3 ma tylko klasy w nowym stylu .
Bez względu na to, czy podklasujesz,
object
czy nie, klasy w Pythonie 3 są w nowym stylu.
type(x)
. Jeśli nie podklasuję typu wbudowanego, wydaje mi się, że nie widzę żadnej korzyści z klas nowego stylu. Wadą jest dodatkowe pisanie(object)
.super()
nie działają na klasach w starym stylu. Nie wspominając już o tym, jak mówi ten artykuł, istnieją podstawowe poprawki, takie jak MRO i specjalne metody, które są więcej niż dobrym powodem do korzystania z niego.Pod względem deklaracji:
Klasy w nowym stylu dziedziczą po obiekcie lub z innej klasy w nowym stylu.
Zajęcia w starym stylu nie.
Uwaga do Python 3:
Python 3 nie obsługuje klas starego stylu, więc każda z wymienionych powyżej form powoduje klasę nowego stylu.
źródło
object
.class AnotherOldStyleClass: pass
class A: pass
iclass A(): pass
są ściśle równoważne. Pierwszy oznacza „A nie dziedziczy żadnej klasy nadrzędnej”, a drugi oznacza „A dziedziczy brak klasy nadrzędnej” . To dość podobne donot is
iis not
Ważne zmiany zachowania między klasami starego i nowego stylu
Exception
(przykład poniżej)__slots__
dodanyZmieniono MRO (Method Resolution Order)
Zostało to wspomniane w innych odpowiedziach, ale oto konkretny przykład różnicy między klasycznym MRO a C3 MRO (używanym w klasach nowego stylu).
Pytanie dotyczy kolejności wyszukiwania atrybutów (które obejmują metody i zmienne składowe) w wielokrotnym dziedziczeniu.
Klasy klasyczne przeprowadzają wyszukiwanie od głębokości od lewej do prawej. Zatrzymaj się przy pierwszym meczu. Nie mają
__mro__
atrybutu.Klasy w nowym stylu MRO jest bardziej skomplikowane do syntezy w jednym zdaniu w języku angielskim. Jest to szczegółowo wyjaśnione tutaj . Jedną z jego właściwości jest to, że klasa podstawowa jest przeszukiwana dopiero po przeszukaniu wszystkich jej klas pochodnych. Mają
__mro__
atrybut, który pokazuje kolejność wyszukiwania.Obiekty klasy nowego stylu nie mogą zostać podniesione, chyba że pochodzą z
Exception
W środowisku Python 2.5 można było stworzyć wiele klas, a w Pythonie 2.6 zostało to usunięte. W Pythonie 2.7.3:
źródło
Klasy starego stylu są wciąż nieznacznie szybsze w wyszukiwaniu atrybutów. Nie jest to zwykle ważne, ale może być przydatne w wrażliwym na wydajność kodzie Python 2.x:
źródło
%timeit aobj.a
10000000 loops, best of 3: 66.1 ns per loop
%timeit bobj.a
10000000 loops, best of 3: 53.9 ns per loop
Guido napisał „ The Story Story on New-Class Classes” , naprawdę świetny artykuł o nowej i starej klasie w Pythonie.
Python 3 ma tylko klasę w nowym stylu. Nawet jeśli napiszesz „klasę w starym stylu”, jest ona domyślnie wywodzona z
object
.Klasy w nowym stylu mają pewne zaawansowane funkcje, których brakuje w klasach w starym stylu, takie jak
super
nowe mro C3 , niektóre magiczne metody itp.źródło
Oto bardzo praktyczna, prawdziwa / fałszywa różnica. Jedyną różnicą między dwiema wersjami następującego kodu jest to, że w drugiej wersji Person dziedziczy po obiekcie . Poza tym dwie wersje są identyczne, ale z różnymi wynikami:
Zajęcia w starym stylu
Zajęcia w nowym stylu
źródło
_names_cache
to słownik, który buforuje (przechowuje do przyszłego wyszukiwania) każdą przekazywaną nazwęPerson.__new__
. Metoda setdefault (zdefiniowana w dowolnym słowniku) przyjmuje dwa argumenty: klucz i wartość. Jeśli klucz znajduje się w nagraniu, zwróci jego wartość. Jeśli nie ma go w dyktonie, najpierw ustawi wartość przekazaną jako drugi argument, a następnie zwróci.__new__()
zawsze jest wywoływany i zawsze konstruuje nowy obiekt, a następnie go rzuca. W takim przypadkuif
preferowane jest a.setdefault()
.__new__
tak naprawdę nie jest rzeczą dla klas w starym stylu, nie przyzwyczaja się do budowy instancji (to po prostu losowa nazwa, która wygląda wyjątkowo, jak definiowanie__spam__
). Tak więc konstruowanie klasy w starym stylu wywołuje tylko__init__
, podczas gdy konstrukcja w nowym stylu wywołuje__new__
(łączenie się w instancję singletona według nazwy), aby skonstruować i__init__
zainicjować ją.Klasy nowego stylu dziedziczą
object
po Pythonie 2.2 i muszą być zapisane jako takie (tj.class Classname(object):
Zamiastclass Classname:
). Podstawową zmianą jest ujednolicenie typów i klas, a przyjemnym efektem ubocznym jest to, że pozwala ci dziedziczyć po typach wbudowanych.Przeczytaj descrintro po więcej szczegółów.
źródło
Klasy nowego stylu mogą używać
super(Foo, self)
gdzieFoo
jest klasą iself
instancją.W Pythonie 3.x można po prostu używać
super()
wewnątrz klasy bez żadnych parametrów.źródło