Ham*_*asi 6 python metaprogramming metaclass
假设我具有带有t属性的Python类型。我想创建一个“参数化的元类型”,以便进行以下工作:
class MySuperClass(type):
pass
class MySubClass(MySuperClass):
# Here is the problem -- How do I define types that contain stuff,
# independent of an object?
def __init__(self, t): # Or __getitem__
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance, MySubClass) and instance.t == self.t
def __subclasscheck__(self, subclass):
return MySubClass in subclass.__mro__ and subclass.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
## Ideally
assert isinstance(MyObject(0), MySuperClass) or isinstance(MyObject(0), MySubClass)
Run Code Online (Sandbox Code Playgroud)
目前,我收到以下错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-99ad08881526> in <module>
14 return MySubClass in subclass.__mro__ and subclass.t == self.t
15
---> 16 class MyObject(metaclass=MySubClass):
17 def __init__(self, t):
18 self.t = t
TypeError: __init__() takes 2 positional arguments but 4 were given
Run Code Online (Sandbox Code Playgroud)
可以满足第一部分或要求。但它需要一个辅助检查器类。MySubClass 是类型的后代,MySubClass(0)应该是一个类。InstanceChecker在 中创建一个内部类MySubClass并覆盖__instancecheck__它们就足够了。
代码可以是:
class MySubClass(MySuperClass):
def __new__(cls, name, bases=None, namespace=None, *args, **kwargs):
if bases is not None:
return super().__new__(cls, name, bases, namespace, **kwargs)
return cls.InstanceChecker(name)
class InstanceChecker:
def __init__(self, t):
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance.__class__, MySubClass) and instance.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我已经删除了__subclasscheck__覆盖,因为t只有一个实例属性MyObject
或者,元类可以自动在参数中添加超类bases。在下面的代码中,MySuperClass不再是MySubClassbut的超类MyObject:
class MySuperClass():
pass
class MySubClass(type):
def __new__(cls, name, bases=None, namespace=None, *args, **kwargs):
if bases is not None:
return super().__new__(cls, name, bases + (MySuperClass,), namespace, **kwargs)
return cls.InstanceChecker(name)
class InstanceChecker:
def __init__(self, t):
self.t = t
def __instancecheck__(self, instance):
return isinstance(instance.__class__, MySubClass) and instance.t == self.t
class MyObject(metaclass=MySubClass):
def __init__(self, t):
self.t = t
# Test code:
## Both of these, square brackets work too
assert isinstance(MyObject(0), MySubClass(0))
assert not isinstance(MyObject(0), MySubClass(1))
## Ideally
assert isinstance(MyObject(0), MySuperClass)
Run Code Online (Sandbox Code Playgroud)