2017-06-27 3 views
1

Ich versuche, von einer Klasse zu kopieren Klasse in eine andere AttributeSo kopieren Klassenattribute ohne Instanziierung

d = {1:'one', 2:'two'} 
class X(object): 
    a = 1 
    b = 2 

Ich brauche Klasse Y zu definieren, so dass die folgenden Bedingungen erfüllt ist: assert Y.a =='one' and Y.b=='two'

Ein Weg, um dies zu erreichen ist wie folgt:

attrDict = {attr:d[getattr(X,attr)] for attr in dir(X) if isinstance(getattr(X,attr), int)} 
# attrDict is {'a':'one', 'b':'two'} 

class Y(X): 
    def __init__(self): 
     self.copyOver() 

    @classmethod 
    def copyOver(klass): 
     [setattr(klass, k,v) for k,v in attrDict.iteritems()] 

y = Y() # Y.a = 1 unless this runs 
assert Y.a == 'one' and Y.b == 'two' 

jedoch Instanziierung in einer realen Anwendung kann teuer sein: Wäre es möglich, aCH ieve das ohne?

Mit anderen Worten, was built-in verwende ich Klasse ohne Instanziierung eines Objekts davon erforderlich aktualisieren Attribute?

class Y(X): 
    #TODO: setattr all key value pairs in attrDict on the class Y, not on instances of it. 
    #TODO: Do it without requiring to instantiate an object of class Y 
+2

Bitte nicht missbrauchen Listenkomprehensionen für Nebenwirkungen = (Wie auch immer, können Sie einfach anrufen 'Y.copyOver()' direkt nach der Definition von 'Y' statt es in '__init__' Or. Dies ist sogar eine völlig separate Funktion, da es keine Klassenmethode sein muss: 'copy_over (Y, attrDict)' – Ryan

+0

@Ryan, Sure - Listenverständnis, das nur dazu dient, eine Lösung zu demonstrieren, ich stimme mit 'Y.copyOver (Aber wie stelle ich sicher, dass jeder, der Y benutzt, Y.copyOver() ausführt? – Spade

+0

Sie können dafür Metaklassen verwenden, da sie vererbt werden, aber was Sie wirklich damit erreichen wollen ? Was für ein Gesamtbild? – Ryan

Antwort

1

ähnlich, was Sie haben, aber ohne in das Wörterbuch zu schaffen zwischen:

In [120]: d = {1:'one', 2:'two'} 
    ...: class X(object): 
    ...:  a = 1 
    ...:  b = 2 
    ...: 

In [121]: class Y(X): 
    ...:  @classmethod 
    ...:  def change_me(cls): 
    ...:   for k, v in X.__dict__.items(): 
    ...:    if v in d: 
    ...:     setattr(cls, k, d[v]) 
    ...: 

In [122]: Y.a 
Out[122]: 1 

In [123]: Y.change_me() 

In [124]: Y.a 
Out[124]: 'one' 

In [125]: X.a 
Out[125]: 1 

Hier ist eine Version mit metaclasses, die Adressen Ihr Anliegen mit, die explizit einen Class laufen (unter der Annahme python3):

In [145]: d = {1:'one', 2:'two'} 
    ...: class X(object): 
    ...:  a = 1 
    ...:  b = 2 
    ...: 
    ...: 

In [146]: class ChangeOnCreation(type): 
    ...:  def __init__(cls, name, bases, attr_dict): 
    ...:   super().__init__(name, bases, attr_dict) 
    ...:   for subs in bases: 
    ...:    for k, v in subs.__dict__.items(): 
    ...:     if v in d: 
    ...:      setattr(cls, k, d[v]) 
    ...: 

In [147]: class Y(X, metaclass=ChangeOnCreation): 
    ...:  pass 
    ...: 

In [148]: Y.a 
Out[148]: 'one' 

In [149]: X.a 
Out[149]: 1 
+0

Danke, dass Sie sich die Zeit genommen haben, dies zu veröffentlichen. Eine ähnliche Lösung wurde bereits in einem Kommentar von @Ryan erwähnt. Die Anforderung besteht jedoch darin, jeden und jeden, der auf Ya oder Yb zugreift, zu zwingen, ihn transparent auszuführen und nicht nur innerhalb des Moduls, in dem er sich befindet. Kann nicht alle Anwendungsfälle von Ya erzwingen, um Y.change_me() auszuführen. 'vor der Verwendung. – Spade

+0

@Spade siehe Bearbeiten mit Metaklassen. – salparadise

+0

Ausgezeichnet. Das funktioniert und ich kann keine Nebenwirkungen sehen. Als Antwort akzeptiert. – Spade

0

Was hält Sie von der Zuweisung die Werte direkt auf Ihrem Typ (Klasse)? zB:

class X(object): 
    a = 1 
    b = 2 

d = {1: 'one', 2: 'two'} 

class Y(X): pass 

for k in dir(Y): 
    val = getattr(Y, k) 
    try: 
     if val in d: 
      setattr(Y, k, d[val]) 
    except TypeError: 
     pass # ignore the types that cannot be in our `d` 

assert Y.a == "one" and Y.b == "two" 
Verwandte Themen