Python'da iki sözlük tek bir ifadede nasıl birleştirilir?


4783

İki Python sözlüğüm var ve birleştirilen bu iki sözlüğü döndüren tek bir ifade yazmak istiyorum. update()Yöntem onun sonucunu döndürdü yerine yerinde bir sözlük değiştirerek eğer, ne gerek olacaktır.

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

Son birleştirilen sözlüğü nasıl alabilirim z, değil xmi?

(Daha net olmak gerekirse, sonuncusu ile çatışmaları ele almak dict.update()benim aradığım şeydir.)


1
Python 3.9 alfa kullanma şansınızda, sadece kullanınz = x | y
The Daleks

Yanıtlar:


5696

İki Python sözlüğünü tek bir ifadede nasıl birleştirebilirim?

Sözlüklerde için xve y, zbir sığ değerlerle Sözlük birleşti olur ygelenler değiştirilmesi x.

  • Python 3.5 veya üstü sürümlerde:

    z = {**x, **y}
  • Python 2'de (veya 3.4 veya daha düşük) bir işlev yazın:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z

    ve şimdi:

    z = merge_two_dicts(x, y)
  • Python 3.9.0a4 veya daha büyük sürümlerde (son yayın tarihi yaklaşık Ekim 2020): Burada tartışılan PEP-584 , bunu daha da basitleştirmek için uygulandı:

    z = x | y          # NOTE: 3.9+ ONLY

açıklama

İki dikteniz olduğunu ve orijinal dikleri değiştirmeden bunları yeni bir dikte birleştirmek istediğinizi varsayalım:

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

İstenen sonuç, zbirleştirilen değerler ve ikinci diktenin değerleri birinciden bunların üzerine yazılan yeni bir sözlük ( ) elde etmektir.

>>> z
{'a': 1, 'b': 3, 'c': 4}

Önerilen bunun için yeni bir sözdizimi, PEP 448 ve Python 3.5 itibariyle mevcut olduğu

z = {**x, **y}

Ve aslında tek bir ifadedir.

Gerçek gösterimle de birleştirebileceğimizi unutmayın:

z = {**x, 'foo': 1, 'bar': 2, **y}

ve şimdi:

>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}

Şimdi 3.5, PEP 478 sürüm programında uygulandığı şekliyle gösteriliyor ve şimdi Python 3.5 belgesindeki Yenilikler belgesine girdi .

Ancak, birçok kuruluş hala Python 2'de olduğu için, bunu geriye dönük uyumlu bir şekilde yapmak isteyebilirsiniz. Python 2 ve Python 3.0-3.4'te bulunan klasik Pythonic yolu, bunu iki adımlı bir işlem olarak yapmaktır:

z = x.copy()
z.update(y) # which returns None since it mutates z

Her iki yaklaşımda da yikinci olacak ve değerleri x'nin değerlerinin yerini alacak , böylece nihai sonucumuza 'b'işaret edecektir 3.

Henüz Python 3.5'te değil, tek bir ifade istiyorum

Henüz Python 3.5'te değilseniz veya geriye dönük uyumlu bir kod yazmanız gerekiyorsa ve bunu tek bir ifadede istiyorsanız , en doğru performans en doğru yaklaşım onu ​​bir işleve koymaktır:

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

ve sonra tek bir ifadeniz var:

z = merge_two_dicts(x, y)

Ayrıca, sıfırdan çok büyük bir sayıya kadar tanımsız sayıda dikteyi birleştirmek için bir işlev de yapabilirsiniz:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

Bu işlev tüm dikteler için Python 2 ve 3'te çalışacaktır. Verilen dicts örneğin aiçin g:

z = merge_dicts(a, b, c, d, e, f, g) 

ve anahtar değer çiftleri gdicts göre öncelikli olacağını aetmek f, vb.

Diğer Cevapların Eleştirileri

Daha önce kabul edilen cevapta gördüklerinizi kullanmayın:

z = dict(x.items() + y.items())

Python 2'de, her bir dikte için bellekte iki liste oluşturursunuz, bellekte bir araya getirilen ilk ikinin uzunluğuna eşit uzunlukta üçüncü bir liste oluşturursunuz ve daha sonra dikteyi oluşturmak için üç listeyi de atarsınız. Python 3'te,dict_items iki liste değil, iki nesne eklediğiniz için bu başarısız olur -

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

ve bunları açıkça liste olarak oluşturmanız gerekir, örn z = dict(list(x.items()) + list(y.items())). Bu, kaynakların ve hesaplama gücünün israfıdır.

Benzer şekilde, değerler paylaşılamayan nesneler (örneğin listeler gibi) olduğunda items()Python 3'te ( viewitems()Python 2.7'de) birleşimi de başarısız olur. Değerleriniz yıkanabilir olsa bile, kümeler semantik olarak sıralanmamış olduğundan, davranış önceliğe göre tanımlanmamıştır. Yani bunu yapma:

>>> c = dict(a.items() | b.items())

