Bir dikte değişmezi ile bir diksiyon kurucu kullanmak arasında bir fark var mı?


205

PyCharm'ı kullanarak, bir dikte değişmezini dönüştürmeyi teklif ettiğini fark ettim :

d = {
    'one': '1',
    'two': '2',
}

bir diksiyon kurucuya :

d = dict(one='1', two='2')

Bu farklı yaklaşımlar önemli ölçüde farklılık gösteriyor mu?

(Bu soruyu yazarken dict(), sayısal bir anahtar belirtmenin imkansız göründüğünü fark ettim .. d = {1: 'one', 2: 'two'}mümkün, ama açıkçası dict(1='one' ...)değil. Başka bir şey var mı?)


4
dict()anahtar / değer çiftlerinin bir listesini alır ve adlandırılmış parametrelere izin verir, böylece kullandığınız sözdizimiyle değil, herhangi bir tür sözlük oluşturmak için kullanılır. Ayrıca muhtemelen pyCharm'da bir hata ( youtrack.jetbrains.net/issue/PY-2512 ) olduğu için, özellikle de keşfettikleriniz, düzeltilenler nedeniyle) hiçbir şeye değmez .
Wooble

1
related: stackoverflow.com/questions/5790860/… (özet: PyCharm'ın davranışı daha yavaş ve daha çirkin)
Wooble

1
Görünüşe göre CPython 2.7 dict () daha yavaş (6 kat daha yavaş?). Bkz. Doughellmann.com/2012/11/… Her durumda, kurgu ve işlev çağrıları arasında kod yazmayı ve taşımayı daha kolay bulduğum için kurucu sözdizimini tercih etmeye başlıyorum.
David Wheaton

2
Boşlukları unutmayın: İkinci yolu kullanarak boşluk içeren anahtarlar oluşturamazsınız. İlk yol, herhangi bir dize alabilir, ancak umursamaz. Aynı şey elbette Unicode için de geçerlidir.
CamilB

2
Python 2'de, dict(abc = 123)yapıcı, sözlük anahtarlarının unicode olmasını ve beklemesini beklemeniz 'abc'şaşırtıcı olabilecek bayt-string anahtarları olan bir sözlük üretir . Bkz. Stackoverflow.com/questions/20357210/… . unicode_literalsu'abc'
Li-aung Yip

Yanıtlar:


117

Bence en bariz farkı gösterdiniz. Onun dışında,

İlki aramaya gerek yok dict, bu da onu biraz daha hızlı yapmalı

İkinci görünüyor yukarı dictiçinde locals()ve sonra globals()adlı bir yerel tanımlayarak davranışı geçiş yapabilirsiniz ve buluntular yerleşik, dicther yerde düşünemiyorum rağmen örneğin bu zaman ayıklama belki dışında iyi bir fikir olacağını


4
Yerel olarak adlandırılan bir
diktenin

Ben de dict () kullanmak ilk önce dict () argümanları için bir dict inşa edecek ve daha sonra oluşturulacak gerçek dict örneği için ikinci bir dict yaratacağım inanıyorum. Parantezler, dikte örneğini bir adımda oluşturur.
NeilG

58

Değişmez CALL_FUNCTION genel yerine optimize edilmiş BUILD_MAP ve STORE_MAP opcodes kullandığından çok daha hızlıdır:

> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop

> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop

> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop

> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop

10
@Ned: Çoğu kullanıcı için çoğu zaman önemli değil, ancak bunlardan milyonlarca veya milyarlarca kişinin yaratıldığı ve 2x hızlandırmanın anlamlı olduğu durumlar var.
Bay Fooz

5
@MrFooz: Böyle durumlar var. Mikro zamanlama yapan kişilerin% 99,9'unun bu durumlarda olmadığını düşünüyorum.
Ned Batchelder

29
@Ned Bir iş parçacığında hangisinin daha hızlı olduğunu sorar.
Elliott

11
@Elliot OP hangisinin daha hızlı olduğunu sormadı.
Tom Ferguson

5
Milyonlarca dikte veya milyonlarca anahtarlı bir dikte üretiyorsanız, kaynağınızdaki dikte değişmezlerinden, yanlış yapıyorsunuz.
jwg

41

Python 3.2'de hemen hemen aynı görünüyorlar.

Gnibbler'ın işaret ettiği gibi, ilk önce aramaya gerek yoktur dict, bu da onu biraz daha hızlı hale getirmelidir.

>>> def literal():
...   d = {'one': 1, 'two': 2}
...
>>> def constructor():
...   d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 ('one')
              9 STORE_MAP
             10 LOAD_CONST               3 (2)
             13 LOAD_CONST               4 ('two')
             16 STORE_MAP
             17 STORE_FAST               0 (d)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE
>>> dis.dis(constructor)
  2           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('one')
              6 LOAD_CONST               2 ('1')
              9 LOAD_CONST               3 ('two')
             12 LOAD_CONST               4 ('2')
             15 CALL_FUNCTION          512
             18 STORE_FAST               0 (d)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

Bazı uygulamalarda, bunun gerçekten bir "küçük bit" olmadığını, daha çok 100 faktörüne $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' "{'a': 1, 'b': 2, 'c': 3}" ....... Mean +- std dev: 1.73 ns +- 0.14 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' '{k:v for k,v in i}' ....... Mean +- std dev: 139 ns +- 10 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' 'dict(i)' ....... Mean +- std dev: 188 ns +- 16 ns
benzediğini unutmayın

13

Bu iki yaklaşım, Python'un sözlü kurallarının karıştığı yerler dışında, aynı sözlükleri üretir.

Sözlük değişmezleri biraz daha açık bir şekilde sözlüklerdir ve herhangi bir anahtar türü oluşturabilirsiniz, ancak anahtar adlarını alıntılamanız gerekir. Öte yandan, herhangi bir nedenle gerekiyorsa tuşlar için değişkenler kullanabilirsiniz:

a = "hello"
d = {
    a: 'hi'
    }

dict()Yapıcı çünkü sürer giriş formlarının çeşitliliği size daha fazla esneklik sağlar. Örneğin, bir çift yineleyici sağlayabilir ve bunları anahtar / değer çiftleri olarak ele alır.

Neden PyCharm'ın bir formu diğerine dönüştürmeyi önereceği hakkında hiçbir fikrim yok.


2
Sanırım PyCharm çok güzel olmaya çalışıyor. Her zaman olduğu gibi, tek tırnaklı dizeleri çift tırnak içine dönüştürmek gibi görünüyor - belirgin bir neden yok.
maligree

1
Anahtarlarınızı yalnızca anahtarlarınız dizgiyse alıntılamanız gerekir. Yüzen frozensetlerin tuplleri gibi kolayca olabilirler, ancak bu biraz çirkinleşebilir.
Wooble

7

Python 3.4 + pycharm ile büyük bir fark, dict () yapıcısının anahtar sayısı 256'yı aşarsa bir "sözdizimi hatası" mesajı üretmesidir.

Şimdi dict hazır bilgisini kullanmayı tercih ediyorum.


3
Bu sadece python 3.4 değil. Bunun nedeni, CPython <3.7'nin bir çağrılabilir etikete geçirilen en fazla 255 literal bağımsız değişkeni olmasıdır. ( stackoverflow.com/a/8932175/2718295 )
cowbert

6

Python 2.7 öğreticisinden:

Bir çift diş teli boş bir sözlük oluşturur: {}. Parantez içine virgülle ayrılmış bir anahtar: değer çiftleri listesi yerleştirmek sözlüğe ilk anahtar: değer çiftlerini ekler; bu aynı zamanda sözlüklerin çıktı üzerine yazılma şeklidir.

tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}

