Python idiom เพื่อส่งคืนไอเท็มแรกหรือไม่มี


274

ฉันแน่ใจว่ามีวิธีที่ง่ายกว่าในการทำเช่นนี้ซึ่งไม่ได้เกิดขึ้นกับฉัน

ฉันกำลังเรียกวิธีการมากมายที่ส่งคืนรายการ รายการอาจว่างเปล่า หากรายการไม่ว่างฉันต้องการส่งคืนรายการแรก; มิฉะนั้นฉันต้องการคืนค่าไม่มี รหัสนี้ใช้งานได้:

my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None

สำหรับฉันแล้วดูเหมือนว่าควรมีสำนวนแบบบรรทัดเดียวที่เรียบง่ายสำหรับการทำสิ่งนี้ แต่สำหรับชีวิตของฉันฉันไม่สามารถคิดได้ มีอะไรบ้าง

แก้ไข:

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

x = get_first_list()
if x:
    # do something with x[0]
    # inevitably forget the [0] part, and have a bug to fix
y = get_second_list()
if y:
    # do something with y[0]
    # inevitably forget the [0] part AGAIN, and have another bug to fix

สิ่งที่ฉันต้องการจะทำแน่นอนสามารถทำได้ด้วยฟังก์ชั่น (และอาจจะ):

def first_item(list_or_none):
    if list_or_none: return list_or_none[0]

x = first_item(get_first_list())
if x:
    # do something with x
y = first_item(get_second_list())
if y:
    # do something with y

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


28
btw บน Python 2.6+ คุณสามารถใช้next(iter(your_list), None)แทนการfirst_item(your_list)สมมติว่าyour_listไม่ใช่None( get_first_list()และget_second_list()จะต้องส่งคืน iterable เสมอ)
jfs

1
ฉันคิดว่าคุณหมายถึงnext(iter(your_list))เพราะถ้าคุณให้ข้อโต้แย้งครั้งที่สองiterคุณกำลังบอกว่าอาร์กิวเมนต์แรกนั้นสามารถเรียกได้
Robert Rossney

7
ไม่มีNoneนี่คือพารามิเตอร์ที่สองสำหรับการไม่ได้next() ส่งคืนพารามิเตอร์ตัวที่สองหากได้รับแทนที่จะเพิ่มถ้าว่าง iter()next()StopIterationyour_list
jfs

โซลูชันที่ @JFSebastian แนะนำมีอยู่พร้อมกับคำถามที่ซ้ำกัน: stackoverflow.com/a/18533669/144408
shahjapan

คำตอบ:


205

Python 2.6+

next(iter(your_list), None)

ถ้าyour_listสามารถNone:

next(iter(your_list or []), None)

Python 2.4

def get_first(iterable, default=None):
    if iterable:
        for item in iterable:
            return item
    return default

ตัวอย่าง:

x = get_first(get_first_list())
if x:
    ...
y = get_first(get_second_list())
if y:
    ...

ตัวเลือกอื่นคือการแทรกฟังก์ชั่นด้านบน:

for x in get_first_list() or []:
    # process x
    break # process at most one item
for y in get_second_list() or []:
    # process y
    break

เพื่อหลีกเลี่ยงbreakคุณสามารถเขียน:

for x in yield_first(get_first_list()):
    x # process x
for y in yield_first(get_second_list()):
    y # process y

ที่ไหน:

def yield_first(iterable):
    for item in iterable or []:
        yield item
        return

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

โอ้ฉันไม่ชอบสิ่งนี้เลย หากรายการใด ๆ ในรายการประเมินค่าเท็จค่านั้นจะถูกยกเลิกและแทนที่ ถ้าคุณมีสตริงที่ว่างเปล่าในรายการที่จะถูกยกเลิกไปและแทนที่ด้วยรายการที่ว่างเปล่า"" []หากคุณมี 0 []ยังถูกแทนที่ด้วย หากคุณมีFalseในนั้นก็เปลี่ยน ฯลฯ คุณอาจได้รับสิ่งนี้ในบางกรณี แต่นี่เป็นนิสัยที่ไม่ดีในการพัฒนา
steveha

