ไวยากรณ์ Python สำหรับ "ถ้า a หรือ b หรือ c แต่ไม่ใช่ทั้งหมด"


130

ฉันมีสคริปต์ python ที่สามารถรับอาร์กิวเมนต์บรรทัดคำสั่งเป็นศูนย์หรือสาม (ไม่ว่ามันจะทำงานบนพฤติกรรมเริ่มต้นหรือต้องการทั้งสามค่าที่ระบุ)

ไวยากรณ์ที่เหมาะสำหรับบางสิ่งเช่น:

if a and (not b or not c) or b and (not a or not c) or c and (not b or not a):

?


4
อาจเริ่มต้นด้วยบางสิ่งเช่นถ้า len (sys.argv) == 0:
Edgar Aroutiounian

6
@EdgarAroutiounian len(sys.argv)จะมีค่าอย่างน้อย 1 เสมอ: รวมไฟล์ปฏิบัติการเป็นไฟล์argv[0].
RoadieRich

10
เนื้อหาของคำถามไม่ตรงกับชื่อคำถาม คุณต้องการตรวจสอบ "ถ้า a หรือ b หรือ c แต่ไม่ใช่ทั้งหมด" หรือ "ถ้าเป็นหนึ่งใน a, b และ c" (ตามที่นิพจน์ที่คุณระบุ)
Doug McClean

2
คุณพูดอะไรเกี่ยวกับ a + b + c ได้บ้าง?
gukoff

6
เดี๋ยวก่อนคำถามอาจใช้อาร์กิวเมนต์เป็นศูนย์หรือสามข้อก็ได้ คุณไม่สามารถพูดได้ว่าif not (a and b and c)(ศูนย์ args) แล้วif a and b and c(ทั้งสาม args)?
acolyte

คำตอบ:


236

หากคุณหมายถึงรูปแบบที่เรียบง่ายให้ใช้สิ่งนี้:

if (not a or not b or not c) and (a or b or c):

ซึ่งแปลชื่อคำถามของคุณ

UPDATE: ตามที่ Volatility และ Supr กล่าวไว้อย่างถูกต้องคุณสามารถใช้กฎหมายของ De Morgan และได้รับสิ่งที่เทียบเท่า:

if (a or b or c) and not (a and b and c):

คำแนะนำของฉันคือการใช้รูปแบบใดที่มีความสำคัญมากกว่าสำหรับคุณและโปรแกรมเมอร์คนอื่น ๆ วิธีแรก"มีบางสิ่งบางอย่างที่ผิดพลาด แต่ยังบางสิ่งบางอย่างที่แท้จริง"ที่สอง"มีบางอย่างที่เป็นจริง แต่ไม่ได้ทุกอย่าง" ถ้าฉันจะเพิ่มประสิทธิภาพหรือทำสิ่งนี้ในฮาร์ดแวร์ฉันจะเลือกอย่างที่สองที่นี่เพียงเลือกที่อ่านได้มากที่สุด (โดยคำนึงถึงเงื่อนไขที่คุณจะทดสอบและชื่อของพวกเขาด้วย) ฉันเลือกอย่างแรก


3
คำตอบที่ดีทั้งหมด แต่สิ่งนี้ชนะด้วยความกระชับและมีการลัดวงจรที่ยอดเยี่ยม ขอบคุณทุกคน!
Chris Wilson

38
ฉันจะทำให้กระชับมากขึ้นและไปด้วยif not (a and b and c) and (a or b or c)
Volatility

208
หรือแม้กระทั่งif (a or b or c) and not (a and b and c)เพื่อให้ตรงกับชื่อที่ดีเลิศ;)
Supr

3
@HennyH ฉันเชื่อว่าคำถามถามว่า "อย่างน้อยหนึ่งเงื่อนไขเป็นจริง แต่ไม่ใช่ทั้งหมด" ไม่ใช่ "มีเงื่อนไขเดียวเท่านั้น"
ความผันผวน

63
@Suprif any([a,b,c]) and not all([a,b,c])
eternalmatt

238

เกี่ยวกับ:

conditions = [a, b, c]
if any(conditions) and not all(conditions):
   ...

ตัวแปรอื่น ๆ :

if 1 <= sum(map(bool, conditions)) <= 2:
   ...

