涉及元类的动态 Class 创建 python
Dynamic Class Creation python with metaclass involved
我正在尝试使用参数创建 class 的实例,问题是我的元 class 需要一些位置参数来决定 class 创建的基础。
这里有一个更清楚的例子:
这是 class 的方法的子项(它们将被选为父 class 对象名称)
import inspect
import sys
class ParentA:
pass
class Child1(ParentA):
def ch1_cmd(self):
print('This is RAM Telnet IOS Cisco ')
class Child2(ParentA):
def ch2_cmd(self):
print('This is Time Telnet IOS Cisco ')
这是我的元class,它接受一个额外的参数CONNECTION_TYPE,它是一个字典,所以metaclass 将根据这个 Dictionary
加载适当的子项
class MainMeta(type):
def __new__(cls, clsname, bases, clsdict, CONNECTION_TYPE):
if CONNECTION_TYPE != None:
CONNECTION_TYPE['OBJ'] = getattr(
sys.modules[__name__], CONNECTION_TYPE['OBJ'])
if CONNECTION_TYPE['TYPE'] == 'CONDITION1':
if CONNECTION_TYPE['CONNECTION_TYPE'] == 'CONDITION2':
bases = []
for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj):
if CONNECTION_TYPE['OBJ'].__subclasscheck__(obj):
if CONNECTION_TYPE['OBJ'].__name__ != obj.__name__:
bases.append(obj)
bases = tuple(bases)
print(clsname, bases, clsdict) # here Shows that bases are loaded CORRECTLY
return super().__new__(cls, clsname, bases, clsdict)
这是将提供给元 class 的词典。
clsdic = {'TYPE': 'CONDITION1',
'CONNECTION_TYPE': 'CONDITION2', 'OBJ': "ParentA", }
这是问题所在,我使用 exec 使用我想要的 CONNECTION_TYPE 字典动态创建我的 class,代码运行时没有错误,但有一些东西在创建的 class 中缺失,它们是 __module__
和 child classes.
def dev_creator(*args, **kwargs):
print()
myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n pass\n"""
return exec(myclass, globals())
dev = dev_creator(**clsdic)
print(dir(dev))
这是输出:|
MyMain (<class '__main__.Child1'>, <class '__main__.Child2'>) {'__module__': '__main__', '__qualname__': 'MyMain'}
['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
嗯,解决了。
是全局变量定义问题。
下面是我们应该如何调用 exec 并从中获取 return。
dev = None
def dev_creator(*args, **kwargs):
# print(kwargs)
myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n pass\ndev = MyMain"""
exec(myclass, globals(), dev)
return dev
您根本不需要也不应该调用 exec
。
只需调用您的元class 传递所需的参数(在这种情况下,名称、基数和命名空间就足够了:
myclass = metaclass("myclass", (), {}, CONNECTION_TYPE=kwargs)
将为您创建一个新的 class。 (metaclass __new__
末尾的 super() 调用就是这样做的)。
我正在尝试使用参数创建 class 的实例,问题是我的元 class 需要一些位置参数来决定 class 创建的基础。
这里有一个更清楚的例子:
这是 class 的方法的子项(它们将被选为父 class 对象名称)
import inspect
import sys
class ParentA:
pass
class Child1(ParentA):
def ch1_cmd(self):
print('This is RAM Telnet IOS Cisco ')
class Child2(ParentA):
def ch2_cmd(self):
print('This is Time Telnet IOS Cisco ')
这是我的元class,它接受一个额外的参数CONNECTION_TYPE,它是一个字典,所以metaclass 将根据这个 Dictionary
加载适当的子项class MainMeta(type):
def __new__(cls, clsname, bases, clsdict, CONNECTION_TYPE):
if CONNECTION_TYPE != None:
CONNECTION_TYPE['OBJ'] = getattr(
sys.modules[__name__], CONNECTION_TYPE['OBJ'])
if CONNECTION_TYPE['TYPE'] == 'CONDITION1':
if CONNECTION_TYPE['CONNECTION_TYPE'] == 'CONDITION2':
bases = []
for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj):
if CONNECTION_TYPE['OBJ'].__subclasscheck__(obj):
if CONNECTION_TYPE['OBJ'].__name__ != obj.__name__:
bases.append(obj)
bases = tuple(bases)
print(clsname, bases, clsdict) # here Shows that bases are loaded CORRECTLY
return super().__new__(cls, clsname, bases, clsdict)
这是将提供给元 class 的词典。
clsdic = {'TYPE': 'CONDITION1',
'CONNECTION_TYPE': 'CONDITION2', 'OBJ': "ParentA", }
这是问题所在,我使用 exec 使用我想要的 CONNECTION_TYPE 字典动态创建我的 class,代码运行时没有错误,但有一些东西在创建的 class 中缺失,它们是 __module__
和 child classes.
def dev_creator(*args, **kwargs):
print()
myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n pass\n"""
return exec(myclass, globals())
dev = dev_creator(**clsdic)
print(dir(dev))
这是输出:|
MyMain (<class '__main__.Child1'>, <class '__main__.Child2'>) {'__module__': '__main__', '__qualname__': 'MyMain'}
['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
嗯,解决了。 是全局变量定义问题。
下面是我们应该如何调用 exec 并从中获取 return。
dev = None
def dev_creator(*args, **kwargs):
# print(kwargs)
myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n pass\ndev = MyMain"""
exec(myclass, globals(), dev)
return dev
您根本不需要也不应该调用 exec
。
只需调用您的元class 传递所需的参数(在这种情况下,名称、基数和命名空间就足够了:
myclass = metaclass("myclass", (), {}, CONNECTION_TYPE=kwargs)
将为您创建一个新的 class。 (metaclass __new__
末尾的 super() 调用就是这样做的)。