4
@steveha: bool(lst) บอกเราว่าlen(lst) > 0มันไม่ได้บอกให้เราทราบอะไรเกี่ยวกับสิ่งที่รายการlstเช่นมี, bool([False]) == True;จึงแสดงออก[False] or []ผลตอบแทน[False]เดียวกันสำหรับมันผลตอบแทน[0] or [] [0]
jfs

@RobertRossney: ฉันได้เพิ่มyield_first()เพื่อหลีกเลี่ยงbreakคำสั่ง
jfs

1
@ThomasAhle: ทั้งคู่เป็นจริง ฉันได้อัปเดตคำตอบเพื่อให้การแก้ปัญหาสำหรับกรณีที่ไม่มี
jfs

218

วิธีที่ดีที่สุดคือ:

a = get_list()
return a[0] if a else None

คุณสามารถทำได้ในหนึ่งบรรทัด แต่มันยากสำหรับโปรแกรมเมอร์ที่จะอ่าน:

return (get_list()[:1] or [None])[0]

อุ่ย ควรจะกล่าวถึงนี้เป็นแอพ Python 2.4
Robert Rossney

15
@ Adam: อนาคตอาจใช้next(iter(your_list), None)
jfs

@JFSebastian จริงnext(iter(your_list))เพียงพอแล้ว
Brad Johnson

13
@BradleagheJohnson: ผิด มันเพิ่ม StopIteration แทนที่จะส่งกลับNoneเมื่อ OP ถาม ลอง: next(iter([])).
jfs

72
(get_list() or [None])[0]

ว่าควรจะทำงาน

BTW ฉันไม่ได้ใช้ตัวแปรlistเพราะมันเขียนทับlist()ฟังก์ชั่นบิวอิน

แก้ไข: ฉันมีรุ่นที่เรียบง่ายกว่าเล็กน้อย แต่ไม่ถูกต้องที่นี่ก่อนหน้านี้


4
นี่ฉลาดและใช้งานได้ดี แต่ฉันคิดว่า "return foo [0] ถ้า foo else None" ตามที่ efotinis แนะนำไว้นั้นง่ายต่อการบำรุงรักษา
Jay

3
คำถามกำลังถามหาทางออกหนึ่งบรรทัดดังนั้นฉันจึงตัดออก
recursive

นิพจน์เหล่านั้นไม่ทำงานถ้า get_list () ส่งคืน None คุณได้รับ "TypeError: วัตถุ 'NoneType' ไม่สามารถอธิบายได้" หรือ "TypeError: ประเภทตัวถูกดำเนินการที่ไม่รองรับสำหรับ +: 'NoneType' และ 'list'
Robert Rossney

4
ในคำถามมันบอกว่าวิธีการส่งกลับรายการซึ่งไม่มีใครไม่ใช่ ตามข้อกำหนดฉันยังเชื่อว่าทั้งคู่ทำงานได้ดี
เรียกซ้ำ

ควรใช้งานได้แล้วถ้า get_list () คืนค่า None เนื่องจากจะไม่ได้รับการห้อยหรือเพิ่มอีกต่อไป
Robert

32

วิธีที่ใช้สำนวนภาษาไพ ธ อนมากที่สุดคือการใช้ตัวถัดไป () บนตัววนซ้ำเนื่องจากรายการสามารถทำซ้ำได้ เช่นเดียวกับสิ่งที่ @JFSebastian แสดงความคิดเห็นในวันที่ 13 ธันวาคม 2011

next(iter(the_list), None)ผลตอบแทนนี้ไม่มีถ้าthe_listเป็นที่ว่างเปล่า ดูถัดไป () Python 2.6+

หรือถ้าคุณรู้ว่าthe_listไม่ว่าง:

iter(the_list).next()ดูiterator.next () Python 2.2+


1
นี่เป็นข้อดีที่คุณไม่ต้องกำหนดรายการของคุณให้กับตัวแปรเช่นreturn l[0] if l else Noneถ้ารายการนั้นเป็น libcomp เมื่อรายการเป็น genexpr นี้จะดียิ่งขึ้นเนื่องจากคุณไม่จำเป็นต้องสร้างรายการทั้งหมดในnext(iter(x for x in range(10) if x % 2 == 0), None)
RubenLaguna

