Python, del หรือ delattr ไหนดีกว่ากัน?


181

นี่อาจเป็นเรื่องโง่ ๆ แต่มันก็จู้จี้ที่ด้านหลังของสมองมาระยะหนึ่งแล้ว

Python ให้เราสองวิธีในการลบคุณลักษณะจากวัตถุคำสั่งdelและฟังก์ชันในตัวdelattr ฉันชอบdelattrเพราะฉันคิดว่าชัดเจนกว่า:

del foo.bar
delattr(foo, "bar")

แต่ฉันสงสัยว่าอาจมีความแตกต่างภายใต้ประทุนระหว่างพวกเขาหรือไม่

คำตอบ:


266

ครั้งแรกมีประสิทธิภาพมากกว่าที่สอง del foo.barรวบรวมคำแนะนำ bytecode สองคำ:

  2           0 LOAD_FAST                0 (foo)
              3 DELETE_ATTR              0 (bar)

ในขณะที่delattr(foo, "bar")ใช้เวลาห้า:

  2           0 LOAD_GLOBAL              0 (delattr)
              3 LOAD_FAST                0 (foo)
              6 LOAD_CONST               1 ('bar')
              9 CALL_FUNCTION            2
             12 POP_TOP             

นี่แปลว่าเป็นการวิ่งครั้งแรกที่เร็วขึ้นเล็กน้อย (แต่ก็ไม่แตกต่างกันมาก - .15 μsบนเครื่องของฉัน)

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

[แก้ไขเพื่อแสดงคำแนะนำ bytecode ที่สร้างขึ้นภายในฟังก์ชันซึ่งคอมไพเลอร์สามารถใช้LOAD_FASTและLOAD_GLOBAL]


6
คุณใช้เครื่องมือใดในการสร้างสิ่งนี้
Triptych

33
disโมดูล คุณสามารถเรียกใช้จากบรรทัดคำสั่งใช้และการพิมพ์ในรหัสบางส่วนหรือถอดแยกชิ้นส่วนฟังก์ชั่นที่มีpython -m dis dis.dis()
ไมล์

15
การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากฐานของความชั่วร้ายทั้งหมด ;-) แต่ใช่คุณพูดถูก
Lennart Regebro

26
.. ดังนั้นมันจะตามมาหรือเปล่าว่าความรักเงินคือการเพิ่มประสิทธิภาพก่อนวัยอันควร?
จอห์น Fouhy

5
การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นส่วนหนึ่งของความรักของเงินเป็นมันหมายความว่าคุณกำลังพยายามที่จะใช้จ่ายน้อยลงในการประมวลผล :)
ร็อบแกรนท์

41
  • เดลชัดเจนและมีประสิทธิภาพมากขึ้น
  • delattrอนุญาตให้ลบแอตทริบิวต์แบบไดนามิก

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

for name in ATTRIBUTES:
    delattr(obj, name)

หรือ:

def _cleanup(self, name):
    """Do cleanup for an attribute"""
    value = getattr(self, name)
    self._pre_cleanup(name, value)
    delattr(self, name)
    self._post_cleanup(name, value)

คุณไม่สามารถทำมันได้ด้วยเดล


2
คุณสามารถทำสิ่งที่สองด้วยเดล del self.__dict__[name]สมมติว่าไม่มีเรื่องตลก ๆ เกิดขึ้นกับเมตาคลาส
smac89

17

อย่างไม่ต้องสงสัยในอดีต ในมุมมองของฉันนี้เป็นเหมือนถามว่าfoo.barดีกว่าgetattr(foo, "bar")และฉันไม่คิดว่าใครถามคำถาม :)


3
ฉันแน่ใจว่ามีคนอย่างน้อยหนึ่งคนที่ต้องการ getattr (foo, "bar") มากกว่า foo.bar ได้รับฉันจะไม่เห็นด้วยกับพวกเขา แต่คนคนนั้นก็ยังพอที่จะทำให้มันไม่ใช่อดีตอย่างแน่นอน
เจสันเบเกอร์

3
@ Jason จากนั้นไม่มีอะไร "ดีกว่าอย่างแน่นอน" กว่าสิ่งอื่นใดโดยการตีความวลีของคุณ ฉันคิดว่านี่เป็นการใช้ "สมเหตุสมผล" อย่างสมบูรณ์แบบ
Phob

26
getattr จะดีกว่าเมื่อมีความเป็นไปได้ที่คุณสมบัติไม่มีอยู่และคุณต้องการตั้งค่าเริ่มต้นโดยไม่ต้องเขียนบล็อกลอง / ยกเว้น กล่าวคือ gettattr (foo, "bar", None)
Marc Gibbons

2
@MarcGibbons: เดี๋ยวก่อนนั่นเป็นเรื่องจริงเหรอ? ฉันใช้รูปแบบเสมอif hasattr(obj, 'var') and obj.var == ...... ฉันสามารถลดสิ่งนี้ได้if getattr(obj, 'var', None) == ...ในกรณีส่วนใหญ่! ฉันคิดว่าสั้นกว่าและอ่านง่ายกว่าเล็กน้อย
ArtOfWarfare

@ArtOfWarfare hasattrโทรจริงgetattr
cheniel

14

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


5

เช่นเดียวกับ getattr และ setattr ควรใช้ delattr ต่อเมื่อไม่ทราบชื่อแอตทริบิวต์

ในแง่นั้นมันเทียบเท่ากับคุณสมบัติของหลามหลายอย่างที่ใช้ในการเข้าถึงฟังก์ชันการใช้งานในตัวในระดับที่ต่ำกว่าที่คุณมีตามปกติเช่น__import__แทนที่จะเป็นimportและoperator.addแทนที่จะเป็น+


3

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


1

หากคุณคิดว่าdelattrชัดเจนกว่านั้นทำไมไม่ใช้getattrตลอดเวลามากกว่าobject.attr?

สำหรับภายใต้ประทุน ... การเดาของคุณดีพอ ๆ ถ้าไม่ดีขึ้นอย่างมีนัยสำคัญ


1

เป็นคำถามเก่า แต่ฉันต้องการใส่ 2 เซ็นต์ของฉัน

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

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