回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>我试图在运行时将类变量转换为实例变量,类似于Django ORM中的情况,在运行时,不同类型的类变量被转换为相同类型的实例变量。在</p>
<p>我使用元类将某些类型的类变量收集到一个列表中,然后在实例化时将它们设置为实例变量。我尝试删除原始的类变量并保留它们,但在这两种情况下都得到了不同的结果,都是不受欢迎的。在</p>
<ul>
<li>我创建了一个简单的Field对象,它使用<strong><em>get</em>和<strong>set</em>描述符将值转换为类型。Field的一个简单实现是Textfield,它将<strong><em>get</em>上的值进行unicode。在</li>
<li>创建类时,元类将“Field”类型的所有属性收集到一个列表中</li>
<li>然后将字段列表设置为类的as\u meta['fields']。在</li>
<li>当类被实例化到一个对象中时,那些meta['fields']就被设置为对象。在一个用例中,原始类var被提前删除。在</li>
<li>然后,我通过创建两个对象来进行测试,将其中一个的textfield属性设置为某个文本,期望调用<strong><em>get</em><eu</strong>和<strong><em>set</em></em><strong>,它们都具有不同的非冲突值。在</li>
</ul>
<p>当类变量被删除时,设置字段值实际上并不会调用<strong><em>set</em></strong>或<strong><em>get</em>,字段只是将类型更改为str。当我不删除类变量时,实例化的两个对象共享它们之间的值。在</p>
<p>我已经将我的代码稀释成下面的代码,这些代码可以保存到一个文件中并使用<code>python test.py</code>运行,或者导入到pythonshell中。将DELETE_CLASS_VAR设置为True将删除类变量(同时考虑两个测试用例)。在</p>
<p>很明显我遗漏了一些东西。如果不能做到这一点,我会一直使用常规的实例变量,但是我非常喜欢Django模型(我已经完成了Django代码,但没有成功),在这个模型中,设置在模型上的类变量会成为它的实例变量,并在其中设置了某种程度的类型安全性和特定的方法。在</p>
<p>谢谢!在</p>
<pre><code># Set to True to delete class variables
DELETE_CLASS_VAR = False
class Field(object):
def __init__(self, *args, **kwargs):
self.value = None
self._args = args
self._kwargs = kwargs
def __get__(self, instance, owner):
print "__get__ called:", instance
return self.to_python()
def __set__(self, instance, value):
print "__set__ called:", instance, value
self.value = self.from_python(value)
def to_python(self):
return self.value
def from_python(self, value):
return value
class TextField(Field):
def to_python(self):
return unicode(self.value)
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)
_fields.<a href="https://www.cnpython.com/list/append" class="inner-link">append</a>( {'name':key, 'value': _field } )
setattr(obj, '_meta', {'fields': _fields} )
print "-"*80
return obj
class Model(object):
__metaclass__ = ModelMetaClass
def __init__(self):
print "ROOT MODEL INIT", self._meta
print "-"*80
super(Model, self).__init__()
_metafields = self._meta.get('fields',[])
for _field in _metafields:
_f = _field['value']
if DELETE_CLASS_VAR and hasattr(self, _field['name']):
delattr(self.__class__, _field['name'])
setattr(self, _field['name'], _f.__class__(*_f._args, **_f._kwargs))
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"
if DELETE_CLASS_VAR:
print "* If the class var was deleted on instantiation __get__ is not called here, and value is now str"
print "\tNew value is: ", Ad1.textfield
print "* Getting Ad2.textfield, expecting __get__ to be called and no value."
if DELETE_CLASS_VAR:
print "* If the class var was deleted - again __get__ is not called, attribute repalced with str"
print "\tAd2.textfield=", Ad2.textfield
print "* Setting Ad2 text field "
Ad2.textfield = "A different text"
if not DELETE_CLASS_VAR:
print "* When class var is not deleted, the two separate instances share the value later set on Ad2 "
print "\tAd2.textfield=",Ad2.textfield
print "\tAd1.textfield=", Ad1.textfield
</code></pre>