Próbuję zrobić:
award_dict = {
"url" : "http://facebook.com",
"imageurl" : "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png",
"count" : 1,
}
def award(name, count, points, desc_string, my_size, parent) :
if my_size > count :
a = {
"name" : name,
"description" : desc_string % count,
"points" : points,
"parent_award" : parent,
}
a.update(award_dict)
return self.add_award(a, siteAlias, alias).award
Ale jeśli czułbym się naprawdę niewygodny w tej funkcji, a wolałbym zrobić:
return self.add_award({
"name" : name,
"description" : desc_string % count,
"points" : points,
"parent_award" : parent,
}.update(award_dict), siteAlias, alias).award
Dlaczego aktualizacja nie zwraca obiektu, aby można było połączyć?
JQuery robi to w celu tworzenia łańcuchów. Dlaczego nie jest to dopuszczalne w Pythonie?
python
dictionary
language-design
language-features
Paul Tarjan
źródło
źródło
newdict = dict(dict001, **dict002)
Odpowiedzi:
Python w większości implementuje pragmatycznie zabarwioną odmianę separacji poleceń i zapytań : mutatory zwracają
None
(z pragmatycznie indukowanymi wyjątkami, takimi jakpop
;-), więc nie można ich pomylić z akcesoriami (i podobnie przypisanie nie jest wyrażeniem, instrukcja - istnieje separacja wyrażeń i tak dalej).Nie oznacza to, że nie ma wielu sposobów na scalenie rzeczy, gdy naprawdę chcesz, np.
dict(a, **award_dict)
Tworzy nowy dykt, podobny do tego, który wydaje się, że chcesz, aby został.update
zwrócony - więc dlaczego nie użyć TEGO, jeśli naprawdę uważasz, że to ważne ?Edycja : przy okazji, nie ma potrzeby, w twoim konkretnym przypadku, tworzyć
a
po drodze, albo:tworzy pojedynczy dykt z dokładnie taką samą semantyką jak twoja
a.update(award_dict)
(włączając, w przypadku konfliktów, fakt, że wpisy waward_dict
nadpisują te, które podajesz jawnie; aby uzyskać inną semantykę, tj. aby mieć wyraźne wpisy "wygrywające" takie konflikty, przejśćaward_dict
jako jedyny argument pozycyjny , przed słowami kluczowymi jedynkami i pozbawiony**
postaci -dict(award_dict, name=name
itd. itd.).źródło
a
całkowicie uniknąć tworzenia , przy okazjiTypeError
dict(old_dict, old_key=new_value)
nie wyrzuci wielu wartości słowa kluczowego i nie zwróci nowego dict.API Pythona, zgodnie z konwencją, rozróżnia procedury i funkcje. Funkcje obliczają nowe wartości na podstawie swoich parametrów (w tym dowolnego obiektu docelowego); procedury modyfikują obiekty i niczego nie zwracają (tj. zwracają None). Zatem procedury mają skutki uboczne, a funkcje nie. aktualizacja jest procedurą, dlatego nie zwraca wartości.
Motywacją do zrobienia tego w ten sposób jest to, że w przeciwnym razie mogą wystąpić niepożądane skutki uboczne. Rozważać
Jeśli reverse (które odwraca listę w miejscu) również zwróci listę, użytkownicy mogą pomyśleć, że reverse zwraca nową listę, która zostanie przypisana do bar, i nigdy nie zauważą, że foo również zostanie zmodyfikowane. Dokonując odwrócenia zwrotu Brak, natychmiast rozpoznają, że słupek nie jest wynikiem odwrócenia i przyjrzą się dokładniej efektowi odwrócenia.
źródło
reverse(foo)
czuje się dziwnie.bar=foo[:]
), a następnie przywróć kopię.bar = foo.reverse()
, można pomyśleć, żefoo
nie jest modyfikowany. Aby uniknąć nieporozumień, masz zarównofoo.reverse()
ibar = reversed(foo)
.Jest to proste, ponieważ:
źródło
Zauważ, że oprócz zwrócenia scalonego dyktu, modyfikuje on lokalnie pierwszy parametr. Więc dict_merge (a, b) zmodyfikuje plik.
Lub, oczywiście, możesz to wszystko zrobić w tekście:
źródło
lambda
nie powinny być wykorzystywane w ten sposób, zamiast wykorzystania funkcji konwencjonalnegodef
zamiasta.update(b) or a
nie ma wystarczającej reputacji, by zostawić komentarz przy górnej odpowiedzi
@beardc to nie wygląda na rzecz CPythona. PyPy wyświetla „TypeError: słowa kluczowe muszą być ciągami”
Rozwiązanie
**kwargs
tylko działa, ponieważ słownik, który ma zostać scalony, zawiera tylko klucze typu string .to znaczy
vs
źródło
Nie chodzi o to, że jest to niedopuszczalne, ale raczej, że
dicts
nie zostały wdrożone w ten sposób.Jeśli spojrzysz na ORM Django, szeroko wykorzystuje on łańcuchy. Nie jest to zniechęcające, możesz nawet odziedziczyć
dict
i tylko zastąpićupdate
aktualizację ireturn self
, jeśli naprawdę tego chcesz.źródło
tak blisko proponowanego rozwiązania, jak tylko mogłem
źródło
Dla tych, którzy spóźnili się na imprezę, przygotowałem trochę czasu (Py 3.7), pokazując to
.update()
metody bazujące wyglądają nieco (~ 5%) szybciej, gdy dane wejściowe są zachowane i zauważalnie (~ 30%) szybciej, gdy tylko aktualizują się na miejscu .Jak zwykle do wszystkich benchmarków należy podchodzić z przymrużeniem oka.
Czasy operacji w miejscu są nieco trudniejsze, więc należałoby je zmodyfikować w ramach dodatkowej operacji kopiowania (pierwszy czas jest tylko w celach informacyjnych):
źródło
źródło
Właśnie próbowałem tego sam w Pythonie 3.4 (więc nie mogłem użyć fantazyjnego
{**dict_1, **dict_2}
składni).Chciałem mieć klucze niebędące ciągami znaków w słownikach, a także udostępniać dowolną liczbę słowników.
Chciałem też stworzyć nowy słownik, więc zdecydowałem się go nie używać
collections.ChainMap
(taki powód, dla którego początkowo nie chciałem używaćdict.update
.Oto, co napisałem:
źródło