Bu bir hata gibi gözüküyor. onlar sadece "O"
bir biçim dizesi geçirerek, _PyObject_CallMethodId
(PyObject_CallMethod
optimize edilmiş bir varyantı) kötüye gibi The implementation is to convert the dict_keys
to a set
, then call .difference_update(arg)
on it.
görünüyor. Thing is, PyObject_CallMethod
and friends are documented to require a Py_BuildValue
format string that "should produce a tuple
". Birden fazla biçim koduyla, tuple
'daki değerleri otomatik olarak kaydırır, ancak yalnızca bir biçim koduyla, tuple
değil, yalnızca değeri oluşturur (bu durumda, zaten PyObject*
olduğu için, hepsi bunu artırır referans sayısı). Bu yapıyor olabilir nerede aşağı izlenmez olsa da
, ben tuple
sözde fonksiyon aslında can bir tek eleman yapmak için bir tuple
üretemezler CallMethod
çağrıları belirleme ve bunları sarıyor içlerinde bir yerlerde şüpheli argümanları beklenen formatta alırsınız. Bir tuple
çıkarıldığında, zaten bir tuple
, ve bu düzeltme kodu hiçbir zaman etkinleşmez; list
'u iletirken, list
'u içeren tek bir öğe tuple
haline gelir.
difference_update
varargs (def difference_update(self, *args)
olarak bildirilmiş gibi) alır. Bu nedenle, açılmamış tuple
'u aldığında, tuple
'daki her girdiden öğeleri çıkarması gerektiğini düşünür, söz konusu girdileri kendileri çıkarmak için değerler olarak ele almaz. Bunu yaparken, göstermek için:
mydict.keys() - (1, 2)
böcek bunu yapmak neden olan (kabaca):
result = set(mydict)
# We've got a tuple to pass, so all's well...
result.difference_update(*(1, 2)) # Unpack behaves like difference_update(1, 2)
# OH NO!
ederken:
mydict.keys() - [1, 2]
yapar:
result = set(mydict)
# [1, 2] isn't a tuple, so wrap
result.difference_update(*([1, 2],)) # Behaves like difference_update([1, 2])
# All's well
Bu yüzden yerine 'abc'
ve '123'
vs., 'c'
, 'b'
, 'a'
için
result.difference_update(*('abc', '123'))
# or without unpacking:
result.difference_update('abc', '123')
ve str
ler kendi karakterlerinin Iterables olduğundan, sadece kaygısızca kaldırır girişleri:işleri (yanlış), - ('abc', '123')
bir çağrı eşdeğer performans beklediğin gibi.
Temel olarak, bu bir hatadır ve (bir şans elde ettiğimde), bunu CPython milletine karşı yazacağım.
doğru davranış muhtemelen (bu Id
varyant bu API için var varsayarak) aramak olmalıydı: hiç paketleme sorunları olmazdı ve daha hızlı boot aday olacağını
_PyObject_CallMethodObjArgsId(result, &PyId_difference_update, other, NULL);
; En küçük değişiklik, biçim dizgesini "(O)"
biçiminde tek bir öğe için bile tuple
oluşturmaya zorlamak olacaktır, ancak biçim dizisi hiçbir şey kazanmadığından, _PyObject_CallMethodObjArgsId
daha iyidir.
Tuple'ler değişmezdir ve bu nedenle sözlüğün kendileri için anahtarlar olabilir, bu durumda belirsiz olur - eğer en azından bir programcının zihninde sözdizimsel değilse. – L3viathan
@ L3viathan İkna olmadım çünkü 'dict.fromkeys ('') tuşları() -' 02 'hala çalışıyor – wim
Evet, iyi nokta. – L3viathan