2
sum(conditions)สามารถไปผิดถ้าพวกเขาส่งกลับตัวอย่างซึ่งเป็น2 True
eumiro

7
จริงอยู่คุณต้องน่าเกลียดsum(map(bool, conditions))
jamylak

5
โปรดทราบว่านี่ไม่ใช่การลัดวงจรเนื่องจากเงื่อนไขทั้งหมดได้รับการประเมินล่วงหน้า
จอร์เจีย

14
@PaulScheltema รูปแบบแรกเข้าใจมากกว่าสำหรับใคร
cmh

6
"ใด ๆ และไม่ใช่ทั้งหมด" นี้เป็นวิธีการบูลีนที่ดีที่สุดและชัดเจนที่สุดเพียงแค่คำนึงถึงความแตกต่างที่สำคัญระหว่างอาร์กิวเมนต์ที่มีอยู่และอาร์กิวเมนต์เป็น 'ความจริง'
wim

115

คำถามนี้มีคำตอบที่ได้รับการโหวตสูงและเป็นคำตอบที่ได้รับการยอมรับแล้ว แต่ทั้งหมดนี้ถูกเบี่ยงเบนความสนใจด้วยวิธีการต่างๆในการแสดงปัญหาบูลีนและพลาดประเด็นสำคัญ:

ฉันมีสคริปต์ python ที่สามารถรับอาร์กิวเมนต์บรรทัดคำสั่งเป็นศูนย์หรือสาม (ไม่ว่าจะทำงานตามพฤติกรรมเริ่มต้นหรือต้องการทั้งสามค่าที่ระบุ)

ตรรกะนี้ไม่ควรเป็นความรับผิดชอบของโค้ดของคุณตั้งแต่แรกแต่ควรจัดการโดยargparseโมดูล อย่ากังวลกับการเขียนคำสั่ง if ที่ซับซ้อนให้ตั้งค่าตัวแยกวิเคราะห์อาร์กิวเมนต์ของคุณแทนดังนี้:

#!/usr/bin/env python
import argparse as ap
parser = ap.ArgumentParser()
parser.add_argument('--foo', nargs=3, default=['x', 'y', 'z'])
args = parser.parse_args()
print(args.foo)

และใช่มันควรจะเป็นตัวเลือกที่ไม่ได้เป็นอาร์กิวเมนต์ตำแหน่งเพราะมันเป็นหลังจากที่ทุกตัวเลือก


แก้ไข: ที่อยู่ที่ความกังวลของ LarsH ในความคิดเห็นด้านล่างนี้เป็นตัวอย่างของวิธีที่คุณสามารถเขียนมันถ้าคุณมีบางอย่างที่คุณต้องการติดต่อกับทั้ง 3 หรือ 0ตำแหน่ง args ฉันมีความเห็นว่าอินเทอร์เฟซก่อนหน้านี้มีสไตล์ที่ดีกว่าเนื่องจากอาร์กิวเมนต์ที่เป็นทางเลือกควรเป็นตัวเลือกแต่นี่คือแนวทางอื่นเพื่อความสมบูรณ์ สังเกต kwarg ที่ลบล้างusageเมื่อสร้างโปรแกรมแยกวิเคราะห์ของคุณเพราะargparseจะสร้างข้อความการใช้งานที่ทำให้เข้าใจผิดโดยอัตโนมัติ!

#!/usr/bin/env python
import argparse as ap
parser = ap.ArgumentParser(usage='%(prog)s [-h] [a b c]\n')
parser.add_argument('abc', nargs='*', help='specify 3 or 0 items', default=['x', 'y', 'z'])
args = parser.parse_args()
if len(args.abc) != 3:
  parser.error('expected 3 arguments')
print(args.abc)

นี่คือตัวอย่างการใช้งานบางส่วน:

# default case
wim@wim-zenbook:/tmp$ ./three_or_none.py 
['x', 'y', 'z']

# explicit case
wim@wim-zenbook:/tmp$ ./three_or_none.py 1 2 3
['1', '2', '3']

# example failure mode
wim@wim-zenbook:/tmp$ ./three_or_none.py 1 2 
usage: three_or_none.py [-h] [a b c]
three_or_none.py: error: expected 3 arguments

