portaldacalheta.pt
  • หลัก
  • กระบวนการและเครื่องมือ
  • การวางแผนและการพยากรณ์
  • การออกแบบ Ui
  • การจัดการโครงการ
เทคโนโลยี

Buggy Python Code: 10 ข้อผิดพลาดทั่วไปที่นักพัฒนา Python ทำ



เกี่ยวกับ Python

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

เกี่ยวกับบทความนี้

ไวยากรณ์ที่เรียบง่ายและเรียนรู้ง่ายของ Python อาจทำให้เข้าใจผิดได้ นักพัฒนา Python - โดยเฉพาะอย่างยิ่งผู้ที่ยังใหม่กับภาษา - พลาดรายละเอียดปลีกย่อยบางอย่างและประเมินพลังของ ภาษา Python ที่หลากหลาย .



ด้วยเหตุนี้บทความนี้จึงนำเสนอรายการ '10 อันดับแรก' ของข้อผิดพลาดที่ค่อนข้างละเอียดอ่อนและจับต้องได้ยากกว่าที่สามารถกัดได้มากขึ้น นักพัฒนา Python ขั้นสูง ด้านหลัง



(หมายเหตุ: บทความนี้จัดทำขึ้นสำหรับผู้ชมขั้นสูงมากกว่า ข้อผิดพลาดทั่วไปของโปรแกรมเมอร์ Python ซึ่งมุ่งเน้นไปที่ผู้ที่ใช้ภาษาใหม่มากกว่า)



ข้อผิดพลาดทั่วไป # 1: การใช้นิพจน์ในทางที่ผิดเป็นค่าเริ่มต้นสำหรับอาร์กิวเมนต์ของฟังก์ชัน

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

>>> def foo(bar=[]): # bar is optional and defaults to [] if not specified ... bar.append('baz') # but this line could be problematic, as we'll see... ... return bar

ข้อผิดพลาดทั่วไปคือการคิดว่าอาร์กิวเมนต์ทางเลือกจะถูกตั้งค่าเป็นนิพจน์เริ่มต้นที่ระบุ แต่ละครั้ง ฟังก์ชันนี้ถูกเรียกโดยไม่ต้องระบุค่าสำหรับอาร์กิวเมนต์ที่เป็นทางเลือก ตัวอย่างเช่นในโค้ดด้านบนอาจมีคนคาดหวังว่าจะเรียก foo() ซ้ำ ๆ (เช่นโดยไม่ระบุ bar อาร์กิวเมนต์) จะส่งกลับ 'baz' เสมอเนื่องจากสมมติฐานจะเป็นเช่นนั้น แต่ละครั้ง foo() ถูกเรียกว่า (โดยไม่มี bar อาร์กิวเมนต์ระบุ) bar ถูกตั้งค่าเป็น [] (เช่นรายการว่างใหม่)



แต่มาดูสิ่งที่เกิดขึ้นจริงเมื่อคุณทำสิ่งนี้:

>>> foo() ['baz'] >>> foo() ['baz', 'baz'] >>> foo() ['baz', 'baz', 'baz']

ฮะ? เหตุใดจึงต่อท้ายค่าเริ่มต้นของ 'baz' เป็น ที่มีอยู่เดิม รายชื่อทุกครั้ง foo() ถูกเรียกว่าแทนที่จะสร้างไฟล์ ใหม่ รายการแต่ละครั้ง?



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

FYI วิธีแก้ปัญหาทั่วไปสำหรับสิ่งนี้มีดังนี้:



>>> def foo(bar=None): ... if bar is None: # or if not bar: ... bar = [] ... bar.append('baz') ... return bar ... >>> foo() ['baz'] >>> foo() ['baz'] >>> foo() ['baz']

ข้อผิดพลาดทั่วไป # 2: การใช้ตัวแปรคลาสไม่ถูกต้อง

พิจารณาตัวอย่างต่อไปนี้:

