<p>我最终成功地解决了这个问题,非常感谢来自Python IRC通道的pjdelport。感谢所有花时间发表评论和回答的人-这一切都帮助很大。
事实证明,我确实漏掉了一些重要的部分,<strong><em>get</em>和<strong>set</em>描述符是在类级别上操作的,通过使用“self”来设置一个值,我将它设置在字段的<strong>类</strong>上,而不是对象的实例上。在</p>
<p>合适的解决方案是使用传递给<strong><em>get</em>和<strong>set</em>的实例参数,并使用实例的<strong>dict</em></em>直接将值放入实例中,而不会触发<strong><em>get</em>。在</p>
<p>显然,删除类变量部分是多余的,因为我们不想删除类变量。现在这些对象可以使用类型化的实例变量,还可以维护一个包含所有字段的列表。事实上,我们并不真的需要一个元类,但它很容易拥有对象的所有字段的集合,这些字段是在类创建时创建的,而不是在每次实例化时创建的。在</p>
<pre><code>class Field(object):
def __init__(self, *args, **kwargs):
self.value = None
self.name = None
self._args = args
self._kwargs = kwargs
def __get__(self, instance, owner):
print "__get__ called: %s for %s" %(self.name, instance)
if instance:
return self.to_python(instance)
else: # called directly from class - return itself
return self
def __set__(self, instance, value):
print "__set__ called: %s for %s with value %s" %(self.name, instance, value)
self.value = self.from_python(instance, value)
def to_python(self, instance):
return instance.__dict__.get(self.name)
def from_python(self, instance, value):
instance.__dict__[self.name] = value
class TextField(Field):
def to_python(self, instance):
return unicode(instance.__dict__.get(self.name))
class ModelMetaClass(type):
def __new__(cls, name, bases, attrs):
print "Creating new class: %s" % name
obj = super(ModelMetaClass, cls).__new__(cls, name, bases, attrs)
print "class=", cls
_keys = attrs.keys()
_fields = []
for key in _keys:
if isinstance(attrs[key], Field):
_field = attrs.pop(key)
_field.name = key
_fields.append( {'name':key, 'value': _field } )
setattr(obj, '_meta', {'fields': _fields} )
return obj
class Model(object):
__metaclass__ = ModelMetaClass
def __init__(self):
super(Model, self).__init__()
_metafields = self._meta.get('fields',[])
class BasicAdModel(Model):
def __init__(self):
super(BasicAdModel, self).__init__()
self._id = None
self.created_at = None
self.last_modified = None
class SpecialAdModel(BasicAdModel):
textfield = TextField()
def __init__(self):
super(SpecialAdModel, self).__init__()
print "INIT SPECIALAD", self._meta
print "-"*80
print "* creating two models, Ad1 and Ad2"
Ad1 = SpecialAdModel()
Ad2 = SpecialAdModel()
print "* Ad1 textfield attribute is", Ad1.textfield
print "* Setting Ad1 TextField instance to 'Text', expecting __set__ on Textfield to be called"
Ad1.textfield = "Text"
print "\tNew value is: ", Ad1.textfield
print "* Getting Ad2.textfield, expecting __get__ to be called and no value."
print "\tAd2.textfield=", Ad2.textfield
print "* Setting Ad2 text field "
Ad2.textfield = "A different text"
print "\tAd2.textfield=",Ad2.textfield
print "\tAd1.textfield=", Ad1.textfield
</code></pre>