4
ใช่ฉันเพิ่มสิ่งนั้นโดยเจตนา มันจะเป็นไปได้ที่จะทำให้ตำแหน่งอาร์กิวเมนต์เป็นไปได้และบังคับให้ใช้ 3 หรือ 0 แต่มันจะไม่ทำให้ CLI ดีดังนั้นฉันจึงไม่แนะนำ
Wim

8
แยกประเด็น คุณไม่เชื่อว่าเป็น CLI ที่ดีและคุณสามารถโต้แย้งในจุดนั้นได้และ OP อาจถูกโน้มน้าวใจ แต่คำตอบของคุณเบี่ยงเบนไปจากคำถามมากพอที่จะต้องกล่าวถึงการเปลี่ยนแปลงข้อมูลจำเพาะ ดูเหมือนคุณจะดัดสเป็คเพื่อให้พอดีกับเครื่องมือที่มีอยู่โดยไม่ได้กล่าวถึงการเปลี่ยนแปลง
LarsH

2
@LarsH ตกลงฉันได้เพิ่มตัวอย่างที่เข้ากันได้ดีกับอินเทอร์เฟซดั้งเดิมที่บอกเป็นนัยในคำถาม ตอนนี้ก็ดัดเครื่องมือเพื่อตอบสนองความต้องการสเปคที่มีอยู่ ... ;)
Wim

2
นี่เป็นคำตอบเดียวที่ฉันโหวต +1 สำหรับการตอบคำถามที่แท้จริง
Jonathon Reinhart

1
+1 รูปแบบของ CLI เป็นประเด็นที่มีความสำคัญไม่แยกออกจากกันโดยสิ้นเชิงตามที่บุคคลอื่นกล่าว ฉันเพิ่มคะแนนโพสต์ของคุณและโพสต์อื่น ๆ - ของคุณเป็นต้นตอของปัญหาและเสนอวิธีแก้ปัญหาที่สวยงามในขณะที่โพสต์อื่น ๆ ตอบคำถามตามตัวอักษร และคำตอบทั้งสองประเภทมีประโยชน์และสมควรได้รับ +1
Ben Lee

32

ฉันจะไปเพื่อ:

conds = iter([a, b, c])
if any(conds) and not any(conds):
    # okay...

ฉันคิดว่าสิ่งนี้น่าจะลัดวงจรได้อย่างมีประสิทธิภาพ

คำอธิบาย

โดยการสร้างcondsตัววนซ้ำการใช้anyจะลัดวงจรครั้งแรกและปล่อยให้ตัววนซ้ำชี้ไปยังองค์ประกอบถัดไปหากรายการใดเป็นจริง Falseมิฉะนั้นก็จะใช้รายชื่อทั้งหมดและ ต่อไปanyจะนำรายการที่เหลือมาทำซ้ำและตรวจสอบให้แน่ใจว่าไม่มีค่าจริงอื่นใด ... หากมีข้อความทั้งหมดจะไม่เป็นจริงจึงไม่มีองค์ประกอบที่ไม่ซ้ำกัน (ดังนั้นการลัดวงจร อีกครั้ง) สุดท้ายanyทั้งสองจะกลับมาFalseหรือจะหมด iterable Trueและ

หมายเหตุ: ข้างต้นจะตรวจสอบว่ามีการตั้งเงื่อนไขเพียงข้อเดียวหรือไม่


หากคุณต้องการตรวจสอบว่ามีการตั้งค่ารายการตั้งแต่หนึ่งรายการขึ้นไป แต่ไม่ใช่ทุกรายการคุณสามารถใช้:

not all(conds) and any(conds)

5
ฉันไม่เข้าใจ มันอ่านว่า: ถ้า True และไม่ใช่ True ช่วยฉันเข้าใจ
rGil

1
@rGil: มันอ่านว่า "ถ้าแอปเปิ้ลบางลูกเป็นสีแดง แต่ก็ไม่เป็นสีแดง" - เหมือนกับการพูดว่า "แอปเปิ้ลบางลูกเป็นสีแดง แต่ไม่ใช่ทั้งหมด"
georg

