วิธีที่เหมาะสมในการรักษา Python argparse.Namespace () เป็นพจนานุกรมคืออะไร


228

หากฉันต้องการใช้ผลลัพธ์ของargparse.ArgumentParser()ซึ่งเป็นNamespaceวัตถุด้วยวิธีการที่คาดว่าวัตถุหรือคล้ายการทำแผนที่ (ดูคอลเลกชันการทำแผนที่) วิธีที่เหมาะสมในการทำคืออะไร?

C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> args.baz = 'yippee'
>>> args['baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Namespace' object has no attribute '__getitem__'
>>> dir(args)
['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '_
_format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__
', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'ba
r', 'baz', 'foo']

เหมาะสมหรือไม่ที่จะ "เข้าถึงวัตถุ" และใช้__dict__คุณสมบัติของวัตถุหรือไม่

ฉันคิดว่าคำตอบคือไม่: __dict__มีกลิ่นเหมือนแบบแผนสำหรับการนำไปใช้ แต่ไม่ใช่สำหรับอินเทอร์เฟซวิธี__getattribute__หรือ__setattr__หรือ__contains__ดูเหมือนจะเป็น

คำตอบ:


385

คุณสามารถเข้าถึงพจนานุกรมของ namespace ด้วยvars () :

>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}

คุณสามารถแก้ไขพจนานุกรมได้โดยตรงหากต้องการ:

>>> d['baz'] = 'store me'
>>> args.baz
'store me'

ใช่การเข้าถึงแอตทริบิวต์ __dict__ นั้นเป็นเรื่องปกติ มันเป็นพฤติกรรมที่กำหนดทดสอบและรับประกันได้ดี


1
เอกสารกล่าวว่า: "พจนานุกรมที่ส่งคืนไม่ควรแก้ไข: ผลกระทบต่อตารางสัญลักษณ์ที่สอดคล้องกันจะไม่ได้กำหนด" ซึ่งอาจอ้างถึงพฤติกรรมของvars()(ซึ่งเป็นอย่างใดอย่างหนึ่งlocals()หรือglobals()) แต่ฉันไม่แน่ใจจริงๆ

2
อืมฉันคิดว่าฉันไม่เข้าใจความแตกต่างระหว่างการใช้vars()กับ__dict__
Jason S

21
@delnan มีคนทำการแก้ไขเอกสารที่ไม่ถูกต้องและสร้างคำเตือนในวงกว้าง เอกสารได้รับการแก้ไขในภายหลัง ดู docs.python.org/2.7/library/functions.html#vars ในขณะที่มีบางกรณีพิเศษที่มีพจนานุกรมแบบอ่านอย่างเดียว (เช่นชาวบ้านและพร็อกซี่พจนานุกรมระดับ) ส่วนที่เหลือของกรณีที่สามารถปรับปรุงได้ การโทรvars (obj)มีความหมายเหมือนกันกับ obj .__ dict__ ในกรณีของเนมสเปซargparse , vars (args)ให้การเข้าถึงโดยตรงกับพจนานุกรมที่อัพเดตได้
Raymond Hettinger

1
@RaymondHettinger เอาล่ะเรียบร้อย ฉันได้รับข้อความนั้นจาก/3/เวอร์ชันของเอกสาร (ในการตรวจสอบอย่างใกล้ชิด 3.1 ถึง 3.4 รวมถึง) ดังนั้นการแก้ไขจึงขาดหายไป

8
@delnan ฉันเพิ่งอัปเดตเอกสาร 3.3 และ 3.3 มันจะมองเห็นได้ในวันพรุ่งนี้ ขอบคุณสำหรับการชี้ให้เห็น
Raymond Hettinger

64

ตรงจากปากม้า :

หากคุณต้องการที่จะมีมุมมองเหมือน dict ของคุณลักษณะคุณสามารถใช้สำนวน Python มาตรฐานvars():

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

- Python Standard Library, 16.4.4.6 วัตถุ Namespace


1
ยังคง 'foo' คิดถึง '-' ความคิดใดที่จะ?
user2678074

1
@ user2678074 นี่เป็นความตั้งใจที่จะจับคู่แฟล็กเชลล์ เครื่องหมายขีดคั่นเป็นส่วนเกินภายในการดำเนินการหลาม
ริช

vars(args)ให้ฉันTypeError: 'dict' object is not callable
user5359531

6
@ user5359531 คุณอาจเขียนทับ global varsด้วยตัวแปร คุณสามารถใช้__builtins__.varsเพื่อเข้าถึงโดยตรงหรือdel varsเพื่อหยุดการแรเงา
Nick T

@NickT Minor correction: ฟังก์ชั่น Python จะถูกกำหนดขอบเขตแบบคงที่ดังนั้นหากคุณทำเงาตัวแปรทั่วโลกในฟังก์ชั่นตัวระบุนั้นจะอ้างถึงตัวแปรโลคอลภายในฟังก์ชันนั้นเสมอก่อนที่จะได้รับมอบหมายหรือหลังจากdelนั้น ที่ขอบเขตของโมดูลdel จะทำงานกับบิวด์อิน "un-shadow"
augurar

-1

มันเหมาะสมหรือไม่ที่จะ "เข้าถึงวัตถุ" และใช้คุณสมบัติdictของมัน?

โดยทั่วไปแล้วฉันจะพูดว่า "ไม่" อย่างไรก็ตามNamespaceทำให้ฉันเป็นคนออกแบบมากเกินไปอาจมาจากเมื่อชั้นเรียนไม่สามารถสืบทอดจากประเภทในตัว

ในทางกลับกันNamespaceนำเสนอวิธีการที่มุ่งเน้นงานในการโต้แย้งและฉันไม่สามารถนึกถึงสถานการณ์ที่จะเรียกร้องให้คว้า__dict__แต่ขอบเขตของจินตนาการของฉันไม่เหมือนกับของคุณ


11
การเข้าใช้แอตทริบิวต์ __dict__ นั้นเป็นเรื่องที่สมบูรณ์ วิปัสสนาเป็นพื้นฐานของภาษา แอททริบิวนี้เผยแพร่สู่สาธารณะด้วยเหตุผล :-)
Raymond Hettinger

8
แต่ทุกอย่างใน Python นั้นเป็น "สาธารณะ" ไม่มีความแตกต่าง (ยกเว้นอนุสัญญาขีดเส้นใต้ชั้นนำ) ระหว่างตัวแปรการนำไปใช้ที่ใช้ในอินสแตนซ์และส่วนต่อประสานสาธารณะที่แสดง โดยเฉพาะอย่างยิ่งในวัตถุที่คล้ายพจนานุกรม: เส้นแบ่งระหว่างวิธีการอินสแตนซ์และค่าพจนานุกรมซึ่งเป็นฟังก์ชั่นนั้นค่อนข้างเบลอ
Jason S

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