คุณสมบัติที่ซ่อนของ Python [ปิด]


1419

ฟีเจอร์ที่เป็นที่รู้จักน้อย แต่มีประโยชน์ของภาษาการเขียนโปรแกรม Python คืออะไร

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

ลิงก์ด่วนไปยังคำตอบ:

คำตอบ:


740

ตัวดำเนินการเปรียบเทียบการโยง:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

ในกรณีที่คุณกำลังคิดที่มันทำ1 < xซึ่งออกมาเป็นTrueแล้วเปรียบเทียบTrue < 10ซึ่งยังเป็นTrueแล้วไม่มีที่จริงไม่ได้เป็นสิ่งที่เกิดขึ้น (ดูตัวอย่างสุดท้าย.) มันจริงๆแปลเป็1 < x and x < 10และx < 10 and 10 < x * 10 and x*10 < 100แต่พิมพ์น้อยลงและแต่ละ เทอมถูกประเมินเพียงครั้งเดียว


121
มีประโยชน์มาก ควรเป็นมาตรฐานสำหรับทุกภาษา น่าเศร้าที่มันไม่ใช่
stalepretzel

8
คุณควรเพิ่มตัวอย่างที่คืนค่า false เช่นกัน เช่น >>> 10 <x <20 False
ShoeLace

19
สิ่งนี้ใช้กับโอเปอเรเตอร์การเปรียบเทียบอื่น ๆ ด้วยเช่นกันซึ่งบางครั้งผู้คนก็แปลกใจว่าทำไมรหัสเช่น (5 ใน [5] เป็นจริง) นั้นเป็นเท็จ (แต่มันไม่ไพเราะเลย
ไมล์

19
ดี แต่ระวังความเท่าเทียมกันเช่น 'ใน' และ '=' 'A ใน B == C ใน D' หมายถึง '(A ใน B) และ (B == C) และ (C ใน D)' ซึ่งอาจไม่คาดคิด
Charles Merriam

15
Azafe: การเปรียบเทียบของ LISP ทำงานได้ตามปกติ มันไม่ได้เป็นกรณีพิเศษเพราะไม่มีเรื่องอื่น ๆ (ที่เหมาะสม) (< 1 x 10)วิธีการตีความ คุณสามารถนำไปใช้กับข้อโต้แย้งเดียวเช่น(= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/ …
Ken

512

รับ python regex tree tree เพื่อดีบัก regex ของคุณ

นิพจน์ทั่วไปเป็นคุณลักษณะที่ยอดเยี่ยมของงูหลาม แต่การดีบั๊กมันอาจเป็นความเจ็บปวดและมันง่ายเกินไปที่จะทำผิด regex

โชคดีที่หลามสามารถพิมพ์ต้นไม้แยก regex โดยไม่มีเอกสารที่ผ่านการทดลองธงที่ซ่อนอยู่re.DEBUG(ที่จริง 128) re.compileเพื่อ

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

เมื่อคุณเข้าใจไวยากรณ์คุณสามารถสังเกตเห็นข้อผิดพลาดของคุณได้ มีเราจะเห็นว่าฉันลืมที่จะหลบหนีใน[][/font]

แน่นอนคุณสามารถรวมเข้ากับธงใด ๆ ที่คุณต้องการเช่นความคิดเห็น regexes:

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
ยกเว้นการแยกวิเคราะห์ HTML โดยใช้นิพจน์ทั่วไปนั้นช้าและเจ็บปวด แม้แต่โมดูลตัวแยกวิเคราะห์ 'html' ในตัวก็ไม่ได้ใช้ regexes เพื่อทำงานให้เสร็จ และหากโมดูล html ไม่เป็นที่พอใจของคุณมีโมดูลตัวแยกวิเคราะห์ XML / HTML มากมายที่ทำงานได้โดยไม่ต้องบูรณาการล้อ
BatchyX

ลิงก์ไปยังเอกสารประกอบของไวยากรณ์เอาต์พุตจะดีมาก
บุคลากร

1
นี่ควรเป็นส่วนที่เป็นทางการของ Python ไม่ใช่การทดลอง ... RegEx มักจะมีเล่ห์เหลี่ยมและสามารถติดตามสิ่งที่เกิดขึ้นมีประโยชน์จริงๆ
Cahit

460

การระบุ

ล้อมรอบ iterable ด้วย enumerate และมันจะให้ไอเท็มพร้อมกับดัชนี

ตัวอย่างเช่น:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

อ้างอิง:


56
ฉันประหลาดใจที่สิ่งนี้ไม่ได้ครอบคลุมในบทช่วยสอนที่พูดถึงรายการไพ ธ อน
Draemon

45
และตลอดเวลาที่ฉันเขียนโค้ดด้วยวิธีนี้: สำหรับฉันอยู่ในช่วง (len (a)): ... จากนั้นใช้ [i] เพื่อรับรายการปัจจุบัน
เฟอร์นันโดมาร์ติน

4
@ Berry Tsakala: สำหรับความรู้ของฉันมันไม่ได้คัดค้าน
JAB

23
อึศักดิ์สิทธิ์นี้น่ากลัว สำหรับฉันใน xrange (len (a)): เป็นสำนวนที่ฉันชอบที่สุด
บุคลากร

15
การแจกแจงสามารถเริ่มจากดัชนีโดยพลการไม่จำเป็น 0 ตัวอย่าง: 'สำหรับ i, รายการในแจกแจง ( รายการ , เริ่ม = 1): พิมพ์ i, รายการ' จะเริ่มนับจาก 1, ไม่ใช่ 0
dmitry_romanov

419

การสร้างวัตถุกำเนิด

ถ้าคุณเขียน

x=(n for n in foo if bar(n))

คุณสามารถออกจากตัวสร้างและกำหนดให้กับ x ตอนนี้มันหมายความว่าคุณสามารถทำได้

for n in x:

ข้อดีของการทำเช่นนี้คือคุณไม่จำเป็นต้องใช้พื้นที่เก็บข้อมูลระดับกลางซึ่งคุณจะต้องใช้ถ้าคุณทำ

x = [n for n in foo if bar(n)]

ในบางกรณีสิ่งนี้อาจทำให้ความเร็วเพิ่มขึ้นอย่างมาก

คุณสามารถเพิ่มจำนวนมากได้ถ้าข้อความต่อท้ายของตัวสร้างโดยทั่วไปแล้วทำซ้ำซ้อนกันสำหรับลูป:

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

คุณสามารถใช้รายการที่ซ้อนกันเพื่อความเข้าใจใช่ไหม?
shapr

54
สิ่งที่ควรทราบคือการประหยัดค่าใช้จ่ายของหน่วยความจำ ค่าจะถูกคำนวณตามความต้องการดังนั้นคุณจะไม่ได้รับผลลัพธ์ทั้งหมดของรายการความเข้าใจในหน่วยความจำ สิ่งนี้เป็นสิ่งที่พึงปรารถนาเป็นพิเศษหากคุณทำซ้ำในภายหลังในบางส่วนของความเข้าใจในรายการเท่านั้น
saffsd

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

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

4
คำตอบที่คล้ายกัน (ซ้ำ?): stackoverflow.com/questions/101268/hidden-features-of-python/ …หมายเหตุอย่างไรก็ตามคำตอบที่ฉันเชื่อมโยงที่นี่กล่าวถึงการนำเสนอที่ดีจริงๆเกี่ยวกับพลังของเครื่องกำเนิดไฟฟ้า คุณควรตรวจสอบมัน
Denilson Sá Maia

353

iter () สามารถโต้แย้งอาร์กิวเมนต์ได้

ตัวอย่างเช่น

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

iter(callable, until_value)ฟังก์ชั่นซ้ำ ๆ เรียกร้องcallableและผลตอบแทนถัวเฉลี่ยผลจนกว่าuntil_valueจะถูกส่งกลับ


ในฐานะมือใหม่ถึงงูใหญ่คุณช่วยอธิบายได้ไหมว่าทำไมlambdaคำหลักจึงจำเป็นที่นี่?
SiegeX

@SiegeX โดยไม่มีแลมบ์ดา f.read (1) จะถูกประเมิน (คืนค่าสตริง) ก่อนที่จะส่งผ่านไปยังฟังก์ชัน iter แลมบ์ดาจะสร้างฟังก์ชั่นนิรนามแทนและส่งผ่านไปยัง iter แทน
jmilloy

339

ระวังข้อโต้แย้งค่าเริ่มต้นที่ไม่แน่นอน

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

คุณควรใช้ค่า Sentinel แทน "ไม่ได้รับ" และแทนที่ด้วยค่าที่ไม่แน่นอนที่คุณต้องการเป็นค่าเริ่มต้น:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
นั่นเป็นคุณสมบัติที่ซ่อนอยู่อย่างน่ารังเกียจอีกอย่างหนึ่ง ฉันพบเจอมันเป็นครั้งคราว
Torsten Marek

77
foo.func_defaultsฉันพบนี้ง่ายมากที่จะเข้าใจเมื่อฉันได้เรียนรู้ว่าการขัดแย้งเริ่มต้นอยู่ในอันดับที่เป็นคุณลักษณะของการทำงานเช่น ซึ่งเป็น tuple เป็นไม่เปลี่ยนรูป
Robert Rossney

2
@grayger: เนื่องจากคำสั่ง def ถูกเรียกใช้งานอาร์กิวเมนต์จะถูกประเมินโดย interpreter สิ่งนี้จะสร้าง (หรือผูกใหม่) ชื่อของรหัสวัตถุ (ชุดของฟังก์ชัน) อย่างไรก็ตามอาร์กิวเมนต์เริ่มต้นจะถูกยกตัวอย่างเป็นวัตถุในเวลาที่กำหนด สิ่งนี้เป็นจริงทุกครั้งของวัตถุที่ผิดนัด แต่มีนัยสำคัญเท่านั้น (เปิดเผยความหมายที่มองเห็นได้) เมื่อวัตถุนั้นไม่แน่นอน ไม่มีทางที่จะผูกพันชื่ออาร์กิวเมนต์เริ่มต้นในการปิดฟังก์ชั่นได้อีกต่อไปแม้ว่าจะสามารถถูกแทนที่ได้อย่างชัดเจนสำหรับการโทรหรือฟังก์ชั่นทั้งหมดสามารถกำหนดใหม่ได้)
จิมเดนนิส

3
@Robert แน่นอนว่าอาร์กิวเมนต์ tuple อาจไม่เปลี่ยนรูป แต่วัตถุที่ชี้ไปนั้นไม่จำเป็นต้องเปลี่ยนแปลง
poolie

16
แฮ็คด่วนหนึ่งครั้งเพื่อทำให้การเริ่มต้นของคุณสั้นลงเล็กน้อย: x = x หรือ [] คุณสามารถใช้มันแทน 2 บรรทัดถ้าคำสั่ง
เดฟ mankoff

317

การส่งค่าไปยังฟังก์ชันตัวสร้าง เช่นมีฟังก์ชั่นนี้:

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

คุณสามารถ:

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

ตกลง สมมติว่านี่เป็นตัวอย่างที่น่ารังเกียจของฟีเจอร์ที่ซ่อนอยู่ของ Python :)
Rafał Dowgird

