เป็นที่น่าสังเกตว่าสำหรับปัญหาเฉพาะที่เป็นปัญหามีหลายทางเลือกในการใช้eval
:
วิธีที่ง่ายที่สุดคือการใช้setattr
:
def __init__(self):
for name in attsToStore:
setattr(self, name, None)
แนวทางที่ชัดเจนน้อยกว่าคือการอัปเดตวัตถุของ__dict__
วัตถุโดยตรง หากสิ่งที่คุณต้องการทำคือเริ่มต้นแอตทริบิวต์None
นี่จะตรงไปตรงมาน้อยกว่าที่กล่าวมา แต่พิจารณาสิ่งนี้:
def __init__(self, **kwargs):
for name in self.attsToStore:
self.__dict__[name] = kwargs.get(name, None)
สิ่งนี้ช่วยให้คุณสามารถส่งผ่านอาร์กิวเมนต์คำสำคัญไปยังตัวสร้างเช่น:
s = Song(name='History', artist='The Verve')
นอกจากนี้ยังช่วยให้คุณใช้ประโยชน์จากlocals()
สิ่งที่ชัดเจนยิ่งขึ้นเช่น:
s = Song(**locals())
... และหากคุณต้องการกำหนดNone
ให้กับแอตทริบิวต์ที่มีชื่ออยู่ในlocals()
:
s = Song(**dict([(k, None) for k in locals().keys()]))
อีกวิธีหนึ่งในการจัดเตรียมวัตถุที่มีค่าเริ่มต้นสำหรับรายการแอตทริบิวต์คือการกำหนด__getattr__
วิธีการของคลาส:
def __getattr__(self, name):
if name in self.attsToStore:
return None
raise NameError, name
วิธีนี้จะถูกเรียกเมื่อไม่พบแอตทริบิวต์ที่มีชื่อในลักษณะปกติ วิธีนี้ค่อนข้างตรงไปตรงมาน้อยกว่าการตั้งค่าแอตทริบิวต์ในตัวสร้างหรือการอัปเดต__dict__
แต่มีข้อดีที่จะไม่สร้างแอตทริบิวต์จริง ๆ เว้นแต่จะมีอยู่ซึ่งสามารถลดการใช้หน่วยความจำของคลาสได้อย่างมาก
ประเด็นทั้งหมดนี้: โดยทั่วไปมีหลายสาเหตุที่ควรหลีกเลี่ยงeval
- ปัญหาด้านความปลอดภัยของการรันโค้ดที่คุณไม่ได้ควบคุมปัญหาในทางปฏิบัติของโค้ดที่คุณไม่สามารถดีบักได้ ฯลฯ แต่เหตุผลที่สำคัญยิ่งกว่า โดยทั่วไปคุณไม่จำเป็นต้องใช้ Python เปิดเผยกลไกภายในมากมายให้กับโปรแกรมเมอร์ซึ่งคุณแทบไม่จำเป็นต้องเขียนโค้ดที่เขียนโค้ด
exec/eval
และยังคงไม่ทราบsetattr
?