หากคุณทราบว่าไม่ว่างคุณจะเขียนthe_list the_list[0]
kaya3

12

หากคุณพบว่าตัวเองพยายามถอนสิ่งแรก (หรือไม่มี) จากรายการความเข้าใจคุณสามารถสลับไปยังเครื่องกำเนิดไฟฟ้าเพื่อทำสิ่งที่ชอบ:

next((x for x in blah if cond), None)

Pro: ทำงานได้ถ้า blah ไม่สามารถจัดทำดัชนี Con: มันเป็นไวยากรณ์ที่ไม่คุ้นเคย มันมีประโยชน์ในขณะที่ทำการแฮ็กและกรองข้อมูลใน ipython


11

ทางออกของ OP ใกล้จะถึงแล้วมีเพียงไม่กี่อย่างเท่านั้นที่จะทำให้ Pythonic เป็นมากกว่า

สำหรับหนึ่งไม่จำเป็นต้องได้รับความยาวของรายการ รายการที่ว่างใน Python จะประเมินเป็น False ใน a if check เพียงแค่พูด

if list:

นอกจากนี้ยังเป็นแนวคิดที่ไม่ดีอย่างมากที่จะกำหนดให้กับตัวแปรที่ทับซ้อนกับคำที่สงวนไว้ "list" เป็นคำสงวนใน Python

งั้นลองเปลี่ยนมันเป็น

some_list = get_list()
if some_list:

จุดสำคัญจริงๆว่าจำนวนมากของการแก้ปัญหาที่นี่พลาดคือการที่ทุกฟังก์ชั่หลาม / วิธีกลับไม่มีโดยค่าเริ่มต้น ลองดังต่อไปนี้

def does_nothing():
    pass

foo = does_nothing()
print foo

ยกเว้นว่าคุณต้องการส่งคืน None เพื่อยกเลิกฟังก์ชั่นก่อน แต่ก็ไม่จำเป็นที่จะต้องส่งคืน None อย่างชัดเจน ค่อนข้างรัดกุมเพียงแค่ส่งคืนรายการแรกควรมีอยู่

some_list = get_list()
if some_list:
    return list[0]

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

def get_first_item(some_list): 
    if some_list:
        return list[0]

my_list = get_list()
first_item = get_first_item(my_list)

อย่างที่ฉันบอกว่า OP ใกล้จะถึงแล้วและมีเพียงไม่กี่สัมผัสที่ให้รสชาติของ Python ที่คุณต้องการ


1
ทำไม 'รายการ' คำที่สงวนไว้ในไพ ธ อน? หรือมากกว่านั้นในจุดที่มันบอกว่า 'รายการ' เป็นคำ reserver ในหลาม? หรืออีกประเด็นคุณยืนยันได้อย่างไรว่า 'รายการ' เป็นคำสงวนในไพ ธ อน? เมื่อพิจารณาว่าฉันสามารถประกาศตัวแปรชื่อ 'รายการ' ได้อย่างชัดเจนไม่ใช่คำที่สงวนไว้
Lasse V. Karlsen

2
จุดที่ถ่าย คำลิขสิทธิ์อย่างแท้จริงในหลามสามารถพบได้ที่นี่tinyurl.com/424663แต่ก็เป็นความคิดที่ดีที่จะพิจารณาในตัวฟังก์ชั่นและประเภทเป็นลิขสิทธิ์ list () สร้างรายการจริง กันไปสำหรับ dict, range, ฯลฯ
gotgenes

ฉันจะรวมสองบรรทัดสุดท้ายโดยกำจัดตัวแปรชั่วคราว (เว้นแต่คุณต้องการ my_list เพิ่มเติม) ที่ช่วยเพิ่มความสามารถในการอ่าน
Svante

นี่เป็นคำตอบที่ฉันอยากทำ
Robert Rossney

