Python2(有六个)元类和带参数的字段
Posted
技术标签:
【中文标题】Python2(有六个)元类和带参数的字段【英文标题】:Python2 (with six) metaclass and Fields with parameters 【发布时间】:2017-05-05 14:12:29 【问题描述】:我正在创建一个应该使用字段的元类。
基于互联网上的资源,在 *** 上我已经走到了这一步:
元类
def getmethod(attrname):
def _getmethod(self):
return getattr(self, "__"+attrname).get()
return _getmethod
def setmethod(attrname):
def _setmethod(self, value):
return getattr(self, "__"+attrname).set(value)
return _setmethod
class Metaclass(type):
def __new__(cls, name, based, attrs):
ndict =
for attr in attrs:
if isinstance(attrs[attr], Field):
ndict['__'+attr] = attrs[attr]
ndict[attr] = property(getmethod(attr), setmethod(attr))
return super(Metaclass, cls).__new__(cls, name, based, ndict)
型号
class Model(six.with_metaclass(Metaclass)):
foo = CharField()
def __init__(self, *args, **kwargs):
pass
字段
class Field(object):
def __init__(self, required=False, *args, **kwargs):
self.required = required
self.name = None
def set(self, value):
self.value = value
def get(self):
return self.value
def set_name(self, name):
self.name = name
字符域
class CharField(Field):
def __init__(self, required=False, max_length=0, min_length=0, *args, **kwargs):
self.max_length = max_length
self.min_length = min_length
super(CharField, self).__init__(required, args, kwargs)
现在当我创建Model
的子类时
class Product(Model):
name = CharField()
并创建Product
的实例
if __name__ == '__main__':
p = Product()
这很好用。
我什至可以添加或更改产品名称
if __name__ == '__main__':
p = Product()
p.name = "Another beautiful product"
但是,当我想使用name
作为参数时:
if __name__ == '__main__':
p = Product(name="Another beautiful product")
出现错误:TypeError: object() takes no parameters
在调试时,我可以看到 Metaclass 的实例已创建,但在到达 return super(Metaclass, cls).__new__(cls, name, based, ndict)
行时引发错误。
有人可以帮我吗?
【问题讨论】:
看来你的问题可以用descriptors更好地解决。 【参考方案1】:在您的代码中,您创建了一组有趣的协作Field
类,可以使其作为丰富的自动属性工作。
(* 见下文)。
但是您的元类代码只担心 Field 属性,并且不会自动执行在类实例化时传递的参数。当您编写像Product(name="my name")
这样的代码时,“name='my name'”参数被传递到类的__init__
方法和__new__
方法中。通常是 Python 特殊情况 __init__
和 __new__
,因此当 __new__
未声明时,__init__
的参数不会传递给基类 (object
)。可能six.with_metaclass
的使用打破了这种机制——你的name
正在进入object
的构造函数(这会触发你看到的错误)。
您可以通过自定义__new__
(或__init__
,如果您可以完全摆脱元类,请参见下文)来解决此问题- 只需使用您的**kwargs
参数,设置发送的任何字段,然后调用对象的__new__
没有那些无关的参数:
class Model(object):
def __init__(self, **kwargs):
for key, value in kwargs.items():
if isinstance(getattr(self.__class__, key, None), Field):
setattr(self, key, value)
(见下文 - 如果您仍然需要一个带有“六”的元类,您可能需要
将此代码写在__new__
,而不是__init__
)
(*) 现在 - 除了你的主要问题 - 因为你需要比 Python 的属性所允许的更丰富的属性,所以你不应该使用它 - 看看 Descriptor Protocol 是如何工作的 - 基本上,通过创建你的 @987654341 @ 名为 __get__
和 __set__
的类定义方法,您可以从字段中获得所需的附加功能,而根本不需要元类(对于该功能 - 要让 __init__
调用根据需要自动工作,您仍然需要自定义基础 __init__
或元类)
【讨论】:
以上是关于Python2(有六个)元类和带参数的字段的主要内容,如果未能解决你的问题,请参考以下文章
参数化类和元类有啥区别(请使用 Python 中的代码示例)?