อุตสาหกรรมความงามมีมูลค่าเท่าไหร่ในปี 2018
>>> class A(object): ... x = 1 ... >>> class B(A): ... pass ... >>> class C(A): ... pass ... >>> print A.x, B.x, C.x 1 1 1

มีเหตุผล.



>>> B.x = 2 >>> print A.x, B.x, C.x 1 2 1

ใช่อีกครั้งตามที่คาดไว้

>>> A.x = 3 >>> print A.x, B.x, C.x 3 2 3

อะไร $% #! & ?? แค่เราเปลี่ยน A.x. ทำไม C.x เปลี่ยนด้วย?



ใน Python ตัวแปรคลาสจะถูกจัดการภายในเป็นพจนานุกรมและทำตามสิ่งที่มักเรียกกันว่า วิธีการแก้ปัญหา (MRO) . ดังนั้นในโค้ดด้านบนตั้งแต่แอตทริบิวต์ x ไม่พบในคลาส C มันจะถูกค้นหาในคลาสพื้นฐาน (เฉพาะ A ในตัวอย่างข้างต้นแม้ว่า Python จะรองรับการสืบทอดหลายรายการ) กล่าวอีกนัยหนึ่ง C ไม่มี x ของตัวเอง คุณสมบัติไม่ขึ้นกับ A. ดังนั้นการอ้างอิงถึง C.x มีการอ้างอิงถึง A.x สิ่งนี้ทำให้เกิดปัญหา Python เว้นแต่จะได้รับการจัดการอย่างเหมาะสม เรียนรู้เพิ่มเติมเกี่ยวกับ แอตทริบิวต์คลาสใน Python .

ข้อผิดพลาดทั่วไป # 3: การระบุพารามิเตอร์ไม่ถูกต้องสำหรับบล็อกข้อยกเว้น

สมมติว่าคุณมีรหัสต่อไปนี้:

>>> try: ... l = ['a', 'b'] ... int(l[2]) ... except ValueError, IndexError: # To catch both exceptions, right? ... pass ... Traceback (most recent call last): File '', line 3, in IndexError: list index out of range

ปัญหาก็คือ except คำสั่งไม่ ไม่ รับรายการข้อยกเว้นที่ระบุในลักษณะนี้ แต่ใน Python 2.x ไวยากรณ์ except Exception, e ใช้เพื่อผูกข้อยกเว้นกับไฟล์ ไม่จำเป็น ระบุพารามิเตอร์ที่สอง (ในกรณีนี้ e) เพื่อให้สามารถตรวจสอบเพิ่มเติมได้ ด้วยเหตุนี้ในโค้ดด้านบนจึงเป็น IndexError ข้อยกเว้นคือ ไม่ ถูกจับโดย except คำให้การ; แต่ข้อยกเว้นกลับถูกผูกไว้กับพารามิเตอร์ชื่อ IndexError

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

>>> try: ... l = ['a', 'b'] ... int(l[2]) ... except (ValueError, IndexError) as e: ... pass ... >>>

ข้อผิดพลาดทั่วไป # 4: เข้าใจผิดกฎขอบเขต Python

ความละเอียดขอบเขต Python ขึ้นอยู่กับสิ่งที่เรียกว่า LEGB กฎซึ่งเป็นชวเลขสำหรับ ล ocal, คือ การปิดจมูก ช โลบอล ข uilt-in. ดูเหมือนตรงไปตรงมาพอใช่มั้ย? จริงๆแล้วมีรายละเอียดปลีกย่อยบางอย่างเกี่ยวกับวิธีการทำงานใน Python ซึ่งนำเราไปสู่ปัญหาการเขียนโปรแกรม Python ขั้นสูงทั่วไปด้านล่าง พิจารณาสิ่งต่อไปนี้:

>>> x = 10 >>> def foo(): ... x += 1 ... print x ... >>> foo() Traceback (most recent call last): File '', line 1, in File '', line 2, in foo UnboundLocalError: local variable 'x' referenced before assignment