89
ในภาษาอื่น ๆ ฉันเชื่อว่าอุปกรณ์มหัศจรรย์นี้เรียกว่า "ตัวแปร"
finnw

5
coroutines ควร coroutines และกำเนิดควรเป็นตัวเองโดยไม่ต้องผสม ลิงค์ขนาดใหญ่และพูดคุยและตัวอย่างเกี่ยวกับสิ่งนี้ได้ที่นี่: dabeaz.com/coroutines
u0b34a0f6ae

31
@finnw: ตัวอย่างใช้สิ่งที่คล้ายกับตัวแปร อย่างไรก็ตามคุณลักษณะนี้สามารถใช้งานได้หลายวิธี ... ไม่เหมือนกับตัวแปร มันควรจะเห็นได้ชัดว่าความหมายที่คล้ายกันสามารถนำมาใช้โดยใช้วัตถุ (ชั้นเรียนดำเนินวิธีการโทรของงูใหญ่โดยเฉพาะอย่างยิ่ง)
จิมเดนนิส

4
นี่เป็นตัวอย่างเล็ก ๆ น้อย ๆ สำหรับผู้ที่ไม่เคยเห็นร่วมกัน ตัวอย่างที่ใช้ค่าเฉลี่ยที่รันอยู่โดยไม่มีความเสี่ยงของตัวแปรผลรวมล้นเป็นสิ่งที่ดี
Prashant Kumar

313

หากคุณไม่ต้องการใช้ช่องว่างเพื่อแสดงขอบเขตคุณสามารถใช้ C-style {} โดยการออก:

from __future__ import braces

122
นั่นคือความชั่วร้าย :)
Jason Baker

37
>>> จาก __future__ วงเล็บปีกกานำเข้าไฟล์ "<stdin>" บรรทัดที่ 1 ไวยากรณ์ผิดพลาด: ไม่มีโอกาส: P
Benjamin W. Smith Smith

