ทำไมจึง[]
เร็วกว่า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 และเรียกมันว่า
ในขณะที่[]
การแสดงรายการหรือตัวอักษรจึงหลีกเลี่ยงการค้นหาชื่อและการเรียกใช้ฟังก์ชัน
()
และ''
มีความพิเศษเนื่องจากไม่เพียง แต่ว่างเปล่า แต่ยังไม่เปลี่ยนรูปและเช่นนี้จึงเป็นชัยชนะที่ง่ายที่จะทำให้พวกเขาเป็นโสด พวกเขาไม่ได้สร้างวัตถุใหม่เพียงแค่โหลดเดี่ยวสำหรับที่ว่างเปล่า/tuple
str
รายละเอียดการใช้งานทางเทคนิค แต่ฉันมีเวลาจินตนาการว่าทำไมพวกเขาจะไม่ แคชเปล่าtuple
/str
ด้วยเหตุผลด้านประสิทธิภาพ ดังนั้นสัญชาตญาณของคุณเกี่ยวกับ[]
และ{}
ผ่านการกลับตัวอักษรหุ้นเป็นเรื่องที่ผิด แต่ก็ไม่นำไปใช้และ()
''