Bu örnek, değerler paylaşılamadığında ne olacağını gösterir:

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

İşte y'nin önceliğe sahip olması gereken bir örnek, ancak bunun yerine x'in değeri, kümelerin keyfi sırası nedeniyle korunur:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

Kullanmamanız gereken başka bir kesmek:

z = dict(x, **y)

Bu, yapıcıyı kullanır dictve çok hızlı ve bellek verimlidir (iki aşamalı işlemimizden biraz daha fazla), ancak burada ne olduğunu tam olarak bilmediğiniz sürece (yani, ikinci diksiyon, dikteye anahtar kelime argümanları olarak geçiriliyorsa) yapıcı), okumak zor, amaçlanan kullanım değildir ve Pythonic değildir.

Django'da düzeltilen kullanımın bir örneği .

Diktelerin, yıkanabilir anahtarlar alması amaçlanmıştır (örn. Frozensets veya tuples), ancak anahtarlar dizgisiz olduğunda bu yöntem Python 3'te başarısız olur.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Gönderen posta listesine , Guido van Rossum, dilin yaratıcısı yazdı:

Sonuçta ** mekanizmasını kötüye kullandığından, dikt ({}, ** {1: 3}) yasadışı ilan etmekte iyiyim.

ve

Görünüşe göre (x, ** y), "x.update (y) çağrısı ve x döndürme" için "cool hack" olarak dolaşıyor. Şahsen ben serinden daha aşağılık buluyorum.

Benim amacım ( ve dilin yaratıcısının anlaşılması ) amaçlanan kullanımın dict(**y)okunabilirlik amaçları için dikte oluşturmaktır, örneğin:

dict(a=1, b=10, c=11)

onun yerine

{'a': 1, 'b': 10, 'c': 11}

Yorumlara yanıt

Guido'nun söylediklerine rağmen dict(x, **y), btw olan dikt şartnamesi ile uyumludur. Hem Python 2 hem de 3 için çalışır. Bunun yalnızca dize anahtarları için çalıştığı gerçeği, anahtar kelime parametrelerinin nasıl çalıştığının doğrudan bir sonucudur ve kısa bir açıklama değildir. ** operatörünü de bu yerde mekanizmanın kötüye kullanılması olarak kullanmıyor, aslında ** tam olarak anahtar kelimeleri anahtar olarak aktarmak için tasarlandı.

Yine, anahtarlar dizgisiz olduğunda 3 için çalışmaz. Örtük çağrı sözleşmesi, ad alanlarının normal dikte alması ve kullanıcıların yalnızca dize olan anahtar kelime bağımsız değişkenlerini iletmesi gerektiğidir. Diğer tüm callables bunu zorladı. dictPython 2'de bu tutarlılığı kırdı:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

Python'un (Pypy, Jython, IronPython) diğer uygulamaları dikkate alındığında bu tutarsızlık kötüydü. Böylece Python 3'te düzeltildi, çünkü bu kullanım kırıcı bir değişiklik olabilir.

Size bir dilin yalnızca bir sürümünde çalışan veya yalnızca belirli rasgele kısıtlamalar verildiğinde çalışan kodların kasıtlı olarak yazılmasının kötü amaçlı bir yetersizlik olduğunu size bildiririm.

Diğer yorumlar:

dict(x.items() + y.items()) hala Python 2 için en okunabilir çözümdür. Okunabilirlik önemlidir.

Cevabım: merge_two_dicts(x, y)aslında okunabilirlik konusunda endişeliysek bana çok daha açık görünüyor. Ve Python 2 gittikçe kullanımdan kaldırıldığı için ileri uyumlu değildir.

{**x, **y}iç içe sözlükleri işlemiyor gibi görünmüyor. iç içe anahtarların içeriği sadece üzerine yazılır, birleştirilmez [...] Yinelenen bu cevaplar tarafından yakıldım ve kimsenin bahsetmediğine şaşırdım. "Birleştirme" kelimesini yorumladığımda, bu cevaplar "bir dikteyi diğeriyle güncellemek" ve birleşmemek anlamına geliyor.

Evet. Sizi iki kişilik sığ birleşme isteyen soruya geri yönlendirmeliyim sözlükten ilkinin değerleri ikincinin değerleri üzerine yazılan tek bir ifadede .

İki sözlük sözlüğü varsayarsak, biri bunları tek bir işlevde yinelemeli olarak birleştirebilir, ancak her iki kaynaktan gelen dikmeleri değiştirmemeye dikkat etmelisiniz ve bundan kaçınmanın en kesin yolu, değerleri atarken bir kopya yapmaktır. Anahtarların yıkanabilir olması ve genellikle değiştirilememesi gerektiğinden, bunları kopyalamak anlamsızdır:

from copy import deepcopy