มีปัญหาอะไร?

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

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

เป็นเรื่องปกติโดยเฉพาะอย่างยิ่งสำหรับสิ่งนี้ในการเพิ่มจำนวนนักพัฒนาเมื่อใช้ รายการ . พิจารณาตัวอย่างต่อไปนี้:

>>> lst = [1, 2, 3] >>> def foo1(): ... lst.append(5) # This works ok... ... >>> foo1() >>> lst [1, 2, 3, 5] >>> lst = [1, 2, 3] >>> def foo2(): ... lst += [5] # ... but this bombs! ... >>> foo2() Traceback (most recent call last): File '', line 1, in File '', line 2, in foo UnboundLocalError: local variable 'lst' referenced before assignment

ฮะ? ทำไม foo2 ขณะระเบิด foo1 วิ่งได้ดี?

คำตอบนั้นเหมือนกับในปัญหาตัวอย่างก่อนหน้า แต่เป็นที่ยอมรับว่าละเอียดกว่า foo1 ไม่ได้สร้างไฟล์ การมอบหมาย ถึง lst, ในขณะที่ foo2 คือ. จำไว้ว่า lst += [5] เป็นเพียงการชวเลขสำหรับ lst = lst + [5] เราเห็นว่าเรากำลังพยายาม กำหนด ค่าเป็น lst (ดังนั้นจึงถือว่า Python อยู่ในขอบเขตท้องถิ่น) อย่างไรก็ตามค่าที่เราต้องการกำหนดให้ lst ขึ้นอยู่กับ lst (อีกครั้งตอนนี้สันนิษฐานว่าอยู่ในขอบเขตท้องถิ่น) ซึ่งยังไม่ได้กำหนด บูม

ข้อผิดพลาดทั่วไป # 5: การแก้ไขรายการในขณะที่ทำซ้ำ

ปัญหาเกี่ยวกับรหัสต่อไปนี้ควรชัดเจนพอสมควร:

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> for i in range(len(numbers)): ... if odd(numbers[i]): ... del numbers[i] # BAD: Deleting item from a list while iterating over it ... Traceback (most recent call last): File '', line 2, in IndexError: list index out of range

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

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

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all >>> numbers [0, 2, 4, 6, 8]

ข้อผิดพลาดทั่วไป # 6: สับสนว่า Python ผูกตัวแปรในการปิดอย่างไร

พิจารณาตัวอย่างต่อไปนี้:

>>> def create_multipliers(): ... return [lambda x : i * x for i in range(5)] >>> for multiplier in create_multipliers(): ... print multiplier(2) ...

คุณอาจคาดหวังผลลัพธ์ต่อไปนี้:

0 2 4 6 8

แต่คุณจะได้รับ:

8 8 8 8 8

เซอร์ไพรส์!

สิ่งนี้เกิดขึ้นเนื่องจาก Python ผูกพันล่าช้า พฤติกรรมที่บอกว่าค่าของตัวแปรที่ใช้ในการปิดจะถูกค้นหาในเวลาที่ฟังก์ชันภายในถูกเรียกใช้ ดังนั้นในโค้ดด้านบนเมื่อใดก็ตามที่มีการเรียกฟังก์ชันที่ส่งคืนค่าของ i ถูกค้นหา ในขอบเขตโดยรอบในเวลาที่เรียก (และจากนั้นลูปก็เสร็จสมบูรณ์ดังนั้น i จึงถูกกำหนดค่าสุดท้ายเป็น 4)

วิธีแก้ปัญหา Python ทั่วไปนี้เป็นการแฮ็กเล็กน้อย:

>>> def create_multipliers(): ... return [lambda x, i=i : i * x for i in range(5)] ... >>> for multiplier in create_multipliers(): ... print multiplier(2) ... 0 2 4 6 8

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

ข้อผิดพลาดทั่วไป # 7: การสร้างการพึ่งพาโมดูลแบบวงกลม

