Załóżmy, że mam klasę z konstruktorem (lub inną funkcją), która przyjmuje zmienną liczbę argumentów, a następnie warunkowo ustawia je jako atrybuty klasy.
Mógłbym ustawić je ręcznie, ale wydaje się, że parametry zmiennych są na tyle powszechne w Pythonie, że powinien istnieć wspólny idiom do tego. Ale nie jestem pewien, jak to zrobić dynamicznie.
Mam przykład używający eval, ale to raczej nie jest bezpieczne. Chcę wiedzieć, jak to zrobić - może z lambdą?
class Foo:
def setAllManually(self, a=None, b=None, c=None):
if a!=None:
self.a = a
if b!=None:
self.b = b
if c!=None:
self.c = c
def setAllWithEval(self, **kwargs):
for key in **kwargs:
if kwargs[param] != None
eval("self." + key + "=" + kwargs[param])
pip install attrs
udekoruj swoją klasę@attr.s
i ustaw argumenty naa = attr.ib(); b = attr.ib()
itp. Przeczytaj więcej tutaj .Odpowiedzi:
Możesz zaktualizować
__dict__
atrybut (który reprezentuje atrybuty klasy w postaci słownika) za pomocą argumentów słów kluczowych:wtedy możesz:
i coś takiego:
możesz wcześniej przefiltrować klucze (użyj
iteritems
zamiast,items
jeśli nadal używasz Pythona 2.x).źródło
self.__dict__.update(locals())
do kopiowania również argumentów pozycyjnych.kwargs[0]
zamiast po prostukwargs
? Czykwargs
może mieć nawet klucz całkowity? Jestem prawie pewien, że muszą to być struny.Możesz skorzystać z
setattr()
metody:Istnieje analogiczna
getattr()
metoda pobierania atrybutów.źródło
.getattr()
? Czy możesz uzyskać dostęp do atrybutów za pomocąFoo.key
?Foo.attrname
. Myślę, że po prostu wskazałem na fakt, żegetattr
metoda istnieje. Jest to również przydatne, jeśli chcesz podać domyślną wartość, gdy nazwany atrybut jest niedostępny.Większość odpowiedzi tutaj nie obejmuje dobrego sposobu inicjowania wszystkich dozwolonych atrybutów tylko do jednej wartości domyślnej. Tak więc, aby dodać do odpowiedzi udzielonych przez @fqxp i @mmj :
źródło
False
. Słuszna uwaga!Proponuję odmianę odpowiedzi fqxp , która oprócz dozwolonych atrybutów pozwala ustawić domyślne wartości atrybutów:
To jest kod Python 3.x, dla Pythona 2.x potrzebujesz przynajmniej jednej korekty
iteritems()
zamiastitems()
.źródło
Kolejny wariant oparty na doskonałych odpowiedziach mmj i fqxp . A jeśli zechcemy
Przez „bezpośrednio” mam na myśli unikanie zbędnego
default_attributes
słownika.Nie jest to duży przełom, ale może komuś się przyda ...
EDYCJA: Jeśli nasza klasa używa
@property
dekoratorów do hermetyzacji „chronionych” atrybutów za pomocą metod pobierających i ustawiających, a jeśli chcemy mieć możliwość ustawiania tych właściwości za pomocą naszego konstruktora, możemy chcieć rozszerzyćallowed_keys
listę o wartości oddir(self)
w następujący sposób:Powyższy kod wyklucza
dir()
(wykluczenie na podstawie obecności „__”) idir()
której nazwa nie znajduje się na końcu nazwy atrybutu (chronionej lub innej) od__dict__.keys()
, w ten sposób prawdopodobnie zachowują tylko metody z dekoracją @właściwość.Ta edycja jest prawdopodobnie poprawna tylko dla Pythona 3 i nowszych.
źródło
Nazwałem tę klasę,
SymbolDict
ponieważ w istocie jest to słownik, który używa symboli zamiast łańcuchów. Innymi słowy, robiszx.foo
zamiast,x['foo']
ale pod kołdrą dzieje się tak samo.źródło
Następujące rozwiązania
vars(self).update(kwargs)
lubself.__dict__.update(**kwargs)
nie są niezawodne, ponieważ użytkownik może wejść do dowolnego słownika bez komunikatów o błędach. Jeśli muszę sprawdzić, czy użytkownik wstawił następujący podpis („a1”, „a2”, „a3”, „a4”, „a5”) rozwiązanie nie działa. Ponadto użytkownik powinien mieć możliwość korzystania z obiektu, przekazując „parametry pozycyjne” lub „parametry par wartości kay”.Proponuję więc następujące rozwiązanie przy użyciu metaklasy.
źródło
To może być lepsze rozwiązanie, ale przychodzi mi na myśl:
źródło
ten jest najłatwiejszy przez Larsks
mój przykład:
źródło
kwargs
jest słownikiem argumentów słów kluczowych iitems()
jest metodą zwracającą kopię listy(key, value)
par ze słownika .Podejrzewam, że w większości przypadków lepiej byłoby użyć nazwanych argumentów (dla lepszego samodokumentującego kodu), więc może to wyglądać mniej więcej tak:
źródło
for key, value in (a, b, c)