def dict_of_dicts_merge(x, y):
    z = {}
    overlapping_keys = x.keys() & y.keys()
    for key in overlapping_keys:
        z[key] = dict_of_dicts_merge(x[key], y[key])
    for key in x.keys() - overlapping_keys:
        z[key] = deepcopy(x[key])
    for key in y.keys() - overlapping_keys:
        z[key] = deepcopy(y[key])
    return z

Kullanımı:

>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}

Diğer değer türleri için beklenmedik durumlarla karşılaşmak bu sorunun kapsamı dışındadır, bu yüzden sizi "sözlüklerin birleştirilmesi sözlükleri" hakkındaki kanonik soruya vereceğim yanıta işaret edeceğim .

Daha Az Performanslı Ama Doğru Ad-hocs

Bu yaklaşımlar daha az performans gösterir, ancak doğru davranış sağlayacaktır. Onlar olacak çok daha az ölçülebilir daha copyve updateyeni açma onlar daha yüksek bir soyutlama düzeyinde her anahtar-değer çifti üzerinden yineleme çünkü ya, ama onlar yapmak öncelik sırasını (ikinci dicts önceliğe sahip) saygı

Bir dikseli kavrama içinde dikleri manuel olarak zincirleyebilirsiniz:

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

veya python 2.6'da (ve belki de jeneratör ifadeleri eklendiğinde 2.4 kadar erken):

dict((k, v) for d in dicts for k, v in d.items())

itertools.chain yineleyicileri anahtar / değer çiftleri üzerinde doğru sırada zincirler:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Performans analizi

Sadece doğru davrandığı bilinen kullanımların performans analizini yapacağım.

import timeit

Ubuntu 14.04'te aşağıdakiler yapılır

Python 2.7'de (sistem Python):

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

Python 3.5'te (deadsnakes PPA):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

Sözlüklerdeki Kaynaklar


9
@MohammadAzim "yalnızca dizeler" genelleştirilmiş paket açma sözdizimi için değil, yalnızca callables'ta anahtar kelime bağımsız değişkeni genişletmesi için geçerlidir. Bunun işe yaradığını göstermek için: {**{(0, 1):2}}->{(0, 1): 2}
Aaron Hall

37
z = {**x, **y}beni gerçekten uyarmak gibi kısa cevaplar
pcko1

1
Bu, PEP-0584 kabul edildiğinde değiştirilebilir. Aşağıdaki sözdizimiyle yeni bir sendika operatörü uygulanacaktır:x | y
Callam Delaney

2
Bir yanıtın üst kısımda bir özete ihtiyacı olduğunda çok uzun olur.
Gringo Suave

2
Merhaba, üst bir özet, evet. Sana bağlı. Her şey harika bir blog yazısı olurdu. Not Py 3.4 ve altı, 2020-09'da EOL'ye yaklaşan EOL, 3.5'dir.
Gringo Suave

1617

Sizin durumunuzda yapabileceğiniz şey:

z = dict(x.items() + y.items())

Bu, istediğiniz gibi, son dikteni koyar ve zanahtarın değerinin bikinci ( y) diktenin değeriyle düzgün bir şekilde geçersiz kılınmasını sağlar :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Python 3 kullanıyorsanız, bu sadece biraz daha karmaşıktır. Oluşturmak için z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

Python sürüm 3.9.0a4 veya üstünü kullanıyorsanız, doğrudan şunları kullanabilirsiniz:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)

Output: {'a': 1, 'c': 11, 'b': 10}

2
Bunu çok verimsiz olduğu için kullanmayın. (Aşağıdaki timeit sonuçlarına bakın.) Bir sarmalayıcı işlevi bir seçenek değilse Py2 günlerinde gerekli olabilir, ancak o günler artık geçmiş olabilir.
Gringo Suave

633

Bir alternatif:

z = x.copy()
z.update(y)

83
Bunun neden soru tarafından sağlanan kriterleri karşılamadığını açıklığa kavuşturmak için: bu tek bir ifade değildir ve z ile geri dönmez.
Alex

2
@neuronet her oneliner genellikle sadece farklı bir bileşene dönüşmesi gereken kodu hareket ettirir ve orada çözer. bu kesinlikle durumlardan biri. ancak diğer diller bunun için python'dan daha güzel yapılara sahiptir. ve öğesini döndüren referans olarak saydam bir varyanta sahip olmak, bir şeye sahip olmak güzeldir.
Alex

12
Bu şekilde söyleyin: kodunuzu verdiğiniz kişilere bir kod satırınızı açıklayan iki yorum satırı koymanız gerekiyorsa ... gerçekten bir satırda yaptınız mı? :) Python'un bunun için iyi olmadığına tamamen katılıyorum: çok daha kolay bir yol olmalı. Bu cevap daha pitonik olsa da, gerçekten bu kadar açık veya net mi? Updateinsanların çok fazla kullanmaya eğilimli olduğu "temel" işlevlerden biri değildir.
eric

İnsanlar bir oneliner yapmakta ısrar ederse, her zaman şunları yapabilirsiniz (lambda z: z.update(y) or z)(x.copy()): P
towr