สมมติว่าคุณมีสองไฟล์ a.py และ b.py ซึ่งแต่ละรายการจะนำเข้าข้อมูลอื่น ๆ ดังนี้:

ใน a.py:

import b def f(): return b.x print f()

และใน b.py:

import a x = 1 def g(): print a.f()

ก่อนอื่นมาลองนำเข้า a.py:

>>> import a 1

ทำงานได้ดี บางทีนั่นอาจทำให้คุณประหลาดใจ ท้ายที่สุดเรามีการนำเข้าแบบวงกลมที่นี่ซึ่งน่าจะเป็นปัญหาใช่หรือไม่

มีอะไรใหม่ใน php 7

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

ดังนั้นกลับไปที่ตัวอย่างของเราเมื่อเรานำเข้า a.py มันไม่มีปัญหาในการนำเข้า b.py ตั้งแต่ b.py ไม่ต้องการอะไรจาก a.py ที่จะกำหนด ในเวลาที่นำเข้า . ข้อมูลอ้างอิงเดียวใน b.py ถึง a คือการโทรไปที่ a.f(). แต่สายนั้นอยู่ใน g() และไม่มีอะไรใน a.py หรือ b.py เรียก g(). ชีวิตจึงดี

แต่จะเกิดอะไรขึ้นถ้าเราพยายามนำเข้า b.py (โดยไม่เคยนำเข้ามาก่อน a.py นั่นคือ):

>>> import b Traceback (most recent call last): File '', line 1, in File 'b.py', line 1, in import a File 'a.py', line 6, in print f() File 'a.py', line 4, in f return b.x AttributeError: 'module' object has no attribute 'x'

เอ่อโอ้. ไม่ดีแน่! ปัญหาคือในกระบวนการนำเข้า b.py จะพยายามนำเข้า a.py ซึ่งจะเรียก f() ซึ่งพยายามเข้าถึง b.x แต่ b.x ยังไม่ได้กำหนด ดังนั้น AttributeError ข้อยกเว้น

อย่างน้อยหนึ่งวิธีแก้ปัญหานี้เป็นเรื่องเล็กน้อย เพียงแค่ปรับเปลี่ยน b.py เพื่อนำเข้า a.py ภายใน g():

x = 1 def g(): import a # This will be evaluated only when g() is called print a.f()

ไม่เมื่อเรานำเข้าทุกอย่างเรียบร้อยดี:

>>> import b >>> b.g() 1 # Printed a first time since module 'a' calls 'print f()' at the end 1 # Printed a second time, this one is our call to 'g'

ข้อผิดพลาดทั่วไป # 8: ชื่อที่ปะทะกับโมดูล Python Standard Library

ความสวยงามอย่างหนึ่งของ Python คือโมดูลไลบรารีมากมายที่มาพร้อมกับ 'นอกกรอบ' แต่ด้วยเหตุนี้หากคุณไม่ได้หลีกเลี่ยงอย่างมีสติก็ไม่ยากที่จะพบการปะทะกันระหว่างชื่อของโมดูลหนึ่งของคุณและโมดูลที่มีชื่อเดียวกันในไลบรารีมาตรฐานที่มาพร้อมกับ Python (ตัวอย่างเช่น คุณอาจมีโมดูลชื่อ email.py ในโค้ดของคุณซึ่งจะขัดแย้งกับโมดูลไลบรารีมาตรฐานที่มีชื่อเดียวกัน)

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

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

ข้อผิดพลาดทั่วไป # 9: ไม่สามารถระบุความแตกต่างระหว่าง Python 2 และ Python 3

พิจารณาไฟล์ต่อไปนี้ foo.py:

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def bad(): e = None try: bar(int(sys.argv[1])) except KeyError as e: print('key error') except ValueError as e: print('value error') print(e) bad()

ใน Python 2 สิ่งนี้ทำงานได้ดี:

