Neue Version:
ich mit der vorherige Antwort ein wenig enttäuscht war, damit ich es ein wenig neu zu schreiben entschieden:
Zuerst hat einen Blick auf the source code of DynamicClassAttribute
und Sie werden wahrscheinlich feststellen, dass es sehr aussieht ähnlich wie der normale property
. Mit Ausnahme der __get__
-Methode:
def __get__(self, instance, ownerclass=None):
if instance is None:
# Here is the difference, the normal property just does: return self
if self.__isabstractmethod__:
return self
raise AttributeError()
elif self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(instance)
Also, was das bedeutet, ist, dass wenn Sie ein DynamicClassAttribute
zugreifen möchten (also nicht abstrakt ist) auf die Klasse wirft er einen AttributeError
statt self
zurückzukehren. Für Instanzen if instance:
wertet True
aus und die ist identisch mit property.__get__
.
Für normale Klassen, die in ein löst nur sichtbarAttributeError
beim Aufruf des Attribut:
from types import DynamicClassAttribute
class Fun():
@DynamicClassAttribute
def has_fun(self):
return False
Fun.has_fun
Attribute - Traceback (jüngste Aufforderung zuletzt)
, dass nicht für sich selbst ist sehr hilfreich, bis Sie sich die Prozedur "Class attribute lookup" anschauen wenn mit metaclass
es (I fand ein schönes Bild davon in this blog). Weil für den Fall, dass ein Attribut eine löst und diese Klasse hat eine Metaklasse Python sieht die metaclass.__getattr__
Methode und sieht, ob das das Attribut auflösen kann.Um dies mit einem minimalen Beispiel zu illustrieren:
Und hier kommt der "dynamische" Teil. Wenn Sie die dynprop
auf der Klasse aufrufen wird es in der Meta-Suche und zurück die Meta dynprop
:
Fun.dynprop
die druckt:
search in meta
'Meta'
So aufgerufen wir die metaclass.__getattr__
und kehrte das ursprüngliche Attribut (das war definiert mit dem gleichen Namen wie die neue Eigenschaft).
Während Instanzen für die dynprop
des Fun
-instance zurückgegeben:
Fun('Not-Meta').dynprop
wir das überschriebene Attribut erhalten:
'Not-Meta'
aus Meine Schlussfolgerung ist, dass DynamicClassAttribute
wichtig ist, wenn Sie wollen Damit Unterklassen ein Attribut mit dem gleichen Namen erhalten, das in der Metaklasse verwendet wird. Sie werden es bei Instanzen spiegeln, aber es ist immer noch zugänglich, wenn Sie es für die Klasse aufrufen.
Ich ging in das Verhalten von Enum
in der alten Version, so ließ ich es hier in:
alten Version
Die DynamicClassAttribute
ist nur nützlich (ich bin nicht wirklich sicher, in diesem Punkt), wenn Sie vermuten, dass Namenskonflikte zwischen einem für eine Unterklasse festgelegten Attribut und einer Eigenschaft für die Basisklasse auftreten können.
Sie werden zumindest einige Grundlagen über metaclasses müssen wissen, denn dies ist nicht ohne metaclasses (eine schöne Erklärung, wie Klassenattribute genannt werden, können in this blog post gefunden werden) arbeiten, da das Attribut Lookup ist leicht verschiedene mit Metaklassen.
Angenommen, Sie haben:
class Funny(type):
dynprop = 'Very important meta attribute, do not override'
class Fun(metaclass=Funny):
def __init__(self, value):
self._stub = value
@property
def dynprop(self):
return 'Haha, overridden it with {}'.format(self._stub)
und dann rufen:
Fun.dynprop
Immobilie 0x1b3d9fd19a8
und auf der Instanz erhalten wir:
Fun(2).dynprop
'Haha, es mit 2 außer Kraft gesetzt'
schlecht ... es verloren gegangen ist. Aber warten wir können die metaclass
spezielle Lookup verwenden: Lassen Sie uns ein __getattr__
implementieren (Fallback) und implementieren Sie die dynprop
als DynamicClassAttribute
.Denn nach ihm documentation ist das ist ihr Zweck - zum __getattr__
zu Rückfall, wenn es auf die Klasse genannt:
from types import DynamicClassAttribute
class Funny(type):
def __getattr__(self, value):
print('search in meta')
return Funny.dynprop
dynprop = 'Meta'
class Fun(metaclass=Funny):
def __init__(self, value):
self._dynprop = value
@DynamicClassAttribute
def dynprop(self):
return self._dynprop
jetzt greifen wir auf die Klasse-Attribut:
Fun.dynprop
die druckt:
search in meta
'Meta'
So haben wir die metaclass.__getattr__
aufgerufen und das ursprüngliche Attribut (das mit dem gleichen Namen wie die neue Eigenschaft definiert wurde) zurückgegeben.
Und für Instanzen:
Fun('Not-Meta').dynprop
erhalten wir das überschriebene Attribut:
'Not-Meta'
Nun, das ist nicht so schlimm bedenkt, dass wir metaclasses zu vorher definierten aber überschriebenen Attribute verwenden, ohne eine Instanz umleiten kann. Dieses Beispiel ist das Gegenteil, der mit Enum
gemacht wird, in dem Sie Attribute der Unterklasse definieren:
from enum import Enum
class Fun(Enum):
name = 'me'
age = 28
hair = 'brown'
und diese danach definiert Attribute standardmäßig zugreifen möchten.
Fun.name
# <Fun.name: 'me'>
aber Sie wollen auch die name
Attribut Zugriff ermöglichen, die als DynamicClassAttribute
definiert wurde (die zurückgibt, welcher Name die Variable tatsächlich):
Fun('me').name
# 'name'
weil sonst wie konnten Sie Zugriff auf den Namen 28
?
Fun.hair.age
# <Fun.age: 28>
# BUT:
Fun.hair.name
# returns 'hair'
Den Unterschied sehen? Warum gibt der zweite nicht <Fun.name: 'me'>
zurück? Das ist wegen dieser Verwendung von DynamicClassAttribute
. Sie können also die ursprüngliche Eigenschaft überschreiben, aber später wieder freigeben. Dieses Verhalten ist das Gegenteil meines Beispiels und erfordert mindestens die Verwendung von __new__
und __prepare__
. Aber dafür müssen Sie wissen, wie das genau funktioniert und in vielen Blogs und Stackoverflow-Antworten erklärt wird, die es viel besser erklären können, als ich kann, also werde ich es überspringen, in so viel Tiefe zu gehen (und ich bin mir nicht sicher, ob Ich könnte es in kurzer Zeit lösen).
tatsächliche Anwendungsfälle könnten spärlich, aber bestimmten Zeitpunkt eine von einigen propably denken kann ...
Sehr schöne Diskussion über die Dokumentation von DynamicClassAttribute
: "we added it because we needed it"