340

Başka, daha özlü bir seçenek:

z = dict(x, **y)

Not : Bu popüler bir cevap haline geldi, ancak yherhangi bir dize olmayan anahtar varsa, bunun hiç işe yaramadığı gerçeğinin bir CPython uygulama ayrıntısının kötüye kullanılması olduğunu ve Python 3'te çalışmadığını belirtmek önemlidir, veya PyPy, IronPython veya Jython'da. Ayrıca, Guido hayranı değil . Bu nedenle, ileri uyumlu veya çapraz uygulama taşınabilir kodu için bu tekniği öneremem, bu gerçekten tamamen kaçınılması gerektiği anlamına gelir.


Python 3 ve PyPy ve PyPy 3'te iyi çalışır , Jython veya Iron ile konuşamaz. Bu desen açıkça belgelendiğinden (bu belgedeki üçüncü kurucu formuna bakın) bunun bir "uygulama detayı" değil, kasıtlı özellik kullanımı olduğunu iddia ediyorum.
amcgregor

5
@amcgregor "y'de dizgi olmayan anahtar varsa" anahtar sözcüğünü kaçırdınız. Python3'te çalışmayan budur; CPython 2'de çalışması, güvenilemeyen bir uygulama detayıdır. Tüm anahtarlarınızın dize olacağı garanti edilir, bu tamamen desteklenen bir seçenektir.
Carl Meyer

214

Bu muhtemelen popüler bir cevap olmayacak, ancak neredeyse kesinlikle bunu yapmak istemiyorsunuz. Birleştirme olan bir kopya istiyorsanız, kopyayı (veya ne istediğinize bağlı olarak derin kopya ) kullanın ve ardından güncelleyin. İki kod satırı, .items () + .items () ile tek satır oluşturmadan çok daha okunabilir - daha Pythonic. Açık, örtük olmaktan iyidir.

Ayrıca, .items () (Python 3.0 öncesi) kullandığınızda, dikteden öğeleri içeren yeni bir liste oluşturursunuz. Sözlükleriniz büyükse, bu oldukça ek yüktür (birleştirilen diksiyon oluşturulduğu anda atılacak iki büyük liste). update () daha verimli çalışabilir, çünkü ikinci dikdörtgeni tek tek yürütebilir.

Zaman açısından :

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO, ilk ikisi arasındaki küçük yavaşlama, okunabilirlik için buna değer. Ayrıca, sözlük oluşturmak için anahtar kelime bağımsız değişkenleri yalnızca Python 2.3'e eklenirken, copy () ve update () eski sürümlerde çalışacaktır.


150

Takip eden bir cevapta, bu iki alternatifin göreceli performansını sordunuz:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

Makinemde, en azından (oldukça sıradan bir x86_64 Python 2.5.2 çalıştıran), alternatif z2sadece daha kısa ve basit değil, aynı zamanda önemli ölçüde daha hızlı. timeitPython ile birlikte gelen modülü kullanarak bunu kendiniz doğrulayabilirsiniz .

Örnek 1: 20 ardışık tamsayıyı kendilerine eşleyen özdeş sözlükler:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z23,5 katına kadar kazanır. Farklı sözlükler oldukça farklı sonuçlar z2veriyor gibi görünüyor , ancak her zaman öne çıkıyor gibi görünüyor. ( Aynı test için tutarsız sonuçlar alırsanız -r, varsayılan 3'ten büyük bir sayı ile aktarmayı deneyin .)

Örnek 2: 252 kısa dizeyi tamsayılarla eşleştiren örtüşmeyen sözlükler veya tersi:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 10'luk bir faktör kazanır. Bu, kitabımda oldukça büyük bir kazanç!

Bu ikisini karşılaştırdıktan sonra, z1kötü performansın iki öğe listesini oluşturma yükü ile ilişkilendirilip ilişkilendirilemeyeceğini merak ettim , bu da beni bu varyasyonun daha iyi çalışıp çalışmadığını merak etmeme neden oldu:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

Birkaç hızlı test, ör.

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

beni z3biraz daha hızlı z1, ama neredeyse hızlı değilz2 . Kesinlikle tüm ekstra yazarak değer.

Bu tartışmada hala önemli bir şey eksik, bu da bu alternatiflerin iki listeyi birleştirmenin "açık" yolu ile performans karşılaştırmasıdır: updateyöntemi kullanma . Hiçbiri x veya y'yi değiştirmeyen ifadelerle eşit temelde tutmaya çalışmak için, aşağıdaki gibi yerinde değiştirmek yerine x'in bir kopyasını oluşturacağım:

z0 = dict(x)
z0.update(y)

Tipik bir sonuç:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

Başka bir deyişle, z0ve z2aslında aynı performansa sahip gibi görünüyor. Sizce bu bir tesadüf olabilir mi? Yapmıyorum....

Aslında, saf Python kodunun bundan daha iyisini yapmasının imkansız olduğunu iddia edecek kadar ileri gideceğim. Ve bir C uzatma modülünde önemli ölçüde daha iyi yapabilirseniz, Python millet Python çekirdeğine kodunuzu (veya yaklaşımınızdaki bir varyasyonu) dahil etmekle ilgilenebileceğini hayal ediyorum. Python dictbirçok yerde kullanır ; operasyonlarını optimize etmek çok önemli.

Bunu şu şekilde de yazabilirsiniz:

z0 = x.copy()
z0.update(y)

Tony'nin yaptığı gibi, ama (şaşırtıcı olmayan bir şekilde) gösterimdeki farkın performans üzerinde ölçülebilir bir etkisi olmadığı ortaya çıkıyor. Size en uygun olanı kullanın. Elbette, iki ifadeli versiyonun anlaşılmasının çok daha kolay olduğunu belirtmek kesinlikle doğrudur.


5
Bu Python 3'te çalışmaz; items()katlanabilir değildir ve iteritemsyoktur.
Antti Haapala

127

Python 3.0 ve sonraki sürümlerde , collections.ChainMaptek bir güncellenebilir görünüm oluşturmak için birden çok dikteyi veya diğer eşlemeleri hangi gruplarla birlikte kullanabilirsiniz:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(ChainMap({}, y, x))
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11

Python 3.5 ve sonrası için güncelleştirme : PEP 448 genişletilmiş sözlük paketleme ve paketini açma kullanabilirsiniz. Bu hızlı ve kolaydır:

>>> x = {'a':1, 'b': 2}
>>> y = y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}