1
get_first_itemควรยอมรับdefaultพารามิเตอร์ (เช่นdict.get) ซึ่งมีค่าเริ่มต้นเป็น None ดังนั้นฟังก์ชั่นอินเทอร์เฟซสื่อสารอย่างชัดเจนว่าเกิดอะไรขึ้นถ้าmy_listว่างเปล่า
jfs

3
for item in get_list():
    return item

นี่คือรวบรัดและสวยงาม
gotgenes

น่าเศร้าที่มันไม่ทำงาน มันจะโยนวัตถุ "TypeError: 'NoneType' ไม่สามารถทำซ้ำได้ยกเว้นถ้า get_list () ส่งกลับไม่มี
Robert Rossney

วิธีแก้ไข: "สำหรับรายการใน get_list () หรือ []:"
itsadok

5
คำถามชัดเจนสันนิษฐานว่า get_list ส่งคืนรายการ len และgetitemถูกเรียกตามผลลัพธ์
A. Coady

2

พูดตรงไปตรงมาฉันไม่คิดว่ามีสำนวนที่ดีกว่า: คุณชัดเจนและกระชับ - ไม่จำเป็นต้องมีอะไร "ดีกว่า" บางที แต่นี้เป็นจริงเรื่องของรสชาติที่คุณสามารถเปลี่ยนif len(list) > 0:ด้วยif list:- รายการที่ว่างเปล่าจะประเมินการเท็จ

ในบันทึกย่อที่เกี่ยวข้อง Python ไม่ใช่ Perl (ไม่มีการเล่นสำนวนเจตนา!) คุณไม่จำเป็นต้องได้รหัสที่เยี่ยมที่สุดเท่าที่จะเป็นไปได้
จริงๆแล้วรหัสที่แย่ที่สุดที่ฉันเคยเห็นใน Python ก็คือ :-) ยอดเยี่ยมมาก

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


ในหลามก็ถือว่าเป็นรูปแบบที่ดีที่จะเขียนมากกว่าif lst: if len(lst) > 0:นอกจากนี้อย่าใช้คำสำคัญ Python เป็นชื่อตัวแปร มันจบลงด้วยน้ำตา เป็นเรื่องปกติที่จะใช้Lหรือlstเป็นชื่อตัวแปรสำหรับบางรายการ ฉันแน่ใจว่าในกรณีนี้คุณไม่ได้ตั้งใจจะแนะนำให้ใช้listชื่อตัวแปรจริง ๆคุณแค่หมายถึง "บางรายการ" และ +1 สำหรับ "เมื่อ lst [0] หาค่าเป็น False"
steveha

ใช่ฉันแค่รักษาชื่อ OP ไว้เหมือนเดิมเพื่อความชัดเจนที่ดีขึ้น แต่คุณพูดถูก: ควรระมัดระวังไม่ให้ลบคำหลักของ Python
ปล้น

2

Python idiom ที่จะคืนค่าไอเท็มแรกหรือไม่?

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

def get_first(l): 
    return l[0] if l else None

และถ้ารายการถูกส่งคืนจากget_listฟังก์ชัน:

l = get_list()
return l[0] if l else None

วิธีอื่นแสดงให้เห็นถึงการทำสิ่งนี้ที่นี่พร้อมคำอธิบาย

for

เมื่อฉันเริ่มพยายามคิดวิธีที่ฉลาดในการทำสิ่งนี้สิ่งที่สองที่ฉันคิดคือ

for item in get_list():
    return item

สิ่งนี้จะสันนิษฐานว่าฟังก์ชั่นสิ้นสุดที่นี่โดยปริยายคืนNoneถ้าget_listส่งกลับรายการที่ว่างเปล่า รหัสที่ชัดเจนด้านล่างเทียบเท่าอย่างแน่นอน:

for item in get_list():
    return item
return None

if some_list