2
แม้จะมีคำอธิบายฉันก็ไม่เข้าใจพฤติกรรม ... ด้วย[a, b, c] = [True, True, False]รหัสของคุณไม่ควร "พิมพ์" Falseในขณะที่ผลลัพธ์ที่คาดหวังคือTrueอะไร?
Awesoon

6
นี่เป็นวิธีที่ค่อนข้างฉลาด แต่ฉันจะใช้วิธีนี้หากคุณไม่ทราบว่าคุณมีเงื่อนไขล่วงหน้ากี่เงื่อนไข แต่สำหรับรายการเงื่อนไขที่เป็นที่รู้จักคงที่การสูญเสียความสามารถในการอ่านนั้นไม่คุ้มค่า
ปุย

4
สิ่งนี้ไม่ลัดวงจร iterรายการจะก่อสร้างเสร็จก่อนที่จะส่งผ่านไปยัง anyและallจะขี้เกียจบริโภครายการจริง แต่รายการได้รับการประเมินอย่างสมบูรณ์แล้วเมื่อคุณไปถึงที่นั่น!
icktoofay

22

ประโยคภาษาอังกฤษ:

“ ถ้า a หรือ b หรือ c แต่ไม่ใช่ทั้งหมด”

แปลเป็นตรรกะนี้:

(a or b or c) and not (a and b and c)

คำว่า "แต่" มักจะมีความหมายถึงการรวมหรืออีกนัยหนึ่งคือ "และ" นอกจากนี้ "ทั้งหมดของพวกเขา" แปลว่าจะร่วมของสภาพ: สภาพนี้และสภาพที่และเงื่อนไขอื่น ๆ "not" จะสลับการเชื่อมต่อทั้งหมดนั้น

ฉันไม่เห็นด้วยกับคำตอบที่ได้รับการยอมรับ ผู้เขียนละเลยที่จะใช้การตีความที่ตรงไปตรงมาที่สุดกับข้อกำหนดและละเลยที่จะใช้กฎของเดอมอร์แกนเพื่อลดความซับซ้อนของนิพจน์ให้กับตัวดำเนินการน้อยลง:

 not a or not b or not c  ->  not (a and b and c)

ในขณะที่อ้างว่าคำตอบคือ "รูปแบบน้อยที่สุด"


จริงๆแล้วแบบนั้นมีน้อย เป็นรูปแบบ PoS ขั้นต่ำสำหรับนิพจน์
Stefano Sanfilippo

10

ผลตอบแทนนี้ถ้าใครและมีเพียงหนึ่งในสามของเงื่อนไขคือTrue Trueอาจเป็นสิ่งที่คุณต้องการในโค้ดตัวอย่างของคุณ

if sum(1 for x in (a,b,c) if x) == 1:

ไม่สวยเท่าคำตอบโดย @defuz
jamylak

10

สิ่งที่เกี่ยวกับ: (เงื่อนไขเฉพาะ)

if (bool(a) + bool(b) + bool(c) == 1):

สังเกตว่าหากคุณอนุญาตสองเงื่อนไขเกินไปคุณก็สามารถทำได้

if (bool(a) + bool(b) + bool(c) in [1,2]):

1
สำหรับบันทึกคำถามจะถามเงื่อนไขสองข้อ อย่างน้อยหนึ่ง แต่ไม่ใช่ทั้งหมด = 1 ในทั้งหมดหรือ 2 ของทั้งหมด
Marius Balčytis

IMHO 1 <= bool(a) + bool(b) + bool(c) <= 2คุณควรสะกดคนที่สองเป็น
คืนสถานะโมนิกา

6

เพื่อความชัดเจนคุณต้องการตัดสินใจโดยพิจารณาจากจำนวนพารามิเตอร์ที่เป็นตรรกะ TRUE (ในกรณีของอาร์กิวเมนต์สตริง - ไม่ว่างเปล่า)?

argsne = (1 if a else 0) + (1 if b else 0) + (1 if c else 0)

จากนั้นคุณได้ทำการตัดสินใจ:

if ( 0 < argsne < 3 ):
 doSth() 

ตอนนี้ตรรกะชัดเจนมากขึ้น


5

และทำไมไม่นับพวกเขา?

import sys
a = sys.argv
if len(a) = 1 :  
    # No arguments were given, the program name count as one
elif len(a) = 4 :
    # Three arguments were given
else :
    # another amount of arguments was given