3
Ancak, ChainMap kullanırken dikkatli olun, yinelenen anahtarlarınız varsa, ilk eşlemeden alınan değerlerin kullanıldığını ve bir çağrıyı yaptığınızda delbir ChainMap c'nin o anahtarın ilk eşlemesini sileceğini söyleyin.
Slayer

7
@Prerit Başka ne yapmasını beklersiniz? Zincirli ad alanlarının normal çalışması budur. $ PATH'ın bash'da nasıl çalıştığını düşünün. Yoldaki bir yürütülebilir dosyayı silmek, yukarı doğru aynı adı taşıyan başka bir yürütülebilir dosyayı engellemez.
Raymond Hettinger

2
@Raymond Hettinger Katılıyorum, sadece bir uyarı ekledim. Çoğu insan bunu bilmiyor olabilir. : D
Slayer

@Prerit Bundan dictkaçınmak için atabilirsiniz , yani:dict(ChainMap({}, y, x))
wjandrea

113

Benzer bir şey istedim, ancak yinelenen anahtarlardaki değerlerin nasıl birleştirildiğini belirleme yeteneğine sahiptim, bu yüzden bunu hackledim (ancak yoğun bir şekilde test etmedim). Açıkçası bu tek bir ifade değil, tek bir işlev çağrısıdır.

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

88

Bir özyinelemeyi tekrarlayan / derin güncelleme

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

gösteri:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

Çıktılar:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

Düzenlemeler için teşekkürler.


1
Bu soruya cevap vermiyor. Soru, orijinal sözlüklerden, x ve y'den yeni bir sözlük ister, y'nin x'in yerine güncellenen bir sözlük değil, y'nin değerlerini alır. Bu yanıt, x'ten değerler ekleyerek y'yi yerinde değiştirir. Daha da kötüsü, bu değerleri kopyalamaz, bu yüzden değiştirilen sözlüğü daha fazla değiştirebilir, y ve değişiklikler x sözlüğüne yansıtılabilir. @ Jérôme Umarım bu kod uygulamanız için herhangi bir hataya neden olmaz - en azından değerleri kopyalamak için deepcopy kullanmayı düşünün.
Aaron Hall

1
@AaronHall bunun soruyu cevaplamadığını kabul etti. Ama bu benim ihtiyacımı karşılıyor. Bu sınırlamaları anlıyorum, ancak bu benim durumumda bir sorun değil. Bunu düşünmek, belki de isim yanıltıcıdır, çünkü vermediği bir derin kopyayı uyandırabilir. Ancak derin yuvalama konusunu ele alır. İşte Martellibot'tan başka bir uygulama: stackoverflow.com/questions/3232943/… .
Jérôme

72

Kopyayı kullanmadığımda düşünebileceğim en iyi sürüm:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

Daha hızlı dict(x.items() + y.items())n = copy(a); n.update(b)En azından CPython'da ama o kadar hızlı değil . Eğer değiştirirseniz Bu sürüm ayrıca Python 3 çalışır iteritems()içinitems() otomatik 2to3 aracı tarafından yapılır, hangi.

Şahsen bu sürümü en çok seviyorum çünkü tek bir işlevsel sözdiziminde ne istediğimi oldukça iyi anlatıyor. Tek küçük sorun, y'den gelen değerlerin x'ten gelen değerlere göre öncelikli olduğunu açıkça ortaya koymamasıdır, ancak bunu anlamanın zor olduğuna inanmıyorum.