40
นั่นเป็นการดูหมิ่น!
Berk D. Demir

335
ฉันคิดว่าเราอาจมีข้อผิดพลาดด้านการสร้างประโยคที่นี่ไม่ควรเป็น "จากวงเล็บปีกกา__past__นำเข้า" หรือไม่
Bill K

47
จาก__cruft__วงเล็บปีกกานำเข้า
Phillip B Oldham

305

อาร์กิวเมนต์ขั้นตอนในตัวดำเนินการแบ่ง ตัวอย่างเช่น:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

กรณีพิเศษx[::-1]เป็นสำนวนที่มีประโยชน์สำหรับ 'x กลับด้าน'

>>> a[::-1]
[5,4,3,2,1]

31
ที่ชัดเจนมากขึ้นในความคิดของฉันเป็นฟังก์ชั่นย้อนกลับ () รายการ >>> (กลับด้าน (ช่วง (4))) [3, 2, 1, 0]
Christian Oudard

3
แล้ววิธีการเขียน "สตริง ia นี้" [:: - 1] ในทางที่ดีขึ้น? ดูเหมือนจะไม่ช่วยกลับ
Tsakala Berry

24
ปัญหาของ reversed () คือมันคืนค่าตัววนซ้ำดังนั้นถ้าคุณต้องการรักษาชนิดของลำดับที่ย้อนกลับ (tuple, string, list, unicode, user types ... ) คุณต้องมีขั้นตอนเพิ่มเติมในการแปลงกลับ .
Rafał Dowgird

6
def reverse_string (สตริง): สตริงส่งคืน [:: - 1]
pi

4
@pi ฉันคิดว่าถ้าใครรู้พอที่จะนิยาม reverse_string ตามที่คุณมีใครสามารถปล่อย [:: - 1] ไว้ในโค้ดของคุณและรู้สึกสบายใจกับความหมายและความรู้สึกที่เหมาะสม
physicsmichael

289

ตกแต่ง

Decoratorsอนุญาตให้ห่อฟังก์ชั่นหรือวิธีการในฟังก์ชั่นอื่นที่สามารถเพิ่มฟังก์ชั่นการแก้ไขข้อโต้แย้งหรือผลลัพธ์ ฯลฯ คุณเขียนมัณฑนากรหนึ่งบรรทัดด้านบนนิยามฟังก์ชั่นเริ่มต้นด้วยเครื่องหมาย "at" (@)

ตัวอย่างแสดงprint_argsมัณฑนากรที่พิมพ์อาร์กิวเมนต์ของฟังก์ชั่นการตกแต่งก่อนที่จะเรียกมัน:

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
เมื่อกำหนดผู้ตกแต่งฉันอยากแนะนำให้ตกแต่งมัณฑนากรด้วย @decorator มันสร้างมัณฑนากรที่เก็บรักษาลายเซ็นฟังก์ชั่นเมื่อทำการวิปัสสนากับมัน ข้อมูลเพิ่มเติมได้ที่นี่: phyast.pitt.edu/~micheles/python/documentation.html
รัก

45
นี่เป็นคุณสมบัติที่ซ่อนอยู่ได้อย่างไร
Vetle

50
มันไม่ได้มีอยู่ในบทช่วยสอน Python ที่ง่ายที่สุดและฉันสะดุดมันนานหลังจากที่ฉันเริ่มใช้ Python นั่นคือสิ่งที่ฉันจะเรียกว่าคุณสมบัติที่ซ่อนอยู่ซึ่งคล้ายกับโพสต์ยอดนิยมอื่น ๆ ที่นี่
DzinX

16
vetler คำถามจะถามหา "คุณสมบัติที่มีประโยชน์น้อยกว่า แต่เป็นประโยชน์ของภาษาโปรแกรม Python" คุณวัด 'คุณสมบัติที่รู้จักน้อย แต่มีประโยชน์' ได้อย่างไร ฉันหมายถึงฟีเจอร์การตอบกลับใด ๆ ที่ซ่อนอยู่
Johnd

4
@vetler ส่วนใหญ่ของสิ่งที่นี่แทบจะไม่ "ซ่อน"
Humphrey Bogart

288