ต่อไปนี้ยังได้รับการเสนอ (ฉันแก้ไขชื่อตัวแปรไม่ถูกต้อง) Noneซึ่งยังใช้โดยปริยาย สิ่งนี้จะดีกว่าที่กล่าวมาเนื่องจากใช้การตรวจสอบแบบลอจิคัลแทนการทำซ้ำที่อาจไม่เกิดขึ้น ควรเข้าใจได้ง่ายขึ้นในทันทีว่าเกิดอะไรขึ้น แต่ถ้าเราเขียนเพื่อความสามารถในการอ่านและการบำรุงรักษาเราควรเพิ่มความชัดเจนreturn Noneในตอนท้าย:

some_list = get_list()
if some_list:
    return some_list[0]

ฝานor [None]และเลือกดัชนีซีโรท

คำตอบนี้ได้รับการโหวตมากที่สุดด้วย:

return (get_list()[:1] or [None])[0]

Slice นั้นไม่จำเป็นและสร้างรายการพิเศษหนึ่งรายการในหน่วยความจำ ต่อไปนี้ควรมีประสิทธิภาพมากขึ้น ในการอธิบายให้orส่งคืนองค์ประกอบที่สองหากองค์ประกอบแรกอยู่Falseในบริบทบูลีนดังนั้นหากget_listส่งคืนรายการว่างเปล่านิพจน์ที่อยู่ในวงเล็บจะส่งคืนรายการด้วย 'ไม่มี' ซึ่งจะเข้าถึง0ดัชนีโดย:

return (get_list() or [None])[0]

รายการถัดไปใช้ข้อเท็จจริงและส่งคืนรายการที่สองหากรายการแรกอยู่Trueในบริบทบูลีนและเนื่องจากมันอ้างอิง my_list สองครั้งจึงไม่ดีไปกว่านิพจน์ประกอบไปด้วย (และในทางเทคนิคไม่ใช่ซับไลน์):

my_list = get_list() 
return (my_list and my_list[0]) or None

next

จากนั้นเรามีการใช้งานที่ชาญฉลาดของ builtin nextและiter

return next(iter(get_list()), None)

ในการอธิบายให้iterส่งคืนตัววนซ้ำด้วย.nextเมธอด ( .__next__ใน Python 3) จากนั้น builtin จะnextเรียก.nextใช้เมธอดนั้นและหากตัววนซ้ำหมดแล้วส่งคืนค่าเริ่มต้นที่เราNoneกำหนด

นิพจน์ประกอบไปด้วยซ้ำซ้อน ( a if b else c) และวนกลับ

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

return None if not get_list() else get_list()[0]

สิ่งที่ตรงกันข้ามที่ดีกว่า:

return get_list()[0] if get_list() else None

ยิ่งไปกว่านั้นให้ใช้ตัวแปรโลคอลเพื่อที่get_listจะเรียกได้เพียงครั้งเดียวเท่านั้นและคุณมีวิธีการแก้ปัญหาแบบ Pythonic ที่แนะนำครั้งแรก:

l = get_list()
return l[0] if l else None

2

เกี่ยวกับสำนวนมีสูตร itertoolsnthเรียกว่า

จากสูตร itertools:

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

หากคุณต้องการ one-liners ให้ลองติดตั้งไลบรารี่ที่ใช้สูตรนี้สำหรับคุณเช่นmore_itertools:

import more_itertools as mit

mit.nth([3, 2, 1], 0)
# 3

mit.nth([], 0)                                             # default is `None`
# None

มีเครื่องมืออีกชิ้นที่สามารถส่งคืนไอเท็มแรกmore_itertools.firstเท่านั้น

mit.first([3, 2, 1])
# 3

mit.first([], default=None)
# None

itertools เหล่านี้ขยายโดยทั่วไปสำหรับ iterable ใด ๆ ไม่เพียง แต่สำหรับรายการ



1

ฉันหมดเวลากับการแก้ปัญหาสองข้อด้วยความอยากรู้ วิธีแก้ปัญหาที่ใช้คำสั่ง return เพื่อสิ้นสุด a for loop ก่อนกำหนดนั้นมีค่าใช้จ่ายสูงกว่าเล็กน้อยในเครื่องของฉันด้วย Python 2.5.1 ฉันสงสัยว่านี่เกี่ยวข้องกับการตั้งค่า iterable

import random
import timeit