71

Python 3.5 (PEP 448) daha iyi bir sözdizimi seçeneğine izin verir:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Ya da

final = {'a': 1, 'b': 1, **x, **y}

Python 3.9'da ayrıca | ve | = aşağıdaki örnekle PEP 584'ten

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

Bu çözüm dict(x, **y)-çözümden ne şekilde daha iyidir ? Siz (@CarlMeyer) kendi cevabınızın notunda belirtildiği gibi ( stackoverflow.com/a/39858/2798610 ) Guido bu çözümü yasadışı kabul eder .
Blackeagle52

14
Guido dict(x, **y), yyalnızca geçerli anahtar kelime bağımsız değişken adları olan anahtarlara sahip olmasından (çok iyi) bir nedenden dolayı hoşlanmaz ( dict yapıcısının hile yaptığı CPython 2.7 kullanmıyorsanız). Bu itiraz / kısıtlama, **değişmezleri belirlemeye yönelik açılmış sözdizimini genelleştiren PEP 448 için geçerli değildir . Dolayısıyla bu çözümün dict(x, **y)dezavantajı olmadan aynı kısma sahiptir .
Carl Meyer

62
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

Her iki sözlükte de anahtar bulunan öğeler için ('b'), hangisini çıktıya sonlandıracağınızı kontrol edebilirsiniz.


Python 3'te +: 'dict_items' ve 'dict_items' için TypeError: desteklenmeyen işlenen tür (ler) i alırsınız ... (y.items ()))
justSaid

49

Soru zaten birkaç kez cevaplanmış olsa da, soruna bu basit çözüm henüz listelenmemiştir.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

Yukarıda z0 ve kötü z2 kadar hızlıdır, ancak anlaşılması ve değiştirilmesi kolaydır.


3
ancak bu bir ifade yerine üç ifade
fortran

14
Evet! Bahsedilen tek-ekspresyon-çözeltileri ya yavaş ya da kötüdür. İyi kod okunabilir ve bakımı yapılabilir. Yani sorun cevap değil soru. Tek satırlık bir çözüm için değil, bir sorunun en iyi çözümünü istemeliyiz.
phobie

7
z4 = {}Bir sonraki satırı kaybedip değiştirin z4 = x.copy()- iyi kod, gereksiz şeyleri yapmaktan daha iyi (daha da okunabilir ve bakım yapılabilir hale getirir).
martineau

3
Öneriniz bunu Matthews cevabına çevirecektir. Cevabı iyi olsa da, benimkinin daha okunabilir ve daha iyi korunabilir olduğunu düşünüyorum. Ek satır yalnızca yürütme süresine mal olacaksa kötü olur.
phobie

47
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Böyle gölgeli ve şüpheli cevaplar arasında, bu parlayan örnek Python'daki diktatörlerin Guido van Rossum'un kendisi için diktatör tarafından onaylanan tek ve tek iyi yoludur ! Birisi bunun yarısını önerdi, ancak bir işleve koymadı.

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

verir:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

39

Lambdaların kötü olduğunu düşünüyorsanız, daha fazla okuyun. İstendiği gibi, hızlı ve bellek tasarruflu çözümü tek bir ifadeyle yazabilirsiniz:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

Yukarıda önerildiği gibi, iki satır kullanmak veya bir işlev yazmak muhtemelen daha iyi bir yoldur.


33

Pitonik olun. Bir anlayış kullanın :

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}

1
Bir fonksiyon olarak:def dictmerge(*args): return {i:d[i] for d in args for i in d}
jessexknight

1
Anahtar / değer çiftlerini doğrudan yineleyerek aramayı kaydedin:z={k: v for d in (x, y) for k, v in d.items()}
ShadowRanger

30

Python3'te, itemsyöntem artık bir liste değil , bir küme gibi çalışan bir görünüm döndürür . Bu durumda, birleştirme +işlemi işe yaramayacağı için set birliğini almanız gerekir :

dict(x.items() | y.items())

2.7 sürümündeki python3 benzeri davranışlar için, viewitemsyöntem şu şekilde çalışmalıdır items:

dict(x.viewitems() | y.viewitems())

Bu gösterimi yine de tercih ediyorum çünkü onu birleştirme yerine bir başlık operasyonu olarak (başlık gösterdiği gibi) düşünmek daha doğal görünüyor.

Düzenle:

Python 3 için birkaç puan daha. İlk dict(x, **y)olarak, anahtarlar girmedikçe hile python 3'te çalışmazy dizgiler .

Ayrıca, Raymond Hettinger'in Chainmap cevabı oldukça zariftir, çünkü argüman olarak keyfi sayıda dikteyi alabilir, ancak dokümanlardan sırayla her arama için tüm diktelerin bir listesini inceler gibi görünüyor:

Aramalar, bir anahtar bulunana kadar altta yatan eşlemeleri sırayla arar.

