Python'da neden “0, 0 == (0, 0)” “(0, Yanlış)” ile eşittir?


118

Python'da (yalnızca Python 3.6 ile kontrol ettim, ancak önceki sürümlerin çoğu için de geçerli olması gerektiğine inanıyorum):

(0, 0) == 0, 0   # results in a two element tuple: (False, 0)
0, 0 == (0, 0)   # results in a two element tuple: (0, False)
(0, 0) == (0, 0) # results in a boolean True

Fakat:

a = 0, 0
b = (0, 0)
a == b # results in a boolean True

Sonuç iki yaklaşım arasında neden farklılık gösteriyor? Eşitlik operatörü demetleri farklı şekilde ele alıyor mu?

Yanıtlar:


156

İlk iki ifadenin her ikisi de tuple olarak ayrıştırılır:

  1. (0, 0) == 0(hangisi False), ardından0
  2. 0, ardından 0 == (0, 0)(hala Falseböyledir).

Eşitlik operatörüne kıyasla virgül ayırıcısının göreli önceliği nedeniyle ifadeler bu şekilde bölünür: Python, iki demet arasındaki eşitlik testi yerine biri eşitlik testi olan iki ifade içeren bir demet görür.

Ancak ikinci ifadelerinizde bir demet a = 0, 0 olamaz . Demet, bir değerler koleksiyonudur ve eşitlik testinin aksine, Python'da atamanın değeri yoktur. Bir atama bir ifade değil, bir ifadedir; bir demete veya çevreleyen başka herhangi bir ifadeye dahil edilebilecek bir değere sahip değildir. (a = 0), 0Yorumlamayı bir demet olarak zorlamak gibi bir şey denediyseniz , bir sözdizimi hatası alırsınız. Bu, bir demet atamasını bir değişkene bırakır - bu, onu yazarak daha açık hale getirilebilir a = (0, 0)- tek geçerli yorum olarak a = 0, 0.

Öyleyse atamada parantezler olmasa bile a, hem ona hem bde değer atanır (0,0), bu a == bnedenle öyledir True.


17
Eşitliğin değerlendirilmesi virgül operatöründen önce geldiğinden virgül operatörünün eşitlikten daha düşük önceliğe sahip olduğunu söyleyebilirim : eşitlik, virgül operatöründen daha yüksek önceliğe sahiptir. Ancak bu her zaman bir kafa karışıklığı kaynağıdır; sadece diğer kaynakların işleri tersine çevirebileceğini belirtmek istedim.
2017 saat

2
Daha düşük / daha yüksek laf kalabalığı karmaşasından kaçınmak için bunun yerine ,daha az sıkı sıkıya bağlanır diyebilirsiniz ==.
amalloy

4
Virgül bir operatör değil docs.python.org/3.4/faq/…
Chris_Rands

48
Dokümanlar istedikleri her şeyi iddia edebilirler ama bu önemli değil. Her operatörün kendi üretimini alması ve uygulamanın hiçbir yerinde açık bir "öncelik" olmaması için bir ayrıştırıcı yazabilirsiniz, ancak bu sözdizimsel birimlerin operatör olmasını engellemez. "Operatör" ü uygulamaya özel bir şekilde yeniden tanımlayabilirsiniz. , görünüşe göre Python'da yaptıkları şey bu, ancak bu terimin anlamını değiştirmiyor. Virgül, etkin bir şekilde tuple üreten bir operatördür. İşleçliği, örneğin, göreli önceliğinin parantezlerden etkilenme şeklini gösterir.
Mark Reed

68

Her 3 örnekte de gördüğünüz , dilin gramer spesifikasyonunun ve kaynak kodda karşılaşılan belirteçlerin ayrıştırma ağacını oluşturmak için nasıl ayrıştırıldığının bir sonucudur .

Bu düşük seviyeli koda bir göz atmak, kaputun altında ne olduğunu anlamanıza yardımcı olacaktır. Bu python ifadelerini alıp bayt koduna dönüştürebilir ve ardından dismodülü kullanarak derlemeyi çözebiliriz :

Dava 1: (0, 0) == 0, 0