def index_first_item(some_list):
    if some_list:
        return some_list[0]


def return_first_item(some_list):
    for item in some_list:
        return item


empty_lists = []
for i in range(10000):
    empty_lists.append([])

assert empty_lists[0] is not empty_lists[1]

full_lists = []
for i in range(10000):
    full_lists.append(list([random.random() for i in range(10)]))

mixed_lists = empty_lists[:50000] + full_lists[:50000]
random.shuffle(mixed_lists)

if __name__ == '__main__':
    ENV = 'import firstitem'
    test_data = ('empty_lists', 'full_lists', 'mixed_lists')
    funcs = ('index_first_item', 'return_first_item')
    for data in test_data:
        print "%s:" % data
        for func in funcs:
            t = timeit.Timer('firstitem.%s(firstitem.%s)' % (
                func, data), ENV)
            times = t.repeat()
            avg_time = sum(times) / len(times)
            print "  %s:" % func
            for time in times:
                print "    %f seconds" % time
            print "    %f seconds avg." % avg_time

นี่คือเวลาที่ฉันได้รับ:

empty_lists:
  index_first_item:
    0.748353 วินาที
    0.741086 วินาที
    0.741191 วินาที
    เฉลี่ย 0.743543 วินาที
  return_first_item:
    0.785511 วินาที
    0.822178 วินาที
    0.782846 วินาที
    เฉลี่ย 0.796845 วินาทีเฉลี่ย
full_lists:
  index_first_item:
    0.762618 วินาที
    0.788040 วินาที
    0.786849 วินาที
    เฉลี่ย 0.779169 วินาที
  return_first_item:
    0.802735 วินาที
    0.878706 วินาที
    0.808781 วินาที
    เฉลี่ย 0.830074 วินาที
mixed_lists:
  index_first_item:
    0.791129 วินาที
    0.743526 วินาที
    0.744441 วินาที
    เฉลี่ย 0.759699 วินาที
  return_first_item:
    0.784801 วินาที
    0.785146 วินาที
    0.840193 วินาที
    เฉลี่ย 0.803380 วินาที

0
try:
    return a[0]
except IndexError:
    return None

1
โดยทั่วไปข้อยกเว้นจะไม่ใช้สำหรับการควบคุมการไหล
Matt Green

ฉันไม่คิดว่าจะทำให้รหัสนี้ยาวขึ้นและเพิ่มการจัดการข้อยกเว้นให้เป็นสำนวนที่ฉันกำลังมองหา
Robert Rossney

3
แต่นี่เป็นสำนวน Python ทั่วไป! ด้วยเหตุผลด้านประสิทธิภาพคุณอาจไม่ได้ใช้งาน คุณจะได้ประสิทธิภาพที่ดีขึ้นif len(a) > 0:แต่นี่ถือว่าเป็นรูปแบบที่ดี โปรดสังเกตว่านี่เป็นการแสดงออกถึงปัญหาได้ดีเพียงใด: "พยายามดึงส่วนหัวของรายการและหากวิธีนี้ไม่ได้ผลโปรดย้อนกลับNone" การค้นหาของ Google สำหรับ "EAFP" หรือดูที่นี่: python.net/~goodger/projects/pycon/2007/idiomatic/…
steveha

@steveha มันขึ้นอยู่กับข้อมูลของคุณ หาก len (a) โดยปกติ> 0 และ len (a) <1 เป็นสถานะที่หายากการจับข้อยกเว้นจะมีประสิทธิภาพมากกว่า
limscoder

@limscoder ฉันเห็นด้วยกับคุณ ฉันเพียงแค่ไม่ได้ลงรายละเอียดของเมื่อคุณอาจจะไม่ใช้มันสำหรับเหตุผลประสิทธิภาพ; ฉันไม่ได้บอกว่าคุณจะไม่ใช้สิ่งนี้
steveha

