ทำไมจึง[]เร็วกว่าlist()?
เหตุผลที่ยิ่งใหญ่ที่สุดคือ Python list()ให้ความสำคัญกับฟังก์ชั่นที่ผู้ใช้กำหนดซึ่งหมายความว่าคุณสามารถดักจับมันด้วยการใช้นามแฝงอย่างอื่นlistและทำสิ่งที่แตกต่างออกไป (เช่นใช้รายการย่อยของคุณเอง
มันจะสร้างตัวอย่างใหม่ของรายการ builtin []ทันที
คำอธิบายของฉันพยายามที่จะให้คุณปรีชาสำหรับเรื่องนี้
คำอธิบาย
[] เป็นที่รู้จักกันทั่วไปว่าเป็นตัวอักษรไวยากรณ์
ในไวยากรณ์นี้เรียกว่า "การแสดงรายการ" จากเอกสาร :
การแสดงรายการเป็นชุดของนิพจน์ที่ว่างเปล่าที่อยู่ในวงเล็บเหลี่ยม:
list_display ::= "[" [starred_list | comprehension] "]"
การแสดงรายการให้ผลกับวัตถุรายการใหม่เนื้อหาที่ถูกระบุโดยรายการของการแสดงออกหรือความเข้าใจ เมื่อรายการนิพจน์ที่คั่นด้วยเครื่องหมายจุลภาคถูกระบุอิลิเมนต์จะถูกประเมินจากซ้ายไปขวาและวางลงในอ็อบเจ็กต์รายการตามลำดับนั้น เมื่อมีการจัดหาความเข้าใจรายการจะถูกสร้างขึ้นจากองค์ประกอบที่เกิดจากความเข้าใจ
ในระยะสั้นซึ่งหมายความว่ามีการสร้างวัตถุชนิดlistภายใน
ไม่มีการหลีกเลี่ยงสิ่งนี้ - ซึ่งหมายความว่า Python สามารถทำได้โดยเร็วที่สุด
ในทางกลับกันlist()สามารถถูกดักจับจากการสร้าง builtin listโดยใช้ builtin list constructor
ตัวอย่างเช่นสมมติว่าเราต้องการให้รายการของเราถูกสร้างขึ้นอย่างดัง
class List(list):
def __init__(self, iterable=None):
if iterable is None:
super().__init__()
else:
super().__init__(iterable)
print('List initialized.')
จากนั้นเราสามารถตัดชื่อlistในขอบเขตโกลบอลระดับโมดูลและจากนั้นเมื่อเราสร้างlistเราจะสร้างรายการย่อยของเรา:
>>> list = List
>>> a_list = list()
List initialized.
>>> type(a_list)
<class '__main__.List'>
ในทำนองเดียวกันเราสามารถลบออกจาก namespace ทั่วโลก
del list
และวางไว้ในเนมสเปซ builtin:
import builtins
builtins.list = List
และตอนนี้:
>>> list_0 = list()
List initialized.
>>> type(list_0)
<class '__main__.List'>
และโปรดทราบว่าการแสดงรายการสร้างรายการโดยไม่มีเงื่อนไข:
>>> list_1 = []
>>> type(list_1)
<class 'list'>
เราอาจทำสิ่งนี้เป็นการชั่วคราวเท่านั้นดังนั้นให้ยกเลิกการเปลี่ยนแปลงของเราก่อน - ลบListวัตถุใหม่ออกจาก builtins:
>>> del builtins.list
>>> builtins.list
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'builtins' has no attribute 'list'
>>> list()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'list' is not defined
โอ้ไม่พวกเราหลงทางต้นฉบับ
ไม่ต้องกังวลเรายังสามารถรับได้list- เป็นประเภทของรายการตามตัวอักษร:
>>> builtins.list = type([])
>>> list()
[]
ดังนั้น...
ทำไมจึง[]เร็วกว่าlist()?
อย่างที่เราเห็น - เราสามารถเขียนทับlist- แต่เราไม่สามารถสกัดกั้นการสร้างประเภทตามตัวอักษร เมื่อเราใช้listเราจะต้องทำการค้นหาเพื่อดูว่ามีอะไรบ้าง
จากนั้นเราต้องโทรหาอะไรก็ได้ที่เรามองหา จากไวยากรณ์:
การโทรเรียกวัตถุที่เรียกได้ (เช่นฟังก์ชั่น) ที่มีชุดของอาร์กิวเมนต์ที่ว่างเปล่า:
call ::= primary "(" [argument_list [","] | comprehension] ")"
เราจะเห็นว่ามันทำสิ่งเดียวกันสำหรับชื่อใด ๆ ไม่ใช่แค่รายการ:
>>> import dis
>>> dis.dis('list()')
1 0 LOAD_NAME 0 (list)
2 CALL_FUNCTION 0
4 RETURN_VALUE
>>> dis.dis('doesnotexist()')
1 0 LOAD_NAME 0 (doesnotexist)
2 CALL_FUNCTION 0
4 RETURN_VALUE
สำหรับ[]ไม่มีการเรียกใช้ฟังก์ชันในระดับ bytecode หลาม:
>>> dis.dis('[]')
1 0 BUILD_LIST 0
2 RETURN_VALUE
เพียงแค่ไปที่การสร้างรายการโดยไม่มีการค้นหาหรือการโทรที่ระดับ bytecode
ข้อสรุป
เราได้แสดงให้เห็นว่าlistสามารถถูกสกัดกั้นด้วยรหัสผู้ใช้โดยใช้กฎการกำหนดขอบเขตและlist()มองหา callable และเรียกมันว่า
ในขณะที่[]การแสดงรายการหรือตัวอักษรจึงหลีกเลี่ยงการค้นหาชื่อและการเรียกใช้ฟังก์ชัน
()และ''มีความพิเศษเนื่องจากไม่เพียง แต่ว่างเปล่า แต่ยังไม่เปลี่ยนรูปและเช่นนี้จึงเป็นชัยชนะที่ง่ายที่จะทำให้พวกเขาเป็นโสด พวกเขาไม่ได้สร้างวัตถุใหม่เพียงแค่โหลดเดี่ยวสำหรับที่ว่างเปล่า/tuplestrรายละเอียดการใช้งานทางเทคนิค แต่ฉันมีเวลาจินตนาการว่าทำไมพวกเขาจะไม่ แคชเปล่าtuple/strด้วยเหตุผลด้านประสิทธิภาพ ดังนั้นสัญชาตญาณของคุณเกี่ยวกับ[]และ{}ผ่านการกลับตัวอักษรหุ้นเป็นเรื่องที่ผิด แต่ก็ไม่นำไปใช้และ()''