2017-03-21 1 views
0

Ich habe die folgende Klasse:Call a Klassenmethode nur einmal

import loader 
import pandas 

class SavTool(pd.DataFrame): 

    def __init__(self, path): 
     pd.DataFrame.__init__(self, data=loader.Loader(path).data) 

    @property 
    def path(self): 
     return path 
    @property 
    def meta_dict(self): 
     return loader.Loader(path).dict 

Wenn die Klasse instanziiert wird die Instanz ein Pandas Dataframe wird, die ich von anderen Attributen wie der Pfad zur Datei und ein Wörterbuch erweitern wollte Metainformationen enthalten ("meta_dict" genannt).

Was ich will, ist das Folgende: das Wörterbuch 'meta_dict' soll veränderbar sein. Das heißt, sollten folgende Arbeiten:

df = SavTool("somepath") 
df.meta_dict["new_key"] = "new_value" 
print df.meta_dict["new_key"] 

Aber was passiert, ist, dass jedes Mal, wenn ich die Syntax ‚df.meta_dict‘ die Methode ‚meta_dict‘ genannt wird und der ursprüngliche ‚meta_dict‘ von loader.Loader solche zurückgegeben Das 'df.meta_dict' kann nicht geändert werden. Daher führt die Syntax zu "KeyError: 'new_key'". 'meta_dict' soll nur einmal und dann nie wieder aufgerufen werden, wenn es eine zweite/dritte ... Zeit benutzt/genannt wird. Die zweite/dritte ... Zeit 'meta_dict' sollte nur ein Attribut sein, in diesem Fall ein Wörterbuch.

Wie kann ich das beheben? Vielleicht ist das ganze Design der Klasse schlecht und sollte geändert werden (ich bin neu in der Verwendung von Klassen)? Danke für deine Antworten!

Antwort

1

Wenn Sie loader.Loader aufrufen, erstellen Sie jedes Mal eine neue Instanz des Wörterbuchs. Die @property Cache nichts für Sie, bietet nur einen Komfort zum Umbruch komplizierte Getter für eine saubere Schnittstelle für den Anrufer.

So etwas sollte funktionieren. Ich aktualisierte auch die path Variable, so dass es korrekt an die Klasse gebunden ist und in der path Eigenschaft korrekt zurückgegeben wurde.

import loader 
import pandas 

class SavTool(pd.DataFrame): 

    def __init__(self, path): 
     pd.DataFrame.__init__(self, data=loader.Loader(path).data) 
     self._path = path 
     self._meta_dict = loader.Loader(path).dict 

    @property 
    def path(self): 
     return self._path 

    @property 
    def meta_dict(self): 
     return self._meta_dict 

    def update_meta_dict(self, **kwargs): 
     self._meta_dict.update(kwargs) 

Eine andere Möglichkeit, nur die Variable Cache wird von hasattr mit:

@property 
def meta_dict(self): 
    if not hasattr(self, "_meta_dict"): 
     self._meta_dict = loader.Loader(path).dict 
    return self._meta_dict 
+0

Dank Ihrer Antwort! Sie haben mir sehr geholfen :). Ich wusste nur nicht, dass es möglich ist, der Instanz einige andere Attribute hinzuzufügen (wenn sie in __init__ inistialisieren), abgesehen von der Inistialisierung des Pandas DataFrame. – John

+0

@John: Gern geschehen. Die Antwort wurde mit einer Verknüpfung "Hack" für das Caching aktualisiert. – sdolan

+0

Eine Sache zu wissen ist, dass, wenn Sie eine Eigenschaft in Ihrem '__init__' hinzufügen, dass die Basisklasse (' DataFrame' in diesem Fall), Sie einige böse Fehler verursachen werden. Pandas ist Open Source, so können Sie immer überprüfen ... Viel Glück, Herr! – sdolan