Süre:

Dict () yapıcısı, doğrudan tuples olarak depolanan anahtar / değer çiftleri listelerinden sözlükler oluşturur. Çiftler bir kalıp oluşturduğunda, liste kavrayışları anahtar / değer çiftini kompakt bir şekilde belirtebilir.

tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))

Anahtarlar basit dizeler olduğunda, bazen anahtar kelime bağımsız değişkenlerini kullanarak çiftleri belirtmek daha kolaydır:

dict(sape=4139, guido=4127, jack=4098)
>>>  {'sape': 4139, 'jack':4098, 'guido': 4127}

Dolayısıyla hem {} hem de dict () sözlük üretir ancak sözlük verilerinin başlatılmasında biraz farklı yollar sağlar.


3

Dikte değişmezinin d = {'one': '1'}, şeyler değerlerini atamak ve bunlarıdict() .

Öte yandan insanların dict literal d = {'one', '1'} modern python 2.7 + bir set oluşturacak .

Buna rağmen hala her şeyi set değişmezini kullanmayı tercih ediyorum çünkü sanırım onun daha okunabilir, kişisel tercihi olduğunu düşünüyorum.


Düzenli söz diziminin setmevcut olduğunu düzenli olarak unutuyorum . Keşke emirleri için gerçek bir sözdizimi olsaydı ... onları setlerden daha sık kullandığımdan eminim.
ArtOfWarfare

2

dict () değişmez değeri, başka bir şeyden (none python) yapıştırma değerlerini kopyaladığınızda güzeldir. Örneğin, ortam değişkenlerinin listesi. eğer bir bash dosyanız varsa,

FOO='bar'
CABBAGE='good'

daha sonra kolayca bir dict()değişmez süreye yapıştırabilir ve yorum ekleyebilirsiniz. Ayrıca tersini yapmayı, başka bir şeye kopyalamayı kolaylaştırır. Oysa {'FOO': 'bar'}sözdizimi python ve json'a özgüdür. Eğer json'u çok kullanırsanız {}, çift tırnaklı değişmez değerler kullanmak isteyebilirsiniz .


2

Dict miras alınan sınıflar, özel dict sınıfları ek yöntemlerle oluşturmak için bir dikte hazır bilgisi yoktur. Bu durumda, özel dict sınıfı yapıcısı kullanılmalıdır, örneğin:

class NestedDict(dict):

    # ... skipped

state_type_map = NestedDict(**{
    'owns': 'Another',
    'uses': 'Another',
})

0

Ayrıca, işleçler için eşleşen belirteçlerin yapıcı sözdiziminde, yani dasherized anahtarlarda kullanılamayacağını da göz önünde bulundurun.

>>> dict(foo-bar=1)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression

>>> {'foo-bar': 1}
{'foo-bar': 1}
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.