ไวยากรณ์สำหรับ ... else (ดูที่http://docs.python.org/ref/for.html )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

โดยปกติแล้วบล็อก "else" จะถูกดำเนินการในตอนท้ายของ for loop ยกเว้นว่ามีการแบ่ง

โค้ดด้านบนสามารถจำลองได้ดังต่อไปนี้:

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
ฉันคิดว่าไวยากรณ์ for / else อึดอัดใจ มัน "รู้สึก" ราวกับว่าประโยคอื่นควรจะดำเนินการถ้าร่างกายของลูปไม่เคยดำเนินการ
codeape

14
อา. ไม่เคยเห็นที่หนึ่ง! แต่ฉันต้องบอกว่ามันเป็นชื่อเรียกผิด ใครจะคาดหวังว่าบล็อกอื่นจะทำงานเมื่อไม่มีการหยุดพักเท่านั้น? ฉันเห็นด้วยกับ codeape: ดูเหมือนว่ามีการป้อนข้อมูลอื่นสำหรับ foos ที่ว่างเปล่า
Daren Thomas

52
ดูเหมือนว่าคำหลักควรจะเป็นในท้ายที่สุดไม่ใช่อย่างอื่น
Jiaaro

21
ยกเว้นว่าในที่สุดจะมีการใช้งานในลักษณะที่ชุดดังกล่าวจะถูกดำเนินการเสมอ

7
ไม่ควรเป็น 'อื่น' อย่างแน่นอน อาจจะ 'แล้ว' หรือบางสิ่งบางอย่างจากนั้นก็ 'อื่น ๆ ' เมื่อไม่มีการกระทำลูป
Tor Valamo

258

จาก 2.5 เป็นต้นไป dicts มีวิธีพิเศษ__missing__ที่เรียกใช้สำหรับรายการที่ขาดหายไป:

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

นอกจากนี้ยังมีคลาสย่อย dict ที่collectionsเรียกdefaultdictว่าคล้ายกันมาก แต่เรียกใช้ฟังก์ชันที่ไม่มีอาร์กิวเมนต์สำหรับรายการที่ไม่มีอยู่:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

ฉันขอแนะนำให้แปลง dicts ดังกล่าวเป็น dicts ปกติก่อนที่จะส่งผ่านไปยังฟังก์ชันที่ไม่ต้องการคลาสย่อยดังกล่าว รหัสจำนวนมากใช้d[a_key]และจับ KeyErrors เพื่อตรวจสอบว่ามีรายการอยู่หรือไม่ซึ่งจะเพิ่มรายการใหม่ให้กับ dict


10
ฉันชอบใช้ setdefault m = {}; m.setdefault ('foo', 1)
grayger

22
@grayger m={}; m.setdefault('foo', []).append(1)หมายนี้
Cristian Ciupitu

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

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

2
defaultdictมีประสิทธิภาพมากกว่าsetdefaultวิธีการในกรณีอื่น ๆ ตัวอย่างเช่นสำหรับเคาน์เตอร์VSdd = collections.defaultdict(int) ... dd[k] += 1 d.setdefault(k, 0) += 1
Mike Graham

247

การแลกเปลี่ยนค่าในสถานที่

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

ทางด้านขวาของการมอบหมายคือนิพจน์ที่สร้าง tuple ใหม่ ด้านซ้ายมือของงานทันทีที่ unpacks (unreferenced) tuple จะชื่อและab

หลังจากการมอบหมาย tuple ใหม่จะไม่ถูกอ้างถึงและทำเครื่องหมายสำหรับการรวบรวมขยะและค่าที่ผูกไว้กับaและbถูกสลับเป็น

ตามที่ระบุไว้ในส่วนการกวดวิชาหลามบนโครงสร้างข้อมูล ,

โปรดทราบว่าการมอบหมายหลายรายการเป็นเพียงการรวมกันของการบรรจุสิ่งอันดับและลำดับการเปิดออก


1
สิ่งนี้ใช้หน่วยความจำจริงมากกว่าแบบดั้งเดิมหรือไม่? ฉันเดาว่าคุณจะสร้าง tuple แทนที่จะเป็นเพียง swap swap ตัว
Nathan

75
มันไม่ได้ใช้หน่วยความจำเพิ่มเติม มันใช้น้อยกว่า .. ฉันเพิ่งเขียนทั้งสองวิธีและยกเลิกการคอมไพล์ bytecode .. คอมไพเลอร์ปรับให้เหมาะสมตามที่คุณหวังว่าจะเป็น ผลลัพธ์โรคแสดงให้เห็นว่ามันตั้งค่า vars แล้ว ROT_TWOing ROT_TWO แปลว่า 'สลับ vars ซ้อนกันมากที่สุดสองรายการ' ...
royal

5
นอกจากนี้คุณยังชี้ให้เห็นคุณลักษณะที่ดีอีกอย่างของ Python โดยไม่ได้ตั้งใจซึ่งคุณสามารถสร้างรายการโดยปริยายเพียงแค่คั่นด้วยเครื่องหมายจุลภาค
asmeurer

3
Dana the Sane: การมอบหมายใน Python เป็นคำสั่งไม่ใช่การแสดงออกดังนั้นการแสดงออกจะไม่ถูกต้องหาก = มีลำดับความสำคัญสูงกว่า (เช่นถูกตีความว่าเป็น a, (b = b), a)
hbn

5
นี่เป็นคุณสมบัติที่ซ่อนอยู่น้อยที่สุดที่ฉันได้อ่านที่นี่ ดี แต่ได้อธิบายไว้อย่างชัดเจนในทุกบทช่วยสอนของ Python
Thiago Chaves

235

นิพจน์ทั่วไปที่อ่านได้

ใน Python คุณสามารถแยกนิพจน์ปกติผ่านหลายบรรทัดตั้งชื่อการจับคู่และแทรกความคิดเห็น

ตัวอย่างไวยากรณ์ verbose (จากDive สู่ Python ):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

ตัวอย่างการตั้งชื่อการจับคู่ (จากปกตินิพจน์ HOWTO )

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

นอกจากนี้คุณยังสามารถเขียน regex อย่างละเอียดโดยไม่ต้องre.VERBOSEขอบคุณการต่อสตริงที่แท้จริง

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
ฉันไม่รู้ว่าฉันจะพิจารณาคุณลักษณะ Python จริง ๆ แล้วเครื่องมือ RE ส่วนใหญ่มีตัวเลือกอย่างละเอียด
Jeremy Banks

18
ใช่ แต่เนื่องจากคุณไม่สามารถทำได้ในแบบ grep หรือในบรรณาธิการส่วนใหญ่ผู้คนจำนวนมากไม่รู้ว่ามี ความจริงที่ว่าภาษาอื่นมีคุณสมบัติที่เทียบเท่ากันไม่ได้ทำให้มันไม่ได้เป็นคุณสมบัติที่มีประโยชน์และเป็นที่รู้จักน้อยในภาษาไพ ธ อน
Mark Baker

7
ในโครงการขนาดใหญ่ที่มีนิพจน์ทั่วไปที่ได้รับการปรับปรุง (อ่าน: ปรับให้เหมาะสมสำหรับเครื่องจักร แต่ไม่ใช่มนุษย์) ฉันจะแสดงหัวข้อย่อยและแปลงพวกเขาทั้งหมดเป็นไวยากรณ์ verbose ตอนนี้การแนะนำนักพัฒนาใหม่ให้กับโครงการง่ายขึ้นมาก จากนี้ไปเราบังคับใช้ verbose REs ในทุกโครงการ
Berk D. Demir

ฉันอยากจะบอกว่า: hundred = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD), ฯลฯ ภาษามีวิธีให้ชื่อสิ่งต่าง ๆ แล้ว วิธีเพิ่มความคิดเห็นและวิธีรวมสตริง เหตุใดจึงใช้ไวยากรณ์ไลบรารีพิเศษที่นี่เพื่อสิ่งที่ภาษาดำเนินไปด้วยดี ดูเหมือนว่าจะตรงกับ Perlis 'Epigram 9
Ken

3
@Ken: regex อาจไม่ได้อยู่ในแหล่งโดยตรงเสมอมันสามารถอ่านได้จากการตั้งค่าหรือไฟล์ config การอนุญาตให้แสดงความคิดเห็นหรือเพิ่มพื้นที่ว่าง (เพื่อให้สามารถอ่านได้) สามารถช่วยได้มาก

222

ฟังก์ชั่นการเปิดออกอาร์กิวเมนต์

คุณสามารถแกะรายการหรือพจนานุกรมเป็นข้อโต้แย้งฟังก์ชั่นการใช้เป็นและ***

ตัวอย่างเช่น:

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

ทางลัดที่มีประโยชน์มากตั้งแต่รายการ tuples และ dicts ถูกใช้อย่างกว้างขวางเป็นคอนเทนเนอร์


27
* เป็นที่รู้จักกันในชื่อตัวดำเนินการ
Gabriel