5

หากคุณไม่รังเกียจที่จะเป็นความลับเล็กน้อยคุณสามารถม้วนแบบจำลอง0 < (a + b + c) < 3ซึ่งจะกลับมาtrueหากคุณมีข้อความจริงระหว่างหนึ่งถึงสองข้อความและเท็จถ้าทั้งหมดเป็นเท็จหรือไม่มีเลยเป็นเท็จ

นอกจากนี้ยังช่วยลดความยุ่งยากหากคุณใช้ฟังก์ชันเพื่อประเมินบูลเนื่องจากคุณประเมินตัวแปรเพียงครั้งเดียวซึ่งหมายความว่าคุณสามารถเขียนฟังก์ชันแบบอินไลน์ได้และไม่จำเป็นต้องเก็บตัวแปรไว้ชั่วคราว (ตัวอย่าง: 0 < ( a(x) + b(x) + c(x) ) < 3.)


4

คำถามระบุว่าคุณต้องการอาร์กิวเมนต์ทั้งสาม (a และ b และ c) หรือไม่มีเลย (ไม่ใช่ (a หรือ b หรือ c))

สิ่งนี้ให้:

(a และ b และ c) หรือไม่ (a หรือ b หรือ c)


4

ตามที่ฉันเข้าใจคุณมีฟังก์ชันที่รับ 3 อาร์กิวเมนต์ แต่ถ้าไม่เป็นเช่นนั้นจะทำงานตามพฤติกรรมเริ่มต้น เนื่องจากคุณยังไม่ได้อธิบายว่าจะเกิดอะไรขึ้นเมื่อมีการให้ 1 หรือ 2 อาร์กิวเมนต์ฉันจะถือว่ามันควรจะเป็นพฤติกรรมเริ่มต้น ในกรณีนี้ฉันคิดว่าคุณจะพบคำตอบต่อไปนี้เป็นประโยชน์มาก:

def method(a=None, b=None, c=None):
    if all([a, b, c]):
        # received 3 arguments
    else:
        # default behavior

อย่างไรก็ตามหากคุณต้องการให้อาร์กิวเมนต์ 1 หรือ 2 จัดการแตกต่างกัน:

def method(a=None, b=None, c=None):
    args = [a, b, c]
    if all(args):
        # received 3 arguments
    elif not any(args):
        # default behavior
    else:
        # some args (raise exception?)

หมายเหตุ:ถือว่าFalseค่า "" จะไม่ถูกส่งผ่านไปยังวิธีนี้


การตรวจสอบค่าความจริงของข้อโต้แย้งเป็นเรื่องที่แตกต่างจากการตรวจสอบว่ามีข้อโต้แย้งอยู่หรือไม่มีอยู่
wim

@wim ดังนั้นกำลังแปลงคำถามให้เหมาะกับคำตอบของคุณ โมดูล argparse ไม่มีส่วนเกี่ยวข้องกับคำถาม แต่จะเพิ่มการนำเข้าอีกครั้งและหาก OP ไม่ได้วางแผนที่จะใช้ argparse เลยมันจะไม่ช่วยอะไรพวกเขาเลย นอกจากนี้หาก "สคริปต์" ไม่ใช่แบบสแตนด์อโลน แต่เป็นโมดูลหรือฟังก์ชันภายในชุดโค้ดที่ใหญ่กว่านั้นอาจมีตัวแยกวิเคราะห์อาร์กิวเมนต์อยู่แล้วและฟังก์ชันเฉพาะนี้ภายในสคริปต์ขนาดใหญ่นั้นสามารถเป็นค่าเริ่มต้นหรือกำหนดเองได้ เนื่องจากข้อมูลที่ จำกัด จาก OP ฉันไม่สามารถรู้ได้ว่าวิธีนี้ควรทำอย่างไร แต่ก็ปลอดภัยที่จะถือว่า OP ไม่ผ่านบูล
Inbar Rose