$ python foo.py 1 key error 1 $ python foo.py 2 value error 2

แต่ตอนนี้เรามาดู Python 3 กันดีกว่า:

$ python3 foo.py 1 key error Traceback (most recent call last): File 'foo.py', line 19, in bad() File 'foo.py', line 17, in bad print(e) UnboundLocalError: local variable 'e' referenced before assignment

เกิดอะไรขึ้นที่นี่? 'ปัญหา' คือใน Python 3 วัตถุข้อยกเว้นไม่สามารถเข้าถึงได้นอกเหนือจากขอบเขตของ except บล็อก. (เหตุผลก็คือมิฉะนั้นจะคงวงจรการอ้างอิงกับสแต็กเฟรมไว้ในหน่วยความจำจนกว่าตัวรวบรวมขยะจะทำงานและล้างข้อมูลอ้างอิงออกจากหน่วยความจำรายละเอียดทางเทคนิคเพิ่มเติมเกี่ยวกับสิ่งนี้มีอยู่ ที่นี่ ).

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

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def good(): exception = None try: bar(int(sys.argv[1])) except KeyError as e: exception = e print('key error') except ValueError as e: exception = e print('value error') print(exception) good()

เรียกใช้สิ่งนี้บน Py3k:

$ python3 foo.py 1 key error 1 $ python3 foo.py 2 value error 2

ไชโย

(อนึ่ง คู่มือการจ้างงาน Python กล่าวถึงความแตกต่างที่สำคัญอื่น ๆ อีกมากมายที่ต้องระวังเมื่อย้ายรหัสจาก Python 2 ไปยัง Python 3)

ข้อผิดพลาดทั่วไป # 10: การใช้ __del__ ในทางที่ผิด วิธี

สมมติว่าคุณมีสิ่งนี้ในไฟล์ชื่อ mod.py:

import foo class Bar(object): ... def __del__(self): foo.cleanup(self.myhandle)

จากนั้นคุณพยายามทำสิ่งนี้จาก another_mod.py:

import mod mybar = mod.Bar()

คุณจะน่าเกลียด AttributeError ข้อยกเว้น

ทำไม? เพราะตามรายงาน ที่นี่ เมื่อล่ามปิดตัวลงตัวแปรส่วนกลางของโมดูลจะถูกตั้งค่าเป็น None ดังนั้นในตัวอย่างข้างต้นเมื่อถึงจุดนั้น __del__ ถูกเรียกชื่อ foo ได้ถูกตั้งค่าเป็น None

วิธีแก้ปัญหาการเขียนโปรแกรม Python ขั้นสูงนี้จะใช้ atexit.register() แทน. ด้วยวิธีนี้เมื่อโปรแกรมของคุณดำเนินการเสร็จสิ้น (เมื่อออกจากปกตินั่นคือ) ตัวจัดการที่ลงทะเบียนของคุณจะเริ่มทำงาน ก่อน ล่ามปิดตัวลง

ด้วยความเข้าใจดังกล่าวการแก้ไขข้างต้น mod.py รหัสอาจมีลักษณะดังนี้:

เป็นแอนิเมชั่นทั้งหมดบนเว็บแอนิเมชั่นแฟลช
import foo import atexit def cleanup(handle): foo.cleanup(handle) class Bar(object): def __init__(self): ... atexit.register(cleanup, self.myhandle)

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

สรุป

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

การทำความคุ้นเคยกับความแตกต่างที่สำคัญของ Python เช่น (แต่ไม่ จำกัด เพียง) ปัญหาการเขียนโปรแกรมขั้นสูงระดับปานกลางที่ยกมาในบทความนี้จะช่วยเพิ่มประสิทธิภาพการใช้ภาษาในขณะที่หลีกเลี่ยงข้อผิดพลาดทั่วไปบางประการ