Uygulamanızda çok fazla arama varsa, bu sizi yavaşlatabilir:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Yani aramalar için daha yavaş bir büyüklük sırası hakkında. Ben Chainmap hayranıyım, ancak birçok arama yapılabilecek yerlerde daha az pratik görünüyor.


22

Matthew'in cevabı için tek ifadeli bir çözüme yol açan kötüye kullanım :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

Bir ifade istediğini söyledin, bu yüzden istismar ettim lambda bir adı bağlamak için ve lambda'nın tek ifade sınırını geçersiz kılmak için tuples. Küstah hissedin.

Kopyalamayı umursamıyorsanız bunu da elbette yapabilirsiniz:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

22

Düzeni koruyan itertools kullanarak basit çözüm (son dikte önceliklidir)

import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))

Ve kullanımı:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}


16

Bu sığ için cevaplar iyi olmasına rağmen sözlük burada tanımlanan yöntemlerin hiçbiri aslında derin bir sözlük birleştirmesi yapmaz.

Aşağıdaki örnekler:

a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())

Böyle bir şeyin sonucu beklenebilir:

{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }

Bunun yerine şunu elde ederiz:

{'two': True, 'one': {'extra': False}}

'One' girdisi, gerçekten bir birleştirme olsaydı sözlüğünün içindeki öğeler olarak 'derinlik_2' ve 'ekstra' olmalıdır.

Zinciri de kullanmak işe yaramaz:

from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

Sonuçlar:

{'two': True, 'one': {'extra': False}}

Rcwesick'in verdiği derin birleşme de aynı sonucu yaratıyor.

Evet, örnek sözlükleri birleştirmek için işe yarayacaktır, ancak hiçbiri birleştirmek için genel bir mekanizma değildir. Gerçek birleştirme yapan bir yöntem yazdığımda bunu daha sonra güncelleyeceğim.


11

(Yalnızca Python2.7 * için; Python3 * için daha basit çözümler vardır.)

Standart bir kütüphane modülünü içe aktarmaktan çekiniyorsanız şunları yapabilirsiniz:

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

(İçindeki or abit lambdagereklidir, çünkü dict.updateher zaman Nonebaşarıya geri döner .)


11

Eğer mutasyona uğramazsan x,

x.update(y) or x

Basit, okunabilir, performans. Sen biliyor update() hep döner Noneyanlış bir değer olan. Yukarıdaki ifade her zamanx güncellendikten sonra .

Standart kütüphanedeki mutasyon yöntemleri konvansiyonla .update()geri döner None, böylece bu örüntü de bunlar üzerinde çalışır. Bu kurala uymayan bir yöntem kullanıyorsanız orişe yaramayabilir. Ancak, bunun yerine tek bir ifade yapmak için bir demet görüntüleme ve dizin kullanabilirsiniz. Bu, ilk öğenin neyi değerlendirdiğinden bağımsız olarak çalışır.

(x.update(y), x)[-1]

Eğer yoksa xhenüz bir değişkene kullanabileceğiniz lambdabir atama deyimi kullanmadan bir yerel yapmak. Bu , işlevsel dillerde yaygın bir teknik olan, ancak belki de sesonik olmayan lambdabir let ifadesi olarak kullanmak anlamına gelir.

(lambda x: x.update(y) or x)({'a': 1, 'b': 2})

Her ne kadar yeni mors operatörünün aşağıdaki kullanımından farklı olmasa da (sadece Python 3.8+):

(x := {'a': 1, 'b': 2}).update(y) or x

Bir kopya istiyorsanız, PEP 448 stili en kolayıdır {**x, **y}. Ancak bu (eski) Python sürümünüzde mevcut değilse, izin deseni burada da çalışır.

(lambda z: z.update(y) or z)(x.copy())

(Tabii ki buna eşdeğerdir (z := x.copy()).update(y) or z, ancak Python sürümünüz bunun için yeterince yeniyse, PEP 448 stili kullanılabilir olacaktır.)


10

Burada ve başka yerlerde fikirlere dayanarak bir işlevi anladım:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Kullanımı (python 3'te test edilmiştir):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

Bunun yerine lambda kullanabilirsiniz.


10

Bugüne kadar listelenen çözümlerde yaşadığım sorun, birleştirilmiş sözlükte "b" anahtarının değerinin 10 olması, ancak benim düşünceme göre, bu 12 olmalıdır. Bu ışıkta, aşağıdakileri sunuyorum:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

Sonuçlar:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}

1
İlginizi çekebilir cytoolz.merge_with( toolz.readthedocs.io/en/latest/… )
bli

10

O kadar aptalca bir şey .updatedöndürmez ki .
Sorunu çözmek için basit bir yardımcı işlev kullanıyorum:

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

Örnekler:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy

10
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

Bu probleminizi çözmeli.


9

Bu tek bir diksiyon kavrayışı ile yapılabilir:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

Benim görüşüme göre, 'tek ifade' kısmı için en iyi cevap, ekstra fonksiyona gerek olmadığı için ve kısa.