คำถามกล่าวอย่างชัดเจนว่า "ฉันมีสคริปต์ python ที่สามารถรับอาร์กิวเมนต์บรรทัดคำสั่งเป็นศูนย์หรือสาม" แต่ไม่ได้บอกว่า "ฉันมีฟังก์ชันที่ได้รับ 3 อาร์กิวเมนต์" เนื่องจากโมดูลอาร์กิวเมนต์เป็นวิธีที่ต้องการในการจัดการอาร์กิวเมนต์บรรทัดคำสั่งใน python จึงมีทุกอย่างที่เกี่ยวข้องกับคำถามโดยอัตโนมัติ สุดท้าย python คือ "รวมแบตเตอรี่" - ไม่มีข้อเสียใด ๆ สำหรับ "การเพิ่มการนำเข้าอื่น" เมื่อโมดูลนั้นเป็นส่วนหนึ่งของไลบรารีมาตรฐาน
wim

@wim คำถามค่อนข้างไม่ชัดเจน (ตัวอย่างเช่นเนื้อหาไม่ตรงกับชื่อเรื่อง) ฉันคิดว่าคำถามไม่ชัดเจนพอที่จะเป็นคำตอบที่ถูกต้องสำหรับการตีความบางอย่าง
คืนสถานะ Monica

2

หากคุณทำงานกับผู้ทำซ้ำเงื่อนไขอาจทำให้เข้าถึงได้ช้า แต่คุณไม่จำเป็นต้องเข้าถึงแต่ละองค์ประกอบมากกว่าหนึ่งครั้งและคุณไม่จำเป็นต้องอ่านทั้งหมดเสมอไป นี่คือวิธีแก้ปัญหาที่จะทำงานร่วมกับเครื่องกำเนิดไฟฟ้าที่ไม่มีที่สิ้นสุด:

#!/usr/bin/env python3
from random import randint
from itertools import tee

def generate_random():
    while True:
        yield bool(randint(0,1))

def any_but_not_all2(s): # elegant
    t1, t2 = tee(s)
    return False in t1 and True in t2 # could also use "not all(...) and any(...)"

def any_but_not_all(s): # simple
    hadFalse = False
    hadTrue = False
    for i in s:
        if i:
            hadTrue = True
        else:
            hadFalse = True
        if hadTrue and hadFalse:
            return True
    return False


r1, r2 = tee(generate_random())
assert any_but_not_all(r1)
assert any_but_not_all2(r2)

assert not any_but_not_all([True, True])
assert not any_but_not_all2([True, True])

assert not any_but_not_all([])
assert not any_but_not_all2([])

assert any_but_not_all([True, False])
assert any_but_not_all2([True, False])

0

เมื่อทุกที่กำหนดboolเป็นTrueหรือเมื่อได้รับทุกคนboolมีFalse ...
พวกเขาทั้งหมดจะเท่ากับแต่ละอื่น ๆ !

ดังนั้นเราต้องหาสององค์ประกอบที่ประเมินเป็นbools ที่ต่างกัน
เพื่อให้รู้ว่ามีอย่างน้อยหนึ่งอย่างTrueและอย่างน้อยหนึ่งFalseและที่หนึ่งอย่างน้อย

วิธีแก้ปัญหาสั้น ๆ ของฉัน:

not bool(a)==bool(b)==bool(c)

ฉันเชื่อว่ามันลัดวงจรทำให้ AFAIK a==b==cเท่ากับa==b and b==cเท่ากับ

วิธีแก้ปัญหาทั่วไปของฉัน:

def _any_but_not_all(first, iterable): #doing dirty work
    bool_first=bool(first)
    for x in iterable:
        if bool(x) is not bool_first:
            return True
    return False

def any_but_not_all(arg, *args): #takes any amount of args convertable to bool
    return _any_but_not_all(arg, args)

def v_any_but_not_all(iterable): #takes iterable or iterator
    iterator=iter(iterable)
    return _any_but_not_all(next(iterator), iterator)

ฉันเขียนโค้ดที่เกี่ยวข้องกับการวนซ้ำหลายรายการ แต่ฉันลบออกจากที่นี่เพราะฉันคิดว่ามันไม่มีจุดหมาย แต่มันยังคงมีอยู่ที่นี่


-2

โดยพื้นฐานแล้วเป็นฟังก์ชัน "บางส่วน (แต่ไม่ใช่ทั้งหมด)" (เมื่อเปรียบเทียบกับฟังก์ชันany()และall()ฟังก์ชันในตัว)

