【发布时间】:2014-02-05 04:23:43
【问题描述】:
我有一个奇怪的问题,我无法解决。我正在尝试使用https://github.com/Climbcare/unleashed 将一些订单推送到 Unleashed API。它具有以下由另一个类继承的 Python 生成器类:
class MetaResource(type):
def __new__(mcs, name, bases, dct):
"""
Looks for attributes whith a `__resourcefield__` attribute and adds them to ` __resourcefields__`.
Replace the attribute with a property so its value can be directly accessed.
"""
dct['__resourcefields__'] = {}
dct['__embeddedresources__'] = {}
for attr_name, attr in dct.iteritems():
if hasattr(attr, '__resourcefield__') and attr.__resourcefield__:
dct['__resourcefields__'][attr_name] = attr
attr.__fieldname__ = attr_name
attr.__parentresource__ = name
elif hasattr(attr, '__metaclass__') and attr.__metaclass__ == mcs:
dct['__embeddedresources__'][attr_name] = attr
return super(MetaResource, mcs).__new__(mcs, name, bases, dct)
def __init__(cls, name, bases, dct):
cls.guess_endpoint()
cls.convert_fields()
cls.convert_embedded_resources()
super(MetaResource, cls).__init__(name, bases, dct)
这个类被这个类扩展了:
class UnleashedResource(object):
__metaclass__ = MetaResource
# Override if necessary
__endpoint__ = None
# Created by metaclass
__resourcefields__ = {}
__embeddedresources__ = {}
def __repr__(self):
return json.dumps(
self.to_dict(),
sort_keys=True,
indent=4,
separators=(',', ': ')
)
def from_dict(self, dict_val):
"""
Set all the resource's field values from a dictionary.
"""
if not dict_val:
return
for field, value in dict_val.iteritems():
if hasattr(self, field):
setattr(self, field, value)
还有一个扩展 UnleashedResource 类的类:
class Product(UnleashedResource):
__endpoint__ = 'Products'
AverageLandPrice = fields.FieldNullableDecimal()
Barcode = fields.FieldString()
BinLocation = fields.FieldString()
CanAutoAssemble = fields.FieldBoolean()
...
如您所见,MetaResource 是 UnleashedResource 类的元类。
奇怪的是,当您创建 Product() 类的多个实例时,所有这些实例都是相同的,即使它们具有不同的内存 ID。例如:
p1 = Product()
p2 = Product()
对 p1 的任何更改也将存在于 p2 中。并且打印 Product() 也会给我同样的东西。
我阅读了 metaclass,但仍然一无所获。
看看这个:
>>> from unleashed.resources.product import Product
>>> p1 = Product()
>>> type(p1)
<class 'unleashed.resources.product.Product'>
>>> p1.Barcode = 12345
>>> p2 = Product()
>>> p2.Barcode
12345
>>> id(p1)
4414711632
>>> id(p2)
4414356560
>>> Product().Barcode
12345
>>> id(Product())
4414711568
>>> type(Product())
<class 'unleashed.resources.product.Product'>
>>>
非常感谢任何帮助。
【问题讨论】:
-
复杂总是带来麻烦。可能有一种更简单、更清晰、更直接的方法。
-
元类创建的属性是类属性,在所有实例之间共享。请参阅有关此问题的大量先前问题,例如this one。为什么要在元类中执行此操作,而不是仅使用常规类并将该数据放入每个实例的实例属性中?