3
ฉันชอบคุณสมบัตินี้ แต่ไพลินท์ก็ไม่ได้เศร้า
สตีเฟ่นพอลเกอร์

5
คำแนะนำของ pylint ไม่ใช่กฎหมาย วิธีอื่นใช้ (callable, arg_seq, arg_map) เลิกใช้แล้วตั้งแต่ 2.3
Yann Vernier

1
คำแนะนำของ pylint อาจไม่ใช่กฎหมาย แต่เป็นคำแนะนำที่ดี การแก้จุดบกพร่องรหัสที่เกินกว่าความเป็นจริงนี่เป็นนรกที่แท้จริง ฐานะที่เป็นบันทึกโปสเตอร์เดิมนี้เป็นประโยชน์ทางลัด
แอนดรู

2
ฉันเห็นสิ่งนี้ถูกใช้ในรหัสครั้งเดียวและสงสัยว่ามันทำอะไร น่าเสียดายที่ google สำหรับ "Python **" ไม่ใช่เรื่องยาก
Fraser Graham

205

ROT13 เป็นการเข้ารหัสที่ถูกต้องสำหรับซอร์สโค้ดเมื่อคุณใช้การประกาศโค้ดที่ถูกต้องที่ด้านบนของไฟล์รหัส:

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
ที่ดี! สังเกตว่ามีการใช้สตริงไบต์อย่างแท้จริงอย่างไร, แต่มีการถอดรหัสสตริง Unicode: ลองcevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
น่าเสียดายที่มันถูกลบออกจาก py3k
mykhal

9
สิ่งนี้เป็นสิ่งที่ดีสำหรับการเลี่ยงไวรัส
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
นั่นไม่เกี่ยวอะไรกับการเข้ารหัสมันเป็นเพียงแค่ไพ ธ อนเขียนเป็นภาษาเวลส์ :-P
Olivier Verdier

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria

183

การสร้างประเภทใหม่ในลักษณะที่มีการเปลี่ยนแปลงอย่างสมบูรณ์

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

ซึ่งเหมือนกันทุกประการ

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

อาจไม่ใช่สิ่งที่มีประโยชน์ที่สุด แต่ก็น่ารู้

แก้ไข : ชื่อคงที่ของประเภทใหม่ควรNewTypeเป็นชื่อเดียวกันกับclassข้อความสั่ง

แก้ไข : ปรับชื่อเพื่ออธิบายคุณสมบัติได้อย่างแม่นยำมากขึ้น


8
สิ่งนี้มีศักยภาพที่เป็นประโยชน์มากมายเช่น JIT ORMs
Mark Cidade

8
ฉันใช้มันเพื่อสร้างคลาส HTML-Form โดยอิงจากอินพุตแบบไดนามิก ดีมาก!
ปี่

15
หมายเหตุ: คลาสทั้งหมดถูกสร้างขึ้นที่รันไทม์ ดังนั้นคุณสามารถใช้คำสั่ง 'คลาส' ภายในเงื่อนไขหรือภายในฟังก์ชัน (มีประโยชน์มากสำหรับการสร้างตระกูลของคลาสหรือคลาสที่ทำหน้าที่เป็นปิด) การปรับปรุงที่ 'type' นำมาใช้คือความสามารถในการกำหนดชุดแอตทริบิวต์ (หรือฐาน) ที่สร้างขึ้นแบบไดนามิก
spookylukey

1
นอกจากนี้คุณยังสามารถสร้างประเภทที่ไม่ระบุตัวตนด้วยสตริงว่างเช่น: type ('', (object,), {'x': 'blah'})
bluehavana

3
อาจมีประโยชน์มากสำหรับการฉีดรหัส
Avihu Turzion

179

ผู้จัดการบริบทและคำสั่ง " with"

นำมาใช้ในPEP 343ตัวจัดการบริบทคือวัตถุที่ทำหน้าที่เป็นบริบทรันไทม์สำหรับชุดคำสั่ง

เนื่องจากคุณลักษณะนี้ใช้ประโยชน์จากคำหลักใหม่จึงมีการนำมาใช้อย่างค่อยเป็นค่อยไป: มีให้บริการใน Python 2.5 ผ่าน__future__คำสั่ง Python 2.6 ขึ้นไป (รวมถึง Python 3) มีให้ใช้งานตามค่าเริ่มต้น

ฉันได้ใช้คำสั่ง "กับ"มากเพราะฉันคิดว่ามันเป็นโครงสร้างที่มีประโยชน์มากนี่คือตัวอย่างรวดเร็ว

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

สิ่งที่เกิดขึ้นที่นี่เบื้องหลังคือคำสั่ง "พร้อม"เรียกสิ่งพิเศษ__enter__และ__exit__วิธีการในวัตถุไฟล์ รายละเอียดข้อยกเว้นจะถูกส่งไปยัง__exit__หากมีข้อยกเว้นเกิดขึ้นจากเนื้อความของคำสั่งอนุญาตให้มีการจัดการข้อยกเว้นเกิดขึ้นที่นั่น

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

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


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

6
ใช่คุณสมบัติ "น่ารัก" เช่นขอบเขตและเครื่องกำเนิดไฟฟ้าจะดีกว่าสำหรับผู้ที่รู้ว่ากำลังทำอะไรอยู่ และใครก็ตามที่ต้องการเข้ากันได้กับ Python เวอร์ชันอนาคต สำหรับขอบเขตและตัวสร้างที่ซ้อนกัน "Python เวอร์ชันอนาคต" หมายถึง 2.2 และ 2.5 ตามลำดับ สำหรับคำสั่ง with, "รุ่นในอนาคต" ของ Python หมายถึง 2.6
Chris B.

10
นี้อาจจะไปโดยไม่บอก แต่มีงูหลาม v2.6 + คุณไม่จำเป็นต้องนำเข้าจากอนาคต ด้วยตอนนี้เป็นคำหลักชั้นหนึ่ง
fitzgeraldsteele

25
ใน 2.7 คุณสามารถมีได้หลายwiths:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson

5
@Austin ฉันไม่สามารถรับไวยากรณ์นั้นได้ที่ 2.7 แต่งานนี้ได้: with open('filea') as filea, open('fileb') as fileb: ...
Wim

168

พจนานุกรมมีวิธีการ get ()

พจนานุกรมมีวิธี 'รับ ()' หากคุณทำ d ['key'] และรหัสไม่อยู่ที่นั่นคุณจะได้รับการยกเว้น หากคุณใช้ d.get ('key') คุณจะไม่ได้รับอะไรเลยหาก 'key' ไม่อยู่ที่นั่น คุณสามารถเพิ่มอาร์กิวเมนต์ที่สองเพื่อรับรายการนั้นกลับมาแทน None เช่น: d.get ('key', 0)

มันยอดเยี่ยมสำหรับสิ่งต่าง ๆ เช่นการเพิ่มตัวเลข:

sum[value] = sum.get(value, 0) + 1


39
นอกจากนี้เช็คเอาต์วิธี setdefault
Daren Thomas

27
นอกจากนี้ยังมีการเช็คเอาต์คอลเลกชันเริ่มต้นเรียนระดับ
jfs

8
หากคุณใช้ Python 2.7 หรือใหม่กว่าหรือ 3.1 หรือใหม่กว่าให้ตรวจสอบคลาส Counter ในโมดูลคอลเล็กชัน docs.python.org/library/collections.html#collections.Counter
Elias Zamaria

get(key, None)โอ้คนนี้ตลอดเวลาที่ฉันได้ทำ ไม่มีความคิดที่Noneให้ไว้โดยค่าเริ่มต้น
Jordan Reiter

152

อธิบาย

พวกมันคือความมหัศจรรย์ที่อยู่เบื้องหลังฟีเจอร์หลักของ Python

เมื่อคุณใช้การเข้าถึงแบบจุดเพื่อค้นหาสมาชิก (เช่น xy) Python จะค้นหาสมาชิกในพจนานุกรมอินสแตนซ์ก่อน หากไม่พบมันจะค้นหาในพจนานุกรมคลาส หากพบว่ามันอยู่ในพจนานุกรมคลาสและวัตถุใช้โพรโทคอล descriptor แทนที่จะส่งคืน Python จะเรียกใช้มัน อธิบายเป็นชั้นใด ๆ ที่ดำเนินการ__get__, __set__หรือ__delete__วิธีการ

นี่คือวิธีที่คุณจะใช้คุณสมบัติของเวอร์ชัน (อ่านอย่างเดียว) ของคุณเองโดยใช้ descriptors:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

และคุณจะใช้มันเหมือนกับทรัพย์สินในตัว ():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

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

Raymond Hettinger มีบทช่วยสอนที่ยอดเยี่ยมซึ่งทำหน้าที่อธิบายได้ดีกว่าฉันมาก


นี่คือสิ่งที่ซ้ำกันของนักตกแต่งใช่ไหม! ( stackoverflow.com/questions/101268/… )
gecco

2
ไม่มัณฑนากรและผู้อธิบายเป็นสิ่งที่แตกต่างกันโดยสิ้นเชิงแม้ว่าในตัวอย่างโค้ดฉันกำลังสร้างมัณฑนากรตกแต่ง :)
Nick Johnson

1
วิธีอื่นในการทำเช่นนี้คือการใช้แลมบ์ดา:foo = property(lambda self: self.__foo)
พีทปีเตอร์สัน

1
@PetePeterson ใช่ แต่propertyตัวเองถูกนำไปใช้กับคำอธิบายซึ่งเป็นจุดโพสต์ของฉัน
Nick Johnson

142

การมอบหมายแบบมีเงื่อนไข

x = 3 if (y == 1) else 2

มันทำสิ่งที่ดูเหมือนว่า: "กำหนด 3 ถึง x ถ้า y เป็น 1 มิฉะนั้นกำหนด 2 ถึง x" โปรดทราบว่าไม่จำเป็นต้อง parens แต่ฉันชอบพวกเขาสำหรับการอ่าน คุณสามารถโยงมันได้หากคุณมีบางอย่างที่ซับซ้อนมากขึ้น:

x = 3 if (y == 1) else 2 if (y == -1) else 1

แม้ว่าจะถึงจุดหนึ่งมันก็ไกลไปหน่อย

โปรดทราบว่าคุณสามารถใช้ถ้า ... else ในนิพจน์ใด ๆ ก็ได้ ตัวอย่างเช่น:

(func1 if y == 1 else func2)(arg1, arg2) 

ที่นี่ func1 จะถูกเรียกถ้า y เป็น 1 และ func2 มิฉะนั้น ในทั้งสองกรณีฟังก์ชันที่เกี่ยวข้องจะถูกเรียกด้วยอาร์กิวเมนต์ arg1 และ arg2

อะนาล็อกต่อไปนี้ถูกต้องเช่นกัน:

x = (class1 if y == 1 else class2)(arg1, arg2)

โดยที่ class1 และ class2 เป็นสองคลาส


29
การมอบหมายไม่ใช่ส่วนพิเศษ คุณสามารถทำอะไรง่ายๆเช่น: คืน 3 ถ้า (y == 1) อื่น 2
Brian

25
ทางเลือกนั้นเป็นครั้งแรกที่ฉันได้เห็น Python ที่สับสน
Craig McQueen

3
Kylebrooks: ในกรณีนี้มันไม่ได้เป็นตัวดำเนินการบูลีนลัดวงจร มันจะประเมินเพียง 2 ถ้าบูล (3) == เท็จ
RoadieRich

15
การเขียนโค้ดแบบย้อนหลังนี้ทำให้ฉันสับสน สิ่งที่ต้องการx = ((y == 1) ? 3 : 2)ทำให้รู้สึกมากขึ้นกับผม
mpen

13
ฉันรู้สึกว่าตรงกันข้ามกับ @Mark ตัวดำเนินการประกอบแบบซีสไตล์มักจะทำให้ฉันสับสนอยู่เสมอด้านขวาหรือตรงกลางสิ่งที่ได้รับการประเมินในสภาพที่ผิด? ฉันชอบไวยากรณ์ส่วนที่สามของไพ ธ อนมาก
เจฟฟรีย์แฮร์ริส

141

Doctest : เอกสารและการทดสอบหน่วยในเวลาเดียวกัน

ตัวอย่างที่แยกจากเอกสาร Python:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
การสอนนั้นเจ๋งแน่นอน แต่ฉันไม่ชอบสิ่งที่คุณต้องพิมพ์เพื่อทดสอบว่ามีบางสิ่งที่จะทำให้เกิดข้อยกเว้น
TM

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

2
ใครบอกว่าคุณไม่สามารถตั้งค่าใน doctest ได้บ้าง เขียนฟังก์ชั่นที่สร้างบริบทและส่งคืนlocals()ใน doctest do locals().update(setUp())= D ของคุณ
Jiaaro