>>> dis.dis(compile("(0, 0) == 0, 0", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               0 (0)
              6 COMPARE_OP               2 (==)
              9 LOAD_CONST               0 (0)
             12 BUILD_TUPLE              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

(0, 0)önce ilk ile karşılaştırılır 0ve değerlendirilir False. Daha sonra bu sonuçla bir demet oluşturulur ve son olarak 0elde edersiniz (False, 0).

Durum 2: 0, 0 == (0, 0)

>>> dis.dis(compile("0, 0 == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               0 (0)
              3 LOAD_CONST               0 (0)
              6 LOAD_CONST               2 ((0, 0))
              9 COMPARE_OP               2 (==)
             12 BUILD_TUPLE              2
             15 POP_TOP
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE

0İlk eleman olarak bir demet oluşturulur . İkinci eleman için, ilk durumda olduğu gibi aynı kontrol yapılır ve değerlendirilir False, böylece elde edersiniz (0, False).

Durum 3: (0, 0) == (0, 0)

>>> dis.dis(compile("(0, 0) == (0, 0)", '', 'exec'))
  1           0 LOAD_CONST               2 ((0, 0))
              3 LOAD_CONST               3 ((0, 0))
              6 COMPARE_OP               2 (==)
              9 POP_TOP
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE

Burada gördüğünüz gibi, sadece bu iki (0, 0)demeti karşılaştırıp geri dönüyorsunuz True.


20

Sorunu açıklamanın başka bir yolu: Muhtemelen sözlük değişmezlerine aşinasınız

{ "a": 1, "b": 2, "c": 3 }

ve dizi değişmez değerleri

[ "a", "b", "c" ]

ve tuple değişmezleri

( 1, 2, 3 )

ama anlamadığınız şey, sözlük ve dizi değişmezlerinin aksine, genellikle bir demet değişmezinin etrafında gördüğünüz parantezlerin değişmez sözdiziminin bir parçası olmadığıdır . Tuples için değişmez sözdizimi, virgülle ayrılmış ifadeler dizisidir:

1, 2, 3

( Python için biçimsel gramer dilinde bir "açıklama" ).

Şimdi, dizinin değişmezinden ne bekliyorsunuz?

[ 0, 0 == (0, 0) ]

değerlendirmek için? Muhtemelen bunun gibi daha çok benziyor gerektiğini aynı olacak

[ 0, (0 == (0, 0)) ]

hangi tabii ki değerlendirir [0, False]. Benzer şekilde, açıkça parantez içine alınmış bir demet hazır bilgisiyle

( 0, 0 == (0, 0) )

elde etmek şaşırtıcı değil (0, False). Ancak parantezler isteğe bağlıdır;

0, 0 == (0, 0)

Aynı şey mi. Ve bu yüzden alırsın (0, False).


Bir demet değişmezinin etrafındaki parantezlerin neden isteğe bağlı olduğunu merak ediyorsanız , büyük ölçüde yıkıcı ödevleri bu şekilde yazmak zorunda kalmanın can sıkıcı olmasından kaynaklanmaktadır:

(a, b) = (c, d) # meh
a, b = c, d     # better

17

Eylemlerin gerçekleştirildiği sıranın etrafına birkaç parantez eklemek, sonuçları daha iyi anlamanıza yardımcı olabilir:

# Build two element tuple comprising of 
# (0, 0) == 0 result and 0
>>> ((0, 0) == 0), 0
(False, 0)

# Build two element tuple comprising of
# 0 and result of (0, 0) == 0 
>>> 0, (0 == (0, 0))
(0, False)

# Create two tuples with elements (0, 0) 
# and compare them
>>> (0, 0) == (0, 0) 
True

Virgül, ifadeleri ayırmak için kullanılır (parantez kullanarak, elbette farklı davranışları zorlayabiliriz). Listelediğiniz parçacıkları görüntülerken, virgül ,onu ayırır ve hangi ifadelerin değerlendirileceğini tanımlar:

(0, 0) == 0 ,   0
#-----------|------
  expr 1      expr2

Demet (0, 0)aynı şekilde benzer şekilde parçalanabilir. Virgül, değişmez değerlerden oluşan iki ifadeyi ayırır 0.


6

İlkinde Python iki şeyden oluşan bir demet oluşturuyor:

  1. Olarak (0, 0) == 0değerlendirilen ifadeFalse
  2. Sabit 0

İkincisi ise tam tersi.


0

şu örneğe bakın:

r = [1,0,1,0,1,1,0,0,0,1]
print(r==0,0,r,1,0)
print(r==r,0,1,0,1,0)

sonra sonuç:

False 0 [1, 0, 1, 0, 1, 1, 0, 0, 0, 1] 1 0
True 0 1 0 1 0

daha sonra karşılaştırma, örnekteki ilk sayıya (0 ve r) yapar.

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.