Performansın çok iyi olmayacağından şüpheleniyorum; Her dikteden bir set oluşturmak ve daha sonra sadece anahtarları yinelemek, her seferinde değer için başka bir arama anlamına gelir (nispeten hızlı olsa da, ölçekleme işlevinin sırasını hala artırır)
Breezer

2
her şey kullandığımız python sürümüne bağlıdır. 3.5 ve üzeri {** x, ** y}, sıralı sözlüğü verir
Rashid Mv

9

PEP 572: Atama İfadeleri sayesinde Python 3.8 yayınlandığında ( 20 Ekim 2019'da yapılması planlanmaktadır) yeni bir seçenek olacaktır . Yeni atama ifadesi işleci , sonucunu atamanıza ve yine de çağırmak için kullanmanıza izin verir , birleştirilmiş kodu iki ifade yerine tek bir ifade bırakarak değiştirir::=copyupdate

newdict = dict1.copy()
newdict.update(dict2)

için:

(newdict := dict1.copy()).update(dict2)

aynı şekilde davranıyorlar. Ayrıca sonucu döndürmeniz gerekiyorsa dict(döndüren bir ifade istediniz dict; yukarıdakiler oluşturur ve atar newdict, ancak geri döndürmez, bu nedenle bunu bir işleve argüman iletmek için kullanamazsınız myfunc((newdict := dict1.copy()).update(dict2))) , daha sonra or newdictsonuna ekleyin ( updatedöndürür None, çünkü falsy olduğundan, newdictifadenin sonucu olarak değerlendirilir ve geri döner ):

(newdict := dict1.copy()).update(dict2) or newdict

Önemli uyarı: Genel olarak, bu yaklaşımı aşağıdaki lehine caydırırdım:

newdict = {**dict1, **dict2}

Açma yaklaşımı (jeneralize, ilk etapta açma bilen herkese nettir hangi yapmanız gerekir hemen a aktarıldığı, bu geçici bir tertip edilirken bu çok daha kısa ve öz yüzden (hiç bir sonuç için bir ad gerektirmez) işlev veya bir list/ tupledeğişmeze veya benzerlerine dahil) ve neredeyse kesinlikle daha hızlıdır (CPython'da) kabaca aşağıdakilere eşittir:

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

ancak somut dictAPI kullanılarak C katmanında yapıldığından, dinamik yöntem arama / bağlama veya işlev çağrısı gönderme yükü dahil değildir (burada (newdict := dict1.copy()).update(dict2)davranıştaki orijinal iki astarla kaçınılmaz olarak özdeştir, işi ayrı adımlarla gerçekleştirir, dinamik arama ile / bağlanma / yöntemlerin çağrılması.

Üç dicts'nin birleştirilmesi açık olduğundan , daha da genişletilebilir :

 newdict = {**dict1, **dict2, **dict3}

atama ifadelerini kullanmanın böyle ölçeklenmediği; alabileceğiniz en yakın şey:

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

veya geçici Nones grubu olmadan , ancak her Nonesonucun doğruluk testi ile :

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

bunların her ikisi de tabii ki çok daha çirkin ve (daha fazla verimsizlikleri içeren ya bir boşa geçici tupleait Noneher bir test virgül ayrılması, ya da anlamsız doğruluğuna ilişkin s updates' Nonekarşılığındaor ayrılması).

Ödev ifadesi yaklaşımının tek gerçek avantajı şu durumlarda oluşur:

  1. Sen ihtiyaçlar hem ele aldığını jenerik koduna sahip sets ve dicts her ikisi destekleyen ( copyveupdate kod kabaca çalışır böylece bunu beklediğiniz gibi)
  2. Sadece dictkendisi değil, keyfi dikte benzeri nesneler almayı beklersiniz ve sol tarafın türünü ve semantiğini korumalıdır (bir düzle bitmek yerine dict). Her myspecialdict({**speciala, **specialb})ne kadar işe yarayabilir olsa da, fazladan bir geçici olabilir dictve myspecialdictdüz özellikleri dictkoruyamazsa (örneğin, normal dictbir anahtarın ilk görünümüne göre düzeni koruyor ve bir anahtarın son görünümüne göre değer koruyor; isteyebilirsiniz dayalı olarak düzeni koruyan, sonuncusunabir anahtarın görünmesi, böylece bir değerin güncellenmesi onu sonuna kadar taşır), o zaman anlambilim yanlış olur. Atama ifadesi sürümü, (uygun şekilde davranmak için muhtemelen aşırı yüklenmiş) adlandırılmış yöntemleri kullandığından, hiçbir zamandicthiç ( dict1zaten a olmadığı sürece dict), orijinal türü (ve orijinal türün semantiğini) korurken, herhangi bir geçici durumdan kaçınarak.

8
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}

Bu yöntem x, kopyasıyla üzerine yazar . Eğer xbir işlev argümanı bu işe yaramazsa ( örneğe bakınız )
bartolo-otrit
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.