นี่หมายความว่าควรมีFalses และ True s อยู่ในผลลัพธ์ ดังนั้นคุณสามารถทำสิ่งต่อไปนี้:

some = lambda ii: frozenset(bool(i) for i in ii).issuperset((True, False))

# one way to test this is...
test = lambda iterable: (any(iterable) and (not all(iterable))) # see also http://stackoverflow.com/a/16522290/541412

# Some test cases...
assert(some(()) == False)       # all() is true, and any() is false
assert(some((False,)) == False) # any() is false
assert(some((True,)) == False)  # any() and all() are true

assert(some((False,False)) == False)
assert(some((True,True)) == False)
assert(some((True,False)) == True)
assert(some((False,True)) == True)

ข้อดีอย่างหนึ่งของรหัสนี้คือคุณต้องวนซ้ำเพียงครั้งเดียวผ่านรายการ (บูลีน) ที่เป็นผลลัพธ์

ข้อเสียอย่างหนึ่งคือนิพจน์ความจริงทั้งหมดเหล่านี้จะได้รับการประเมินเสมอและไม่ทำการลัดวงจรเหมือนตัวดำเนินการor/and


1
ฉันคิดว่านี่เป็นความซับซ้อนที่ไม่จำเป็น ทำไมต้องเป็น Frozenset แทนที่จะเป็นชุดเก่าธรรมดา? ทำไม.issupersetแทนที่จะตรวจสอบความยาว 2 boolไม่สามารถส่งคืนสิ่งอื่นนอกจาก True และ False ได้อยู่ดี เหตุใดจึงกำหนดแลมบ์ดา (อ่าน: ฟังก์ชันไม่ระบุชื่อ) ให้กับชื่อแทนที่จะใช้เพียงแค่ def?
Wim

1
ไวยากรณ์แลมบ์ดามีเหตุผลมากกว่าสำหรับบางคน พวกเขากำลังอยู่แล้วยาวเท่ากันตั้งแต่ที่คุณต้องการหากคุณใช้return defฉันคิดว่าโดยทั่วไปของโซลูชันนี้ดี ไม่จำเป็นที่จะต้อง จำกัด ตัวเองไว้ที่บูลีนคำถามคือ "ฉันจะแน่ใจได้อย่างไรว่าองค์ประกอบเหล่านี้เกิดขึ้นในรายการของฉัน" ทำไมsetถ้าคุณไม่ต้องการการเปลี่ยนแปลง? ความไม่เปลี่ยนรูปจะดีกว่าเสมอหากคุณไม่ต้องการประสิทธิภาพ
Janus Troelsen

@JanusTroelsen คุณถูกเป้าหมาย! นี่คือเหตุผลบางประการที่ทำให้ฉันทำแบบนี้ มันทำให้ฉันง่ายขึ้นและชัดเจนขึ้น ฉันมักจะปรับ Python ให้เข้ากับวิธีการเขียนโค้ด :-)
Abbafei

แต่มันใช้ไม่ได้กับเครื่องกำเนิดไฟฟ้าที่ไม่มีที่สิ้นสุด: P ดูคำตอบของฉัน :) คำใบ้:tee
Janus Troelsen

@JanusTroelsen ฉันตระหนักถึงสิ่งนี้ :-) ในตอนแรกฉันใช้วิธีอื่น (ด้วย True / False ในชุดและสามารถทำซ้ำได้ใน method param) แต่ตระหนักว่าสิ่งนี้จะใช้ไม่ได้กับเครื่องกำเนิดไฟฟ้าที่ไม่มีที่สิ้นสุดและผู้ใช้อาจไม่ทราบ (เนื่องจากข้อเท็จจริงนี้ไม่ใช่ (ยัง) ที่กล่าวถึงในเอกสารสำหรับพารามิเตอร์ชุดวิธีการทำซ้ำ) และอย่างน้อยก็จะเห็นได้ชัดว่าจะไม่ใช้ตัวทำซ้ำแบบไม่สิ้นสุด ฉันรู้itertools.teeแต่ 1) ฉันกำลังมองหาซับเดียวซึ่งเรียบง่าย / เล็กพอที่จะรับประกันการคัดลอกวาง 2) คุณได้ให้คำตอบซึ่งใช้เทคนิคนั้นแล้ว :-)
Abbafei
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.