2009-08-06 12 views
5

Rozważmy następujące klasy:Controlling getter i setter dla klasy A Pythona

class Token: 
    def __init__(self): 
     self.d_dict = {} 

    def __setattr__(self, s_name, value): 
     self.d_dict[s_name] = value 

    def __getattr__(self, s_name): 
     if s_name in self.d_dict.keys(): 
      return self.d_dict[s_name] 
     else: 
      raise AttributeError('No attribute {0} found !'.format(s_name)) 

W moim kodu Reklamowe mieć jakąś inną funkcję (jak get_all() zwracają wich d_dict, ma (s_name), który mi powiedzieć, czy mój żeton ma określony atrybut).

W każdym razie myślę, że jest to usterka w moim planie, ponieważ to nie działa: kiedy tworzę nowe wystąpienie, python próbuje zadzwonić pod numer __setattr__('d_dict', '{}').

W jaki sposób mogę osiągnąć podobne zachowanie (być może w bardziej pythonic?) Bez konieczności pisania czegoś takiego jak Token.set (nazwa, wartość) i otrzymania (nazwa) każdego, który chcę ustawić lub uzyskać atrybut dla znak.

Krytycy o projektowaniu wada i/lub głupoty mile widziane :)

podziękowaniem!

Odpowiedz

3

Potrzebujesz specjalnego d_ dicta.

Chociaż w powyższym kodzie, wszystko, co robisz, jest replikacją tego, co dowolny obiekt robi już z __dict__, więc jest to całkiem bezcelowe. Czy zgaduję poprawnie, jeśli chciałeś, aby specjalne przypadki miały pewne atrybuty i faktycznie używały dla nich metod?

W takim przypadku można użyć właściwości.

class C(object): 
    def __init__(self): 
     self._x = None 

    @property 
    def x(self): 
     """I'm the 'x' property.""" 
     return self._x 

    @x.setter 
    def x(self, value): 
     self._x = value 

    @x.deleter 
    def x(self): 
     del self._x 
1

Rozwiązanie, nie bardzo pytoniczne, ale działa. Jak wskazał Lennart Regebro, musisz użyć specjalnego przypadku dla d_dict.

class Token(object): 

    def __init__(self): 
     super(Token,self).__setattr__('d_dict', {}) 

    def __getattr__(self,name): 
     return self.a[name] 

    def __setattr__(self,name,value): 
     self.a[name] = value 

Musisz użyć nowych klas stylu.

1

Warto pamiętać, że __getattr__ jest wywoływane tylko wtedy, gdy atrybut nie istnieje w obiekcie, podczas gdy __setattr__ jest zawsze wywoływany.

3

Specjalny-obudowa __dict__ działa tak:

def __init__(self): 
    self.__dict__['d_dict'] = {} 

Nie ma potrzeby, aby użyć klasy w nowym stylu do tego.

+0

Myślę, że to zrobię :) W każdym razie używam Python 3.1, więc wszystkie moje klasy są w nowej klasie. – thomas

2

problem wydaje się być w czasie oceny kodu w metodzie __init__. Można zdefiniować metodę __new__ i zainicjować zmienną d_dict zamiast __init__. To trochę hackish, ale działa, pamiętaj jednak, aby go skomentować, ponieważ po kilku miesiącach będzie to całkowita magia.

>>> class Foo(object): 
...  def __new__(cls, *args): 
...    my_cls = super(Foo, cls).__new__(cls, *args) 
...    my_cls.d_dict = {} 
...    return my_cls 

>>> f = Foo() 
>>> id(f.d_dict) 
3077948796L 
>>> d = Foo() 
>>> id(d.d_dict) 
3078142804L 

słowa wyjaśnienia, dlaczego uważam, że hackish: zadzwoń do __new__ zwraca jej nową instancję klasy więc wtedy d_dict zainicjowane tam niby statycznej, ale to zainicjowane z nowej instancji słowniku każdego klasa czasu to "utworzona", więc wszystko działa tak, jak potrzebujesz.

0

Myślę, że będziemy mogli powiedzieć coś o ogólnym projekcie twojej klasy, jeśli wyjaśnisz jej cel.Na przykład,

# This is a class that serves as a dictionary but also has user-defined methods 
class mydict(dict): pass 

# This is a class that allows setting x.attr = value or getting x.attr: 
class mysetget: pass 

# This is a class that allows setting x.attr = value or getting x.attr: 
class mygetsethas: 
    def has(self, key): 
     return key in self.__dict__ 

x = mygetsethas() 
x.a = 5 
print(x.has('a'), x.a) 

myślę ostatnia klasa jest najbardziej zbliżony do tego, co masz na myśli, a ja też lubię grać ze składnią i uzyskać wiele radości z niego, ale niestety nie jest to dobra rzecz. Powody, dla których nie zaleca się używania atrybutów obiektu do ponownego wdrożenia słownika: nie można używać x.3, nie kolidujesz z x.has(), musisz umieścić cytaty w has('a') i wiele innych.

+0

Moim celem jest dostarczenie kontenera, który pozwoli mi nadać mu dowolny dowolny atrybut (nie wiem z góry, ilu ani jak się nazywa), np .: myClassInstance.name1 = wartość1 myClassInstance.name2 = wartość2 Z odpowiednią zadzwoń, chcę pobrać słownik, który będzie zawierał nazwę i wartość moich atrybutów w następującej postaci: {'name1': wartość1, 'nazwa2': wartość2} wartośćX może być dowolnym typem pythona lub niestandardowego. – thomas

+0

W takim razie najlepsze jest drugie, 'class mysetget: pass'. Będziesz mógł ustawić atrybuty, a następnie pobrać je z "x .__ dict__". –

Powiązane problemy