Was ist der Unterschied zwischen alten und neuen Stilklassen in Python?
-
09-06-2019 - |
Frage
Was ist der Unterschied zwischen alten und neuen Stilklassen in Python?Wann sollte ich das eine oder andere verwenden?
Lösung
http: //docs.python .org / 2 / reference / datamodel.html # new-style-und-classic-Klassen :
Bis zu Python 2.1, im alten Stil Klassen der einzige Geschmack für den Benutzer verfügbar waren.
Das Konzept der (alten Stils) Klasse ist mit dem Begriff der Art in keinem Zusammenhang: wenn
x
eine Instanz einer alten Stil-Klasse ist, dannx.__class__
bezeichnet die Klasse vonx
, abertype(x)
ist immer<type 'instance'>
.Dies spiegelt die Tatsache wider, dass alle alten Stil Instanzen unabhängig ihre Klasse wird mit einem einzigen eingebauten Typ implementiert, genannt Beispiel.
New-Style-Klassen wurden in Python 2.2 eingeführt, um die Konzepte der Klasse und Typ zu vereinen. Ein neuer Stil Klasse ist einfach ein benutzerdefinierter Typ, nicht mehr, nicht weniger.
Wenn x eine Instanz eines neuen Stils Klasse ist, dann ist
type(x)
typischerweise die gleichen wiex.__class__
(obwohl dies nicht gewährleistet ist - ein neuer Stil Klasseninstanz darf den Wert außer Kraft zu setzen zurückgegeben fürx.__class__
).Die Hauptmotivation für neuen Stil Klassen einzuführen, ist ein einheitliches Objektmodell mit einem vollständigen Meta-Modell zur Verfügung zu stellen .
Es hat auch eine Reihe von unmittelbaren Vorteilen, wie die Fähigkeit zu Unterklasse die meisten integrierten Typen, oder die Einführung von „Deskriptoren“, die es ermöglichen, berechneten Eigenschaften.
Aus Kompatibilitätsgründen Klassen sind noch im alten Stil standardmäßig .
New-Style-Klassen werden durch die Angabe eine weitere neue Stil-Klasse erstellt (Das heißt eine Art) als eine Elternklasse, oder das „Top-Level-Typ“, wenn kein Objekt andere Elternteil erforderlich.
Das Verhalten der neuen Stils Klassen unterscheidet sich von der im alten Stil Klassen in einer Reihe von wichtigen Details zusätzlich zu welcher Art kehrt zurück.
Einige dieser Veränderungen sind von grundlegender Bedeutung für das neue Objektmodell, wie die Art und Weise spezielle Methoden aufgerufen werden. Andere sind „fixe“ Das konnte nicht bevor für Kompatibilitätsprobleme, wie das Verfahren durchgeführt werden Auflösung, um im Fall von Mehrfachvererbung.
Python 3 hat nur neue Klassen-Stil .
Egal, ob Sie von
object
Unterklasse oder nicht, Klassen sind im neuen Stil in Python 3.
Andere Tipps
Erklärung weise:
New-Style-Klassen erben von Objekt oder von einer anderen neuen Stil-Klasse.
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
Old-Style-Klassen nicht.
class OldStyleClass():
pass
Wichtige Verhaltensänderungen zwischen alten und neuen Stilklassen
- Super hinzugefügt
- MRO geändert (siehe unten)
- Deskriptoren hinzugefügt
- neuen Stil Klasse Objekte können nicht, es sei denn aus
Exception
(Beispiel unten) abgeleitet angehoben werden
-
__slots__
hinzugefügt
MRO (Methode Resolution Order) geändert
Es wurde in anderen Antworten erwähnt, aber hier geht ein konkretes Beispiel für den Unterschied zwischen klassischen MRO und C3 MRO (in neuen Stil Klassen).
Die Frage ist die Reihenfolge, in den Attributen (zu denen auch Methoden und Variablen Mitglied) werden in Mehrfachvererbung gesucht.
Classic Klassen tun, um eine Tiefensuche von links nach rechts. Stopp auf dem ersten Spiel. Sie haben nicht das __mro__
Attribut.
class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 0
assert C21().i == 2
try:
C12.__mro__
except AttributeError:
pass
else:
assert False
New-Style-Klassen MRO komplizierter ist in einem englischen Satz zu synthetisieren. Es wird im Detail hier erklärt. Eine seiner Eigenschaften ist, dass eine Basisklasse wird nur einmal alle seine Abgeleitete Klassen wurden durchsucht. Sie haben das __mro__
Attribut, das die Suchreihenfolge zeigt.
class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 2
assert C21().i == 2
assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)
New Artklasse Objekte können nicht, es sei denn aus Exception
abgeleitet angehoben werden
Um Python 2.5 viele Klassen könnten erhöht werden, um Python 2.6 diese entfernt wurde. Auf Python 2.7.3:
# OK, old:
class Old: pass
try:
raise Old()
except Old:
pass
else:
assert False
# TypeError, new not derived from `Exception`.
class New(object): pass
try:
raise New()
except TypeError:
pass
else:
assert False
# OK, derived from `Exception`.
class New(Exception): pass
try:
raise New()
except New:
pass
else:
assert False
# `'str'` is a new style object, so you can't raise it:
try:
raise 'str'
except TypeError:
pass
else:
assert False
Old Style-Klassen sind noch geringfügig schneller für Attribut-Lookup. Dies ist in der Regel nicht wichtig, kann aber sinnvoll sein, in der Leistung empfindliche Python 2.x Code:
In [3]: class A: ...: def __init__(self): ...: self.a = 'hi there' ...: In [4]: class B(object): ...: def __init__(self): ...: self.a = 'hi there' ...: In [6]: aobj = A() In [7]: bobj = B() In [8]: %timeit aobj.a 10000000 loops, best of 3: 78.7 ns per loop In [10]: %timeit bobj.a 10000000 loops, best of 3: 86.9 ns per loop
Guido hat geschrieben The Inside Story auf New-Style-Klassen , ein wirklich großer Artikel über neuen Stil und im alten Stil Klasse in Python.
Python 3 hat nur neue Stil-Klasse, auch wenn Sie eine ‚alten Stil Klasse‘ zu schreiben, es implizit aus object
abgeleitet wird.
New-Style-Klassen haben einige erweiterte Funktionen fehlen in alten Stil Klassen wie super
und dem neuen C3 MRO einige magische Methoden, etc.
Hier ist ein sehr praktisch, True / False Unterschied. Der einzige Unterschied zwischen den beiden Versionen des folgenden Codes ist, dass in der zweiten Version Person von Objekt erbt. Anders als dass die beiden Versionen identisch sind, aber mit unterschiedlichen Ergebnissen:
1) im alten Stil Klassen
class Person():
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2
>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>
2) new-Style-Klassen
class Person(object):
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2
>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>
New-Style-Klassen von object
erben und müssen 2.2 ab als solche in Python geschrieben werden (das heißt class Classname(object):
statt class Classname:
). Der Kern Änderung Typen und Klassen zu vereinen, und der nette Nebeneffekt ist, dass es Sie von integrierten Typen erben kann.
Lesen Sie descrintro für weitere Details.
New Style-Klassen verwenden super(Foo, self)
wo Foo
ist eine Klasse und self
ist die Instanz.
super(type[, object-or-type])
Gibt ein Proxy-Objekt, dass die Delegierten Methodenaufrufe an einen Elternteil oder Geschwister Klasse des Typs. Dies ist nützlich für geerbte Methoden zugreifen, die in einer Klasse überschrieben wurden. Die Suchreihenfolge ist die gleiche wie die von getattr () verwendet, außer dass der Typ selbst übersprungen wird.
Und in Python 3.x können Sie einfach super()
innerhalb einer Klasse ohne Parameter verwenden.
Oder besser gesagt, Sie sollten immer neuen Stil-Klassen verwenden, es sei denn, Sie Code haben, mit Versionen von Python arbeiten muss älter als 2.2.