ใน Python 3.4+ ทำไมฉันควรใช้ namedtuple บน SimpleNamespace เมื่อไม่ได้ใช้ dict ดูเหมือนว่าจะคล้ายกันมาก


11

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

ฉันอยากจะกลับ ...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

... เข้าสู่ ...

def do_something(a, b, c):
    # Do something

... ที่ไหนaและbมีตัวแปรย่อย

วิธีหนึ่งในการทำเช่นนี้คือ:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

อย่างไรก็ตามดูเหมือนง่ายกว่า:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

ข้อเสียเปรียบคืออะไร? ความจริงที่aและbพิมพ์ไม่ดี? พวกเขาไม่ใช่วัตถุ A และ B?

(Btw ไม่ต้องกังวลเกี่ยวกับชื่อตัวแปรปกติแล้วฉันไม่ได้ใช้เป็นชื่อตัวแปรแบบสั้น)


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

@Goyo ขอบคุณ "ข้อเสียเปรียบ" เป็นวิธีที่งุ่มง่ามในการพูด ฉันไม่ได้หมายความว่าคนใดคนหนึ่งจะดีกว่าคนอื่น แค่ต้องการข้อดีและข้อเสีย ขอบคุณอีกครั้ง.
André Christoffer Andersen

1
ไม่ควรบรรทัดที่ 4 มีลักษณะ "b = B (bu, bv)"
Alen Siljak

@AlenSiljak ใช่มันควรจะเป็น ฉันจะแก้ไขทันที
André Christoffer Andersen

คำตอบ:


21

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

ข้อเสียของความยืดหยุ่นคือมันไม่ได้มีโครงสร้างใด ๆ ไม่มีอะไรจะหยุดใครบางคนจากการโทรSimpleNamespace(x=ax, y=ay)(และdel a.zในบางจุดในภายหลัง) หากอินสแตนซ์นี้ถูกส่งผ่านไปยังฟังก์ชันของคุณข้อยกเว้นจะเกิดขึ้นเมื่อคุณพยายามเข้าถึงฟิลด์

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

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


2

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

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

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

โปรดทราบว่าคุณจะเห็นว่าnamedtupleให้วัตถุพิเศษทั้งหมดแก่เราซึ่งSimpleNamespaceจะไม่เกิดขึ้น แต่ละอันSimpleNamespaceนั้นเป็น "เกล็ดหิมะที่ไม่เหมือนใคร" ในขณะที่namedtupleมีอยู่โดยไม่มีการยกตัวอย่างด้วยค่าที่เป็นรูปธรรมใด ๆ ไม่ว่าคุณต้องการ abstractions ที่พูดถึงคุณค่าที่เป็นรูปธรรมคุณควรจะชอบมัน


1

บทสรุปของ SimpleNamespace

จะช่วยให้การเริ่มต้นคุณลักษณะในขณะที่การสร้างวัตถุ:

sn = SimpleNamespace(a=1, b=2)

มันให้อ่านได้

repr(): eval(repr(sn)) == sn

มันแทนที่การเปรียบเทียบเริ่มต้น แทนที่จะเป็นการเปรียบเทียบโดยid()จะเปรียบเทียบค่าแอตทริบิวต์แทน

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