คุณอาจต้องการตรวจสอบไฟล์ Insider’s Guide to Python Interviewing สำหรับคำแนะนำเกี่ยวกับคำถามสัมภาษณ์ที่สามารถช่วยระบุผู้เชี่ยวชาญของ Python ได้

เราหวังว่าคุณจะพบคำแนะนำในบทความนี้ที่เป็นประโยชน์และยินดีรับฟังความคิดเห็นของคุณ

สำรวจหลักการออกแบบของเกสตัลท์

การออกแบบ Ux

สำรวจหลักการออกแบบของเกสตัลท์
คำแนะนำ: วิธีการเคลื่อนไหวด้วย SVG

คำแนะนำ: วิธีการเคลื่อนไหวด้วย SVG

ส่วนหน้าของเว็บ

โพสต์ยอดนิยม
Buggy CakePHP Code: 6 ข้อผิดพลาดที่พบบ่อยที่สุดนักพัฒนา CakePHP ทำ
Buggy CakePHP Code: 6 ข้อผิดพลาดที่พบบ่อยที่สุดนักพัฒนา CakePHP ทำ
รีวิว CakePHP 3 ของฉัน - ยังสดยังร้อน
รีวิว CakePHP 3 ของฉัน - ยังสดยังร้อน
ภาพรวมของตัวสร้างไซต์คงที่ยอดนิยม
ภาพรวมของตัวสร้างไซต์คงที่ยอดนิยม
นักพัฒนาชาวโบลิเวีย Yasett Acurana ได้รับทุนการศึกษา ApeeScape ครั้งที่หก
นักพัฒนาชาวโบลิเวีย Yasett Acurana ได้รับทุนการศึกษา ApeeScape ครั้งที่หก
การเขียนโปรแกรมจำนวนเต็มผสม: คู่มือสำหรับการตัดสินใจเชิงคำนวณ
การเขียนโปรแกรมจำนวนเต็มผสม: คู่มือสำหรับการตัดสินใจเชิงคำนวณ
 
แนวโน้มอีคอมเมิร์ซที่โดดเด่นและอิทธิพลต่อการออกแบบ (พร้อมอินโฟกราฟิก)
แนวโน้มอีคอมเมิร์ซที่โดดเด่นและอิทธิพลต่อการออกแบบ (พร้อมอินโฟกราฟิก)
การสำรวจเครื่องมือการทำแผนที่ออนไลน์ที่ดีที่สุดสำหรับนักพัฒนาเว็บ: Roadmap to Roadmaps
การสำรวจเครื่องมือการทำแผนที่ออนไลน์ที่ดีที่สุดสำหรับนักพัฒนาเว็บ: Roadmap to Roadmaps
GraphQL กับ REST - บทช่วยสอน GraphQL
GraphQL กับ REST - บทช่วยสอน GraphQL
ปรับปรุงการแปลงค่าเฉลี่ยเชิงปริมาณเฉลี่ยต่อเนื่อง
ปรับปรุงการแปลงค่าเฉลี่ยเชิงปริมาณเฉลี่ยต่อเนื่อง
ข้อมูลขนาดใหญ่: ใบสั่งยาสำหรับสภาพการวิจัยและพัฒนาเภสัชกรรม
ข้อมูลขนาดใหญ่: ใบสั่งยาสำหรับสภาพการวิจัยและพัฒนาเภสัชกรรม
โพสต์ยอดนิยม
  • คุณได้สมัครใช้บริการบนคลาวด์เพื่อซิงโครไนซ์ข้อมูลระหว่าง
  • การสร้างผังบัญชี
  • c corp หรือ s corp llc
  • การปรับประสิทธิภาพในเซิร์ฟเวอร์ sql ทีละขั้นตอน
  • แนวทางปฏิบัติที่ดีที่สุดสำหรับสถาปัตยกรรมแอพ android
หมวดหมู่
  • กระบวนการและเครื่องมือ
  • การวางแผนและการพยากรณ์
  • การออกแบบ Ui
  • การจัดการโครงการ
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt