"Ve" ve "veya" boole olmayan değerlerle nasıl davranır?


105

Python öğrenmeye çalışıyorum ve güzel ve kısa ama tamamen mantıklı olmayan bazı kodlarla karşılaştım

bağlam şuydu:

def fn(*args):
    return len(args) and max(args)-min(args)

Ne yaptığını anlıyorum, ama neden python bunu yapıyor - yani True / False yerine değeri döndürüyor?

10 and 7-2

döndürür 5. Benzer şekilde, ve 'nin değiştirilmesi veya işlevinde bir değişikliğe neden olur. Yani

10 or 7 - 2

10 dönecekti.

Bu yasal / güvenilir bir tarz mı yoksa bu konuda herhangi bir sorun var mı?


1
and(yanı sıra or) boole değerleriyle çalışmak veya döndürmekle sınırlı değildir.
cs95

1
IMNSHO: Bunu yazmanın biraz kafa karıştırıcı bir yolu; Bir boole (farklı bir min ve maks var mı) veya bir sayı (min ve maks arasındaki fark nedir) döndürmesi gerektiğini düşünmeden söyleyemem. İkincisi ise, sıfır uzunluklu listenin bu farkını sayı olarak vermenin mantıklı olup olmadığı sorusu da var. (Yerine Noneveya bir istisna)
ilkkachu

7
Diğer insanların açıkladığı gibi işe yarıyor, ancak olası bir sorun, geri dönerse boş 0mu yoksa argsboş mu olduğunu söyleyemezsiniz , ancak tüm unsurları eşittir.
Özellikle Lime

@ Özellikle Kireç: aynen. Benim bunu söz ettik cevap .
Eric Duminil

Yanıtlar:


145

TL; DR

İki mantıksal operatörün iki davranışını özetleyerek başlıyoruz andve or. Bu deyimler, aşağıdaki tartışmamızın temelini oluşturacaktır.

and

Varsa ilk Falsy değerini, yoksa ifadedeki son değeri döndür.

or

Varsa ilk Gerçek değerini döndür, yoksa ifadedeki son değeri döndür.

Davranış ayrıca , özellikle bu tabloda , belgelerde özetlenmiştir :

görüntü açıklamasını buraya girin

İşlenenlerine bakılmaksızın bir boole değeri döndüren tek operatör notoperatördür.


"Doğruluk" ve "Doğruluk" Değerlendirmeleri

İfade

len(args) and max(args) - min(args)

Bir mı çok pythonic özlü (ve belki daha az okunabilir) "eğer demenin yolu argsboş değilse, sonucunu döndürmek max(args) - min(args)aksi dönüş", 0. Genel olarak, bir if-elseifadenin daha özlü bir temsilidir . Örneğin,

exp1 and exp2

Aşağıdakilere (kabaca) çevrilmelidir:

r1 = exp1
if r1:
    r1 = exp2

Veya eşdeğer olarak,

r1 = exp2 if exp1 else exp1

Benzer şekilde,

exp1 or exp2

Aşağıdakilere (kabaca) çevrilmelidir:

r1 = exp1
if not r1:
    r1 = exp2

Veya eşdeğer olarak,

r1 = exp1 if exp1 else exp2

Nerede exp1ve nerede exp2rasgele python nesneleri veya bazı nesneler döndüren ifadeler. Buradaki mantıksal andve orişleçlerin kullanımlarını anlamanın anahtarı , bunların üzerinde çalışmakla veya boole değerleri döndürmekle sınırlı olmadıklarını anlamaktır. Doğruluk değerine sahip herhangi bir nesne burada test edilebilir. Bu içerir int, str, list, dict, tuple, set, NoneType, ve kullanıcı nesneleri tanımlandığı gibidir. Kısa devre kuralları da hala geçerlidir.

Ama doğruluk nedir?
Koşullu ifadelerde kullanıldığında nesnelerin nasıl değerlendirildiğini ifade eder. @Patrick Haugh bu yazıda gerçeği güzelce özetliyor .

Aşağıdakiler hariç, tüm değerler "doğru" kabul edilir, bunlar "yanlıştır":

  • None
  • False
  • 0
  • 0.0
  • 0j
  • Decimal(0)
  • Fraction(0, 1)
  • [] - boş list
  • {} - boş dict
  • () - boş tuple
  • '' - boş str
  • b'' - boş bytes
  • set() - boş set
  • boş rangegibirange(0)
  • hangi nesneler için
    • obj.__bool__() İadeler False
    • obj.__len__() İadeler 0

Bir "truthy" değeri tarafından gerçekleştirilen çek tatmin edecek ifveya while tablolar. boolDeğerlerden Trueve değerlerinden farklılaşmak için "doğru" ve "yanlış" kullanıyoruz False.


Nasıl andÇalışır

OP'nin sorusunu, bu operatörlerin bu durumlarda nasıl yapıldığına dair bir tartışmanın parçası olarak inşa ediyoruz.

Tanımı olan bir işlev verildiğinde

def foo(*args):
    ...

Sıfır veya daha fazla bağımsız değişken listesindeki minimum ve maksimum değer arasındaki farkı nasıl döndürürüm?

Minimum ve maksimumu bulmak kolaydır (dahili fonksiyonları kullanın!). Buradaki tek engel, bağımsız değişken listesinin boş olabileceği köşe durumunu uygun şekilde ele almaktır (örneğin, arama foo()). andOperatör sayesinde her ikisini de tek bir hatta yapabiliyoruz :

def foo(*args):
     return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4

foo()
# 0

Bu yana andkullanılan ilk ise, ikinci ifade da değerlendirilmelidir True. İlk ifade doğru olarak değerlendirilirse, dönüş değerinin her zaman ikinci ifadenin sonucu olduğunu unutmayın . İlk ifade Yanlış olarak değerlendirilirse, döndürülen sonuç ilk ifadenin sonucudur.

Yukarıdaki işlevde, eğer foobir veya daha fazla argüman alırsa len(args), büyüktür 0(pozitif bir sayı), dolayısıyla döndürülen sonuç olur max(args) - min(args). Hiçbir argüman geçirilir OTOH, len(args)olduğu 0Falsy olduğu ve hangi 0döndürülür.

Bu işlevi yazmanın alternatif bir yolunun şöyle olacağını unutmayın:

def foo(*args):
    if not len(args):
        return 0
    
    return max(args) - min(args)

Veya daha kısaca,

def foo(*args):
    return 0 if not args else max(args) - min(args)

Elbette, bu işlevlerden hiçbiri herhangi bir tür denetimi yapmaz , bu nedenle sağlanan girdiye tamamen güvenmiyorsanız, bu yapıların basitliğine güvenmeyin.


Nasıl orÇalışır

Çalışmasını orbenzer şekilde yapmacık bir örnekle açıklarım.

Tanımı olan bir işlev verildiğinde

def foo(*args):
    ...

fooTüm sayıları geri getirmeyi nasıl tamamlarsınız 9000?

Burada orköşe davasını halletmek için kullanıyoruz . Biz şöyle tanımlıyoruz foo:

def foo(*args):
     return [x for x in args if x > 9000] or 'No number over 9000!'

foo(9004, 1, 2, 500)
# [9004]

foo(1, 2, 3, 4)
# 'No number over 9000!'

footüm sayıları korumak için listede filtreleme yapar 9000. Bu tür sayılar varsa, liste anlayışının sonucu boş olmayan bir listedir ve bu Doğruluktur, bu nedenle geri döndürülür (burada eylemde kısa devre). Böyle bir sayı yoksa, liste []kompozisyonunun sonucu Falsy'dir. Böylece ikinci ifade artık değerlendirilir (boş olmayan bir dize) ve döndürülür.

Koşul cümlelerini kullanarak bu işlevi şu şekilde yeniden yazabiliriz:

def foo(*args):
    r = [x for x in args if x > 9000]
    if not r:
        return 'No number over 9000!' 
    
    return r

Daha önce olduğu gibi, bu yapı hata işleme açısından daha esnektir.


33
Kısalık için tüm netliği feda etmek "pitonik" değildir, bence burada durum böyle. Basit bir yapı değil.
DBedrenko

11
Python koşullu ifadelerinin bu sözdizimini daha az yaygın hale getirdiğine dikkat edilmelidir. Ben kesinlikle max (args) - min (args) eğer len (args) else 0 orjinaline tercih ederim.
richardb

3
Başta kafa karıştıran diğer bir yaygın olan da, eğer yoksa bir değer atamaktır: "bir_var = arg veya 3"
Erik

12
@Baldrickk, insanlar bu sözdizimini üçlü operatörler lehine kullanmaya başlamadan önce, n-ary koşul ifadeleri söz konusu olduğunda, üçlü operatörlerin hızlı bir şekilde kontrolden çıkabileceğini unutmayın. Örneğin, if ... else (if ... else (if ... else (if ... else ...)))aynı şekilde yeniden yazılabilir ... and ... and ... and ... and ...ve bu noktada her iki durumda da okunabilirliği tartışmak gerçekten zorlaşır.
cs95

4
Kısalık için netliği feda etmek pitonik değildir, ancak bu öyle yapmaz. Bu iyi bilinen bir deyimdir. Diğer herhangi bir deyim gibi öğrenmeniz gereken bir deyimdir, ancak 'açıklıktan ödün vermek' zor.
Miles Rout

18

Python Belgelerinden Alıntı Yapma

Ne o Not andne de or kısıtlamak değeri ve yazın onlar dönmek Falseve Trueziyade dönmek son değerlendirdi argüman . Bu bazen yararlıdır, örneğin, boşsa svarsayılan bir değerle değiştirilmesi gereken bir dizeyse, ifade s or 'foo'istenen değeri verir.

Python bu şekilde boole ifadelerini değerlendirmek için tasarlandı ve yukarıdaki belgeler bize bunu neden yaptıklarına dair bir fikir veriyor.

Bir boole değeri elde etmek için sadece yazın.

return bool(len(args) and max(args)-min(args))

Neden?

Kısa devre.

Örneğin:

2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all

Aynı şey için orde geçerli, yani Hakikat olan ifadeyi bulduğu anda geri döndürecektir , çünkü ifadenin geri kalanını değerlendirmek gereksizdir.

Python, hardcore Trueveya döndürmek yerine Truthy veya Falsey'iFalse döndürür , bunlar yine de veya olarak değerlendirilecektir . İfadeyi olduğu gibi kullanabilirsiniz ve yine de çalışacaktır.TrueFalse


Doğruluk ve Falsey'in ne olduğunu öğrenmek için Patrick Haugh'un cevabını kontrol edin


7

ve ve ya boole mantığı gerçekleştirmek, ama onlar karşılaştırarak asıl değerlerle birini döndürür. Kullanırken ve soldan sağa, değerler boolean bağlamında değerlendirilmektedir. 0, '', [], (), {} ve Hiçbiri boole bağlamında yanlıştır; diğer her şey doğru.

Bir boole bağlamında tüm değerler doğruysa ve son değeri döndürürse.

>>> 2 and 5
5
>>> 2 and 5 and 10
10

Herhangi bir değer, bir Boole bağlamda yanlış ise ve ilk ters değer geri gönderir.

>>> '' and 5
''
>>> 2 and 0 and 5
0

Yani kod

return len(args) and max(args)-min(args)

döner değeri max(args)-min(args)olduğunda bağımsız değişken döndürür başka len(args)0 olan.


5

Bu yasal / güvenilir bir tarz mı yoksa bu konuda herhangi bir sorun var mı?

Bu okunaklı, son değerin döndürüldüğü bir kısa devre değerlendirmesidir .

İyi bir örnek veriyorsun. İşlev, 0hiçbir bağımsız değişken iletilmezse ve kodun iletilen hiçbir bağımsız değişkenin özel durumunu kontrol etmesi gerekmiyorsa geri dönecektir .

Bunu kullanmanın başka bir yolu, Yok bağımsız değişkenlerini boş bir liste gibi değiştirilebilir bir ilkele varsayılan olarak ayarlamaktır:

def fn(alist=None):
    alist = alist or []
    ....

Doğru olmayan bir değer alistona aktarılırsa varsayılan olarak boş bir listeye, bir ififadeden ve değişken varsayılan argüman tuzağından kaçınmanın kullanışlı bir yolu


3

Gotchas

Evet, birkaç sorun var.

fn() == fn(3) == fn(4, 4)

İlk olarak, fndöndürülürse 0, herhangi bir parametre olmadan mı, tek bir parametre ile mi yoksa birden çok eşit parametre ile mi çağrıldığını bilemezsiniz:

>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0

Ne anlama fngeliyor?

O halde Python dinamik bir dildir. Ne fnyaptığı, girdisinin ne olması gerektiği ve çıktısının nasıl görünmesi gerektiği hiçbir yerde belirtilmemiştir . Bu nedenle, işlevi doğru bir şekilde adlandırmak gerçekten önemlidir. Benzer şekilde, argümanların çağrılması gerekmez args. delta(*numbers)veya calculate_range(*numbers)işlevin ne yapması gerektiğini daha iyi açıklayabilir.

Bağımsız değişken hataları

Son olarak, mantıksal andoperatörün, herhangi bir argüman olmadan çağrıldığında işlevin başarısız olmasını engellemesi beklenir. Yine de bazı argümanlar sayı değilse yine de başarısız olur:

>>> fn('1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'

Olası alternatif

İşlevi "Bağışlanmak izninden daha kolay" a göre yazmanın bir yolu . ilke :

def delta(*numbers):
    try:
        return max(numbers) - min(numbers)
    except TypeError:
        raise ValueError("delta should only be called with numerical arguments") from None
    except ValueError:
        raise ValueError("delta should be called with at least one numerical argument") from None

Örnek olarak:

>>> delta()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5

Herhangi deltabir bağımsız değişken olmadan çağrıldığında gerçekten bir istisna oluşturmak istemiyorsanız, başka türlü mümkün olmayan bir değer döndürebilirsiniz (örneğin -1veya None):

>>> def delta(*numbers):
...     try:
...         return max(numbers) - min(numbers)
...     except TypeError:
...         raise ValueError("delta should only be called with numerical arguments") from None
...     except ValueError:
...         return -1 # or None
... 
>>> 
>>> delta()
-1

0

Bu yasal / güvenilir bir tarz mı yoksa bu konuda herhangi bir sorun var mı?

Bu soruya sadece yasal ve güvenilir değil, aynı zamanda son derece pratik olduğunu da eklemek isterim. İşte basit bir örnek:

>>>example_list = []
>>>print example_list or 'empty list'
empty list

Bu nedenle, gerçekten kendi avantajınıza kullanabilirsiniz. Uzlaşmak için bunu böyle görüyorum:

Or Şebeke

Python'un oroperatörü ilk Gerçek-y değerini veya son değeri döndürür ve durur

And Şebeke

Python'un andoperatörü ilk False-y değerini veya son değeri döndürür ve durur

Kamera ARKASI

Python'da, tüm sayılar True0 dışında olarak yorumlanır. Bu nedenle şöyle söylenir:

0 and 10 

aynıdır:

False and True

Açıkça olan False. Bu nedenle, 0 döndürmesi mantıklıdır


0

Evet. Bu, doğru davranış ve karşılaştırmadır.

Python En azından A and Bdöner Bise Aesas olduğu Truetakdirde de dahil olmak üzere Adeğil boş, değil Nonedeğil (örneğin boş olarak boş bir kap list, dictvs.). AIFF döndürülür Atemelde Falseya Noneboş veya null veya.

Öte yandan, A or Bdöner Aise Aesas olduğu Truetakdirde de dahil olmak üzere A, boş değil ise değil None(örneğin, bir boş olarak değil boş bir kap list, dictvs.), aksi takdirde döner B.

Bu davranışı fark etmemek (veya gözden kaçırmak) kolaydır, çünkü Python'da, herhangi bir non-nullboş olmayan nesne True olarak değerlendirilir, bir boole olarak değerlendirilir.

Örneğin, aşağıdakilerin tümü "True" yazdıracaktır

if [102]: 
    print "True"
else: 
    print "False"

if "anything that is not empty or None": 
    print "True"
else: 
    print "False"

if {1, 2, 3}: 
    print "True"
else: 
    print "False"

Öte yandan, aşağıdakilerin tümü "Yanlış" yazdıracaktır

if []: 
    print "True"
else: 
    print "False"

if "": 
    print "True"
else: 
    print "False"

if set ([]): 
    print "True"
else: 
    print "False"

Teşekkür ederim. AAslında yazmak istedim True. Düzeltildi.
emmanuelsa

0

basit bir şekilde anlamak,

VE : if first_val is False return first_val else second_value

Örneğin:

1 and 2 # here it will return 2 because 1 is not False

fakat,

0 and 2 # will return 0 because first value is 0 i.e False

ve => eğer birisi yanlışsa, yanlış olacaktır. eğer ikisi de doğruysa, o zaman sadece gerçek olur

VEYA: if first_val is False return second_val else first_value

nedeni, eğer ilk yanlışsa, 2'nin doğru olup olmadığını kontrol eder.

Örneğin:

1 or 2 # here it will return 1 because 1 is not False

fakat,

0 or 2 # will return 2 because first value is 0 i.e False

veya => yanlış biri varsa, doğru olacaktır. yani eğer ilk değer yanlışsa, 2 değeri ne olursa olsun. böylece ne olursa olsun ikinci değeri döndürür.

eğer biri doğruysa, o zaman gerçek olacaktır. ikisi de yanlışsa, o zaman yanlış olur.

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.