2015-07-23 11 views
5

Rozważmy następujący kod:Dodaj atrybut do klasy Pythona

class Foo(): 

    pass 


Foo.entries = dict() 


a = Foo() 
a.entries['1'] = 1 

b = Foo() 
b.entries['3'] = 3 

print(a.entries) 

To będzie druk:

{'1': 1, '3': 3} 

dlatego, że wpisy są dodawane jako atrybutu statycznego. Czy istnieje sposób, w jaki małpa łata definicję klasy, aby dodać nowe atrybuty (bez dziedziczenia).

udało mi się znaleźć w następujący sposób, ale wygląda zawiłe do mnie:

def patch_me(target, field, value): 
    def func(self): 
     if not hasattr(self, '__' + field): 
      setattr(self, '__' + field, value()) 
     return getattr(self, '__' + field) 
    setattr(target, field, property(func)) 

patch_me(Foo, 'entries', dict) 
+0

Dodajesz atrybut * class *, który jest wspólny dla wszystkich instancji. Jeśli dodasz go do instancji, czy instancje * już utworzone * uzyskają nowy atrybut? – jonrsharpe

+0

Dlaczego nie możesz zamiast tego użyć 'a.entries = {'1': 1}? – Vincent

Odpowiedz

1

Zwykle atrybuty są dodawane zarówno przez funkcję __init__() lub po uruchamianiu:

foo = Foo() 
foo.bar = 'something' # note case 

Jeśli chcesz wykonaj to automatycznie, dziedziczenie jest jak dotąd najprostszym sposobem:

class Baz(Foo): 
    def __init__(self): 
     super().__init__() # super() needs arguments in 2.x 
     self.bar = 'something' 

Należy zauważyć, że klasy nie muszą pojawiać się na najwyższym poziomie modułu Python. Można zadeklarować klasę wewnątrz funkcji:

def make_baz(value): 
    class Baz(Foo): 
     def __init__(self): 
      super().__init__() # super() needs arguments in 2.x 
      self.bar = value() 
    return Baz() 

Ten przykład utworzyć nową klasę za każdym razem make_baz() jest tzw. To może, ale nie musi być to, czego chcesz. Prawdopodobnie byłoby prościej po prostu to zrobić:

def make_foo(value): 
    result = Foo() 
    result.bar = value() 
    return result 

Jeśli naprawdę ustawione na małpa-łatanie klasę oryginalny, przykładowy kod, który podałeś jest bardziej lub mniej najprostszy sposób to zrobić. Możesz rozważyć użycie składni dekoratora dla property(), ale to drobna zmiana. Powinienem również zauważyć, że będzie to , a nie wywoływać mylenie nazwy podwójnie podkreślonej, co jest prawdopodobnie dobrą rzeczą, ponieważ oznacza to, że nie można konfliktować z żadnymi nazwami używanymi przez samą klasę.

Powiązane problemy