Saya mencoba melakukan:
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
Tetapi jika dirasa sangat merepotkan dalam fungsinya, dan saya lebih suka melakukannya:
return self.add_award({
"name" : name,
"description" : desc_string % count,
"points" : points,
"parent_award" : parent,
}.update(award_dict), siteAlias, alias).award
Mengapa tidak memperbarui mengembalikan objek sehingga Anda dapat merantai?
JQuery melakukan ini untuk melakukan perangkaian. Mengapa itu tidak dapat diterima di python?
python
dictionary
language-design
language-features
Paul Tarjan
sumber
sumber
newdict = dict(dict001, **dict002)
Jawaban:
Python sebagian besar menerapkan rasa pemisahan perintah-kueri yang diwarnai secara pragmatis : mutators return
None
(dengan pengecualian yang diinduksi secara pragmatis sepertipop
;-) sehingga mereka tidak mungkin bingung dengan pengakses (dan dalam nada yang sama, tugas bukanlah ekspresi, pernyataan -pisah ekspresi itu ada, dan sebagainya).Itu tidak berarti tidak banyak cara untuk menggabungkan berbagai hal ketika Anda benar-benar menginginkannya, misalnya,
dict(a, **award_dict)
membuat dikt baru seperti yang Anda tampaknya ingin.update
kembalikan - jadi mengapa tidak menggunakan ITU jika Anda merasa itu penting ?Sunting : btw, tidak perlu, dalam kasus khusus Anda, untuk membuat
a
sepanjang jalan, baik:membuat dikt tunggal dengan semantik yang sama persis dengan Anda
a.update(award_dict)
(termasuk, jika terjadi konflik, fakta bahwa entri dalamaward_dict
menimpa entri yang Anda berikan secara eksplisit; untuk mendapatkan semantik lain, yaitu, memiliki entri eksplisit yang "memenangkan" konflik tersebut, lulusaward_dict
sebagai satu-satunya argumen posisi , sebelum kata kunci, dan kehilangan**
bentuk -dict(award_dict, name=name
dll).sumber
a
sama sekali, btw,TypeError
dict(old_dict, old_key=new_value)
tidak akan membuang beberapa nilai untuk kata kunci dan mengembalikan dikt baru.API Python, berdasarkan konvensi, membedakan antara prosedur dan fungsi. Fungsi menghitung nilai baru dari parameternya (termasuk objek target); prosedur memodifikasi objek dan tidak mengembalikan apa pun (yaitu mengembalikan None). Jadi prosedur memiliki efek samping, fungsi tidak. update adalah sebuah prosedur, oleh karena itu ia tidak mengembalikan nilai.
Motivasi untuk melakukannya dengan cara itu adalah bahwa jika tidak, Anda mungkin mendapatkan efek samping yang tidak diinginkan. Mempertimbangkan
Jika reverse (yang membalikkan daftar di tempat) juga akan mengembalikan daftar, pengguna mungkin berpikir bahwa reverse mengembalikan daftar baru yang ditugaskan ke bar, dan tidak pernah memperhatikan bahwa foo juga akan diubah. Dengan melakukan reverse return None, mereka segera mengenali bahwa bar bukanlah hasil pembalikan, dan akan melihat lebih dekat apa efek dari kebalikannya.
sumber
reverse(foo)
terasa aneh.bar=foo[:]
), lalu kembalikan salinannya.bar = foo.reverse()
, Anda bisa berpikir itufoo
tidak diubah. Untuk menghindari kebingungan, Anda memilikifoo.reverse()
danbar = reversed(foo)
.Ini semudah:
(lambda d: d.update(dict2) or d)(d1)
sumber
>>> dict_merge = lambda a,b: a.update(b) or a >>> dict_merge({'a':1, 'b':3},{'c':5}) {'a': 1, 'c': 5, 'b': 3}
Perhatikan bahwa selain mengembalikan dikt yang digabungkan, itu mengubah parameter pertama di tempat. Jadi dict_merge (a, b) akan mengubah file.
Atau, tentu saja, Anda dapat melakukan semuanya secara inline:
>>> (lambda a,b: a.update(b) or a)({'a':1, 'b':3},{'c':5}) {'a': 1, 'c': 5, 'b': 3}
sumber
lambda
tidak boleh digunakan seperti itu, sebagai gantinya gunakan fungsi konvensionaldef
sebagai gantinyaa.update(b) or a
reputasi tidak cukup untuk komentar tersisa di jawaban atas
@beardc ini sepertinya bukan hal CPython. PyPy memberi saya "TypeError: kata kunci harus berupa string"
Solusi dengan
**kwargs
hanya berfungsi karena kamus yang akan digabungkan hanya memiliki kunci bertipe string .yaitu
>>> dict({1:2}, **{3:4}) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: keyword arguments must be strings
vs.
>>> dict({1:2}, **{'3':4}) {1: 2, '3': 4}
sumber
Bukannya itu tidak dapat diterima, melainkan itu
dicts
tidak diterapkan seperti itu.Jika Anda melihat ORM Django, ini membuat penggunaan rangkaian secara ekstensif. Ini tidak berkecil hati, Anda bahkan dapat mewarisi dari
dict
dan hanya menimpaupdate
untuk melakukan pembaruan danreturn self
, jika Anda benar-benar menginginkannya.class myDict(dict): def update(self, *args): dict.update(self, *args) return self
sumber
sedekat mungkin dengan solusi yang Anda usulkan
from collections import ChainMap return self.add_award(ChainMap(award_dict, { "name" : name, "description" : desc_string % count, "points" : points, "parent_award" : parent, }), siteAlias, alias).award
sumber
import itertools dict_merge = lambda *args: dict(itertools.chain(*[d.iteritems() for d in args]))
sumber
Bagi mereka yang datang terlambat ke pesta, saya telah menyusun beberapa waktu bersama (Py 3.7), menunjukkan bahwa
.update()
metode berbasis terlihat sedikit (~ 5%) lebih cepat ketika input disimpan dan terasa (~ 30%) lebih cepat ketika hanya memperbarui di tempat .Seperti biasa, semua tolok ukur harus diambil dengan sebutir garam.
def join2(dict1, dict2, inplace=False): result = dict1 if inplace else dict1.copy() result.update(dict2) return result def join(*items): iter_items = iter(items) result = next(iter_items).copy() for item in iter_items: result.update(item) return result def update_or(dict1, dict2): return dict1.update(dict2) or dict1 d1 = {i: str(i) for i in range(1000000)} d2 = {str(i): i for i in range(1000000)} %timeit join2(d1, d2) # 258 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) %timeit join(d1, d2) # 262 ms ± 2.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) %timeit dict(d1, **d2) # 267 ms ± 2.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) %timeit {**d1, **d2} # 267 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Pengaturan waktu untuk operasi di tempat sedikit lebih rumit, sehingga perlu dimodifikasi sepanjang operasi penyalinan tambahan (pengaturan waktu pertama hanya untuk referensi):
%timeit dd = d1.copy() # 44.9 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) %timeit dd = d1.copy(); join2(dd, d2) # 296 ms ± 2.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) %timeit dd = d1.copy(); join2(dd, d2, True) # 234 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) %timeit dd = d1.copy(); update_or(dd, d2) # 235 ms ± 1.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
sumber
Baru saja mencoba ini sendiri dengan Python 3.4 (jadi tidak dapat menggunakan fancy
{**dict_1, **dict_2}
sintaksis ).Saya ingin memiliki kunci non-string dalam kamus serta menyediakan kamus dalam jumlah yang sewenang-wenang.
Juga, saya ingin membuat kamus baru jadi saya memilih untuk tidak menggunakan
collections.ChainMap
(semacam alasan awalnya saya tidak ingin menggunakandict.update
.Inilah yang akhirnya saya tulis:
def merge_dicts(*dicts): all_keys = set(k for d in dicts for k in d.keys()) chain_map = ChainMap(*reversed(dicts)) return {k: chain_map[k] for k in all_keys} merge_maps({'1': 1}, {'2': 2, '3': 3}, {'1': 4, '3': 5}) # {'1': 4, '3': 5, '2': 2}
sumber