บิตของโค้ดนี้ช่วยให้คุณสร้างคลาสใหม่ด้วยชื่อไดนามิกและชื่อพารามิเตอร์ การตรวจสอบพารามิเตอร์ใน__init__
ไม่อนุญาตให้ใช้พารามิเตอร์ที่ไม่รู้จักหากคุณต้องการการตรวจสอบอื่น ๆ เช่นประเภทหรือว่าจำเป็นให้เพิ่มตรรกะที่นั่น:
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass
และสิ่งนี้ได้ผลเช่น:
>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass
ผมเห็นคุณจะขอใส่ชื่อแบบไดนามิกในขอบเขตการตั้งชื่อ - ตอนนี้ว่าจะไม่ถือว่าเป็นวิธีที่ดีในหลาม - คุณอาจมีชื่อตัวแปรรู้จักกันในเวลาเขียนโปรแกรมหรือข้อมูล - และชื่อได้เรียนรู้ในการรันไทม์มีมากขึ้น " ข้อมูล "กว่า" ตัวแปร "-
ดังนั้นคุณสามารถเพิ่มชั้นเรียนของคุณลงในพจนานุกรมและใช้จากที่นั่น:
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
และหากการออกแบบของคุณต้องการชื่อที่อยู่ในขอบเขตจริงๆให้ทำเช่นเดียวกัน แต่ใช้พจนานุกรมที่ส่งคืนโดยการglobals()
เรียกแทนพจนานุกรมตามอำเภอใจ:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(แน่นอนว่าเป็นไปได้ที่ฟังก์ชันโรงงานคลาสจะแทรกชื่อแบบไดนามิกในขอบเขตทั่วโลกของผู้โทร - แต่นั่นเป็นการปฏิบัติที่แย่กว่านั้นและไม่สามารถใช้งานร่วมกันได้กับการใช้งาน Python วิธีการทำเช่นนั้นก็คือการเรียกผู้โทรเข้า เฟรมการดำเนินการผ่านsys._getframe (1)และการตั้งชื่อคลาสในพจนานุกรมส่วนกลางของเฟรมในf_globals
แอตทริบิวต์)
update, tl; dr:คำตอบนี้ได้รับความนิยม แต่ยังคงมีความเฉพาะเจาะจงมากสำหรับเนื้อหาคำถาม คำตอบทั่วไปเกี่ยวกับวิธี
"สร้างคลาสที่ได้รับแบบไดนามิกจากคลาสพื้นฐาน"
ใน Python เป็นการเรียกง่ายๆในการtype
ส่งผ่านชื่อคลาสใหม่ทูเปิลที่มีคลาสพื้นฐาน (es) และ__dict__
เนื้อความสำหรับคลาสใหม่ดังนี้:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
อัปเดต
ใครก็ตามที่ต้องการสิ่งนี้ควรตรวจสอบโครงการผักชีฝรั่งด้วยซึ่งอ้างว่าสามารถดองและเลิกใช้คลาสได้เช่นเดียวกับการดองกับวัตถุธรรมดาและเคยใช้มันในการทดสอบของฉัน
a
มันจะเป็นเสมอMyClass
และTestClass
จะไม่ใช้a
? ทำไมไม่เพียงแค่ประกาศทั้ง 3 อาร์กิวเมนต์BaseClass.__init__()
แต่เริ่มต้นทั้งหมดเป็นNone
?def __init__(self, a=None, b=None, C=None)
เหรอ?