12
หากฟังก์ชั่นแบบสแตนด์อโลนต้องใช้การตั้งค่าโอกาสสูงที่มันจะถูกแยกออกจากสิ่งที่ไม่เกี่ยวข้องหรือนำไปใช้ในชั้นเรียน เนมสเปซของ Doctest ของคลาสสามารถนำกลับมาใช้ใหม่ในการสอนของเมธอดของคลาสดังนั้นมันจึงค่อนข้างคล้ายกับ setUp, DRY เท่านั้นและสามารถอ่านได้
Andy Mikhaylenko

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

138

การจัดรูปแบบที่มีชื่อ

การจัดรูปแบบ% ใช้พจนานุกรม (ยังใช้การตรวจสอบ% i /% s ฯลฯ )

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

และเนื่องจาก localals () เป็นพจนานุกรมคุณก็สามารถส่งมันเป็น dict และมี% -substitions จากตัวแปรโลคอลของคุณ ฉันคิดว่านี่เป็นเรื่องที่ขมวดคิ้ว แต่ทำให้สิ่งต่าง ๆ ง่ายขึ้น ..

การจัดรูปแบบสไตล์ใหม่

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
จะถูกแบ่งออกและในที่สุดก็ถูกแทนที่ด้วยวิธีการรูปแบบของสตริง ()
Constantin

3
การจัดรูปแบบที่มีชื่อมีประโยชน์มากสำหรับนักแปลเนื่องจากพวกเขามักจะเห็นสตริงรูปแบบโดยไม่มีชื่อตัวแปรสำหรับบริบท
pixelbeat

2
ดูเหมือนจะทำงานใน python 3.0.1 (จำเป็นต้องเพิ่มพาเรนต์เหล่านี้รอบ ๆ การเรียกใช้งานการพิมพ์)
Pasi Savolainen

9
กัญชาฮะ? ฉันเห็นว่าคุณมาจากไหน
shylent

11
การจัดรูปแบบ% s จะไม่ถูกยกเลิก str.format () แน่นอนว่าเป็น pythonic มากกว่าอย่างไรก็ตามจริง ๆ แล้วคือ 10x ช้าลงสำหรับการแทนที่สตริงแบบง่าย ๆ ความเชื่อของฉันคือการจัดรูปแบบ% s ยังคงเป็นแนวปฏิบัติที่ดีที่สุด
Kenneth Reitz

132

เพื่อเพิ่มโมดูลหลามเพิ่มเติม (โดยเฉพาะบุคคลที่สาม) คนส่วนใหญ่ดูเหมือนจะใช้ตัวแปรสภาพแวดล้อม PYTHONPATH หรือเพิ่ม symlink หรือไดเรกทอรีในไดเรกทอรีแพ็คเกจไซต์ อีกวิธีคือใช้ไฟล์ * .pth นี่คือคำอธิบายของ python doc อย่างเป็นทางการ:

"วิธีที่สะดวกที่สุด [เพื่อแก้ไขเส้นทางการค้นหาของ python] คือการเพิ่มไฟล์การกำหนดค่าพา ธ ไปยังไดเรกทอรีที่มีอยู่แล้วในเส้นทางของ Python โดยปกติไปที่ ... / site-packages / directory ไฟล์การกำหนดค่าพา ธ มีนามสกุล. pth และแต่ละบรรทัดจะต้องมีเส้นทางเดียวที่จะผนวกเข้ากับ sys.path (เนื่องจากเส้นทางใหม่ถูกผนวกเข้ากับ sys.path โมดูลในไดเรกทอรีที่เพิ่มจะไม่แทนที่โมดูลมาตรฐานซึ่งหมายความว่าคุณไม่สามารถใช้กลไกนี้ สำหรับการติดตั้งโมดูลมาตรฐานรุ่นคงที่) "


1
ฉันไม่เคยทำการเชื่อมต่อระหว่างไฟล์. pth นั้นในไดเรกทอรีแพ็คเกจไซต์จาก setuptools และแนวคิดนี้ น่ากลัว
paola

122

ข้อยกเว้นอื่น ๆ :

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

การใช้อนุประโยคอื่นดีกว่าการเพิ่มโค้ดเพิ่มเติมลงใน try clause เนื่องจากจะหลีกเลี่ยงการจับข้อยกเว้นที่ไม่ได้เกิดจากโค้ดที่ได้รับการปกป้องโดยคำสั่ง try ... ยกเว้น

ดูhttp://docs.python.org/tut/node10.html


8
+1 นี่มันสุดยอดมาก หากการลองบล็อกดำเนินการโดยไม่ต้องป้อนบล็อกข้อยกเว้นบล็อกอื่นจะถูกป้อน และแน่นอนว่าบล็อกสุดท้ายจะถูกดำเนินการ
inspectorG4dget

ในที่สุดฉันก็เข้าใจว่าทำไมจึงมี 'อื่น ๆ ' อยู่ที่นั่น! ขอบคุณ
taynaron

มันจะสมเหตุสมผลมากกว่าที่จะใช้งานต่อไป แต่ฉันคิดว่ามันใช้ไปแล้ว)
PawełPrażak

โปรดทราบว่าใน Python2 เวอร์ชั่นเก่าคุณไม่สามารถมีได้ทั้งสองอย่างและในที่สุด: ประโยคสำหรับลองแบบเดียวกัน: block
Kevin Horn

1
@ PawełPrażakดังที่เควินฮอร์นพูดถึงไวยากรณ์นี้ถูกนำมาใช้หลังจากการเริ่มต้นของ Python และการเพิ่มคำหลักที่สงวนไว้ใหม่ให้กับภาษาที่มีอยู่มักเป็นปัญหา นั่นเป็นเหตุผลที่มักจะนำคำหลักที่มีอยู่กลับมาใช้ใหม่ (cf "อัตโนมัติ" ในมาตรฐาน C ++ ล่าสุด)
Constantin

114

การเพิ่มข้อยกเว้นซ้ำ :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

คำสั่ง 'เพิ่ม' โดยไม่มีข้อขัดแย้งภายในตัวจัดการข้อผิดพลาดบอกให้ Python ยกข้อยกเว้นขึ้นอีกครั้งด้วยการติดตามกลับแบบเดิมซึ่งทำให้คุณสามารถพูดว่า "โอ้ขอโทษขอโทษฉันไม่ได้ตั้งใจจะขอโทษ "

หากคุณต้องการพิมพ์จัดเก็บหรือเล่นซอกับการสืบค้นกลับดั้งเดิมคุณสามารถรับมันได้ด้วย sys.exc_info () และการพิมพ์เหมือน Python จะทำด้วยโมดูล 'traceback'


ขออภัยนี่เป็นคุณสมบัติที่เป็นที่รู้จักและใช้กันทั่วไปในเกือบทุกภาษา
Lucas S.

