涉及元类的动态类创建python
我正在尝试使用参数创建类的实例,问题是我的元类需要一些位置参数来决定类创建的基础。
这是一个更清晰的例子:
Here are the childs which will be methods of the class (they will be chosen be the parent class object name)
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 ')
这是我的元类,它接受一个附加参数CONNECTION_TYPE,它是一个字典,所以元类将根据这个字典加载适当的子级,
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)
这是将提供给元类的字典。
clsdic = {'TYPE': 'CONDITION1',
'CONNECTION_TYPE': 'CONDITION2', 'OBJ': "ParentA", }
问题在于,我使用 exec 使用所需的 CONNECTION_TYPE 字典动态创建我的类,代码运行时没有错误,但创建的类中缺少一些内容,这些是 __module__
和子类。
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__']
i am trying to create an instance of a class using arguments, and the problem is my meta class needs some positional args to decide about the bases of class creation.
here is an example to clear it more:
Here are the childs which will be methods of the class (they will be chosen be the parent class object name)
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 ')
Here is my metaclass which accepts an additional argument CONNECTION_TYPE which is a dictionary, so metaclass will load proper childs according to this 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)
this is the Dictionary which will be served to the meta class.
clsdic = {'TYPE': 'CONDITION1',
'CONNECTION_TYPE': 'CONDITION2', 'OBJ': "ParentA", }
HERE IS The PROBLEM, I use exec to create my class dynamically with my desired CONNECTION_TYPE dictionary, code runs without Err but there are something missing in the created class, and those are __module__
and 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))
This is the output :|
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__']
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
嗯,解决了。
这是全局变量定义问题。
这是我们应该如何调用 exec 并从中获取返回值。
HUM, Solved.
it was the global variable definition problem.
here is how we should call an exec and get a return from it.
您根本不需要也不应该调用
exec
。只需调用您的元类并传递所需的参数(在这种情况下,名称、基础和命名空间就足够了:
将为您创建一个新类。(元类
__new__
末尾的 super() 调用即可执行此操作)。You don't needand should not call
exec
at all.Simply calling your metaclass passign the needed parameters (name, bases and namespace is enough in this case:
will create you a new class. (the super() call atthe end of the metaclass
__new__
does that).