0
def head(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

print head(xrange(42, 1000)  # 42
print head([])               # None

BTW: ฉันจะปรับปรุงการไหลเวียนของโปรแกรมทั่วไปให้เป็นอย่างนี้:

lists = [
    ["first", "list"],
    ["second", "list"],
    ["third", "list"]
]

def do_something(element):
    if not element:
        return
    else:
        # do something
        pass

for li in lists:
    do_something(head(li))

(หลีกเลี่ยงการทำซ้ำเมื่อใดก็ตามที่เป็นไปได้)


0

เกี่ยวกับสิ่งนี้:

(my_list and my_list[0]) or None

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


เกี่ยวกับ([0,1] and 0) or None!
Kenly

นั่นเป็นจุดที่ดี ... ไม่ปลอดภัยที่จะใช้กับคอลเลกชันตัวเลขในรูปแบบปัจจุบัน :(
VitalyB

(['','A'] and '') or Noneสิ่งเดียวกันกับ
Kenly

หากmy_list[0]ได้รับการประเมินว่าเป็นผลที่ควรจะเป็นFalse None
Kenly

2
my_list[0] if len(my_list) else None
นิโคลัสแฮมิลตัน

0

ไม่แน่ใจว่าไพทอนเป็นแบบนี้ได้อย่างไรจนกระทั่งมีฟังก์ชั่นแรกในห้องสมุดฉันรวมสิ่งนี้ไว้ในซอร์ส:

first = lambda l, default=None: next(iter(l or []), default)

เป็นเพียงหนึ่งบรรทัด (สอดคล้องกับสีดำ) และหลีกเลี่ยงการอ้างอิง



-1

อาจไม่ใช่วิธีที่เร็วที่สุด แต่ไม่มีใครพูดถึงตัวเลือกนี้:

dict(enumerate(get_list())).get(0)

ถ้าget_list()สามารถกลับมาNoneคุณสามารถใช้:

dict(enumerate(get_list() or [])).get(0)

ข้อดี:

บรรทัดเดียว

- คุณแค่โทรget_list()ครั้งเดียว

- เข้าใจง่าย


-1

กรณีการใช้งานของฉันเป็นเพียงการตั้งค่าของตัวแปรท้องถิ่น

ส่วนตัวฉันพบความพยายามและยกเว้นตัวทำความสะอาดสไตล์ให้อ่าน

items = [10, 20]
try: first_item = items[0]
except IndexError: first_item = None
print first_item

กว่าการแบ่งรายการ

items = [10, 20]
first_item = (items[:1] or [None, ])[0]
print first_item

-1

หลายคนแนะนำให้ทำสิ่งนี้:

list = get_list()
return list and list[0] or None

ใช้งานได้ในหลายกรณี แต่จะใช้งานได้หากรายการ [0] ไม่เท่ากับ 0, เท็จหรือสตริงว่าง ถ้ารายการ [0] เป็น 0, เท็จหรือสตริงว่างวิธีจะส่งกลับไม่ถูกต้องไม่มี

ฉันได้สร้างข้อบกพร่องนี้ในรหัสของตัวเองหลายครั้งเกินไป!


3
นี่ควรเป็นความคิดเห็นภายใต้คำตอบที่มีข้อบกพร่องมากกว่าคำตอบแบบสแตนด์อะโลน
IJ Kennedy

-2

คุณสามารถใช้สารสกัดจากวิธี ในคำอื่น ๆ แยกรหัสนั้นเป็นวิธีที่คุณจะโทรแล้ว

ฉันจะไม่พยายามบีบอัดมันมากนัก liners ตัวเดียวดูเหมือนอ่านยากกว่าเวอร์ชั่น verbose และถ้าคุณใช้วิธีแยกมันเป็นหนึ่งซับ;)



-3

ไม่ได้เป็นงูหลามที่มีลักษณะคล้ายกับตัวดำเนินการที่ประกอบไปด้วย C

cond and true_expr or false_expr

กล่าวคือ

list = get_list()
return list and list[0] or None

ถ้า [0] เป็นตัวเลข 0 หรือสตริงว่าง (หรือสิ่งอื่นใดที่ประเมินว่าเป็นเท็จ) สิ่งนี้จะส่งคืน None แทนที่จะเป็น [0] จริง ๆ
Adam Rosenfield
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.