6
หมายเหตุข้อความตัวเอียง บางคนจะทำraise eแทนซึ่งจะไม่รักษาย้อนกลับดั้งเดิม
habnabit

12
อาจจะมีมนต์ขลังมากขึ้นexc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]เทียบเท่ากับการนี้ แต่คุณสามารถเปลี่ยนค่าคนรอบข้าง (เช่นเปลี่ยนชนิดยกเว้นหรือข้อความ)
ianb

3
@Lucas S. เอาละฉันไม่รู้หรอกและฉันดีใจที่เขียนไว้ที่นี่
E-satis

ฉันอาจจะแสดงให้เห็นเยาวชนของฉันที่นี่ แต่ฉันได้ใช้หลาม 3 ไวยากรณ์ในหลาม 2.7 กับปัญหาไม่มีเสมอ
Wim

106

ข้อความหลัก :)

import this
# btw look at this module's source :)

ยกเลิกการเชื่อมโยง :

The Zen of Python โดย Tim Peters

สวยดีกว่าน่าเกลียด
ชัดเจนดีกว่าโดยปริยาย
เรียบง่ายดีกว่าซับซ้อน
คอมเพล็กซ์ดีกว่าซับซ้อน
แบนดีกว่าซ้อนกัน
เบาบางดีกว่าหนาแน่น
จำนวนการอ่าน
กรณีพิเศษไม่พิเศษพอที่จะทำลายกฎ
แม้ว่าการปฏิบัติจริงชนะความบริสุทธิ์
ข้อผิดพลาดไม่ควรผ่านไปอย่างเงียบ ๆ
เว้นแต่จะปิดเสียงอย่างชัดเจน
ในการเผชิญกับความกำกวมปฏิเสธสิ่งล่อใจที่จะคาดเดา ควรมีอย่างน้อยหนึ่งวิธีที่ชัดเจนกว่าที่จะทำ
แม้ว่าวิธีนี้อาจไม่ชัดเจนในตอนแรกเว้นแต่ว่าคุณเป็นชาวดัตช์
ตอนนี้ดีกว่าไม่เคย
แม้ว่าจะไม่เคยดีกว่าที่เหมาะสมในขณะนี้
หากการนำไปปฏิบัตินั้นยากที่จะอธิบายเป็นความคิดที่ไม่ดี
หากการนำไปปฏิบัตินั้นง่ายต่อการอธิบายอาจเป็นความคิดที่ดี
Namespaces เป็นหนึ่งในแนวคิดที่ยอดเยี่ยม - ลองทำสิ่งเหล่านี้ให้มากขึ้น!


1
มีความคิดใดบ้างที่ว่าทำไมแหล่งกำเนิดถูกทำให้เป็นเช่นนั้น? มันเพื่อความสนุกหรือมีเหตุผลอื่นอีกไหม?
MiniQuark

42
วิธีที่แหล่งกำเนิดนั้นเขียนไปเทียบกับเซน!
hasen


2
ฉันได้อัปเดต /usr/lib/python2.6/this.py ของฉันเพื่อแทนที่โค้ดเก่าด้วยรหัสนี้print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))และตอนนี้ดูดีขึ้นมาก !! :-D
fortran

2
@MiniQuark: บทเรียนประวัติย่อ: wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

การแปลแท็บ Interactive Interpreter

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

คุณจะต้องตั้งค่าตัวแปรสภาพแวดล้อม PYTHONSTARTUP


2
นี่เป็นคุณสมบัติที่มีประโยชน์มาก มากดังนั้นฉันมีสคริปต์ง่าย ๆ เพื่อเปิดใช้งาน (รวมถึงการปรับปรุงวิปัสสนาอื่น ๆ สองสาม): pixelbeat.org/scripts/inpy
pixelbeat

43
IPython ให้สิ่งนี้บวกกับสิ่งอื่น ๆ ที่เป็นระเบียบอีกมากมายให้คุณ
Akaihola

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

2
@haridsv - easy_install ipdb- จากนั้นคุณสามารถใช้import ipdb; ipdb.set_trace()
Doug Harris

1
ใน OSX [และฉันคิดระบบอื่น ๆ ซึ่งใช้ libedit] ที่คุณต้องทำreadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

ความเข้าใจในรายการแบบซ้อนและนิพจน์ตัวสร้าง:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

สิ่งเหล่านี้สามารถแทนที่โค้ดที่ซ้อนกันจำนวนมาก


"สำหรับ j อยู่ในช่วง (i)" - นี่เป็นตัวพิมพ์ผิดหรือไม่? โดยปกติคุณต้องการช่วงที่แน่นอนสำหรับ i และ j หากคุณเข้าถึงอาร์เรย์ 2 มิติคุณจะพลาดองค์ประกอบครึ่งหนึ่งของคุณ
34990 Peter

ฉันไม่ได้เข้าถึงอาร์เรย์ในตัวอย่างนี้ จุดประสงค์เดียวของรหัสนี้คือการแสดงให้เห็นว่านิพจน์จากช่วงภายในสามารถเข้าถึงได้จากนิพจน์ภายนอก ผลพลอยได้คือรายการของคู่ (x, y) ที่ 4> x> y> 0
Rafał Dowgird

2
sorta เช่นการรวมสองครั้งในแคลคูลัสหรือการรวมสองครั้ง
Yoo

22
จุดสำคัญที่ต้องจำที่นี่ (ซึ่งใช้เวลานานในการตระหนักถึงฉัน) คือคำสั่งของforงบจะต้องเขียนตามลำดับที่คุณคาดหวังว่าพวกเขาจะเขียนในมาตรฐานสำหรับวงจากภายนอกเข้ามา
sykora

2
ในการเพิ่มความคิดเห็นของ sykora: ลองจินตนาการว่าคุณเริ่มต้นด้วยสแต็กfors และifs yield xภายใน หากต้องการแปลงเป็นนิพจน์ตัวสร้างให้ย้ายxก่อนลบโคลอนทั้งหมด (และyield) และล้อมรอบสิ่งทั้งหมดในวงเล็บ หากต้องการสร้างรายการความเข้าใจแทนให้แทนที่ parens ด้านนอกด้วยวงเล็บเหลี่ยม
Ken Arnold

91

ผู้ประกอบการมากไปสำหรับsetbuiltin:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

รายละเอียดเพิ่มเติมจากการอ้างอิงไลบรารีมาตรฐาน: Set Types


ในบทช่วยสอนบางส่วนdocs.python.org/tutorial/datastructures.html#sets
XTL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.