包装纸一类子类方法
我的主要类被定义为如下:包装纸一类子类方法
from pymongo import MongoClient
from credentials import MongoMarketPlaceAuth
client = MongoClient('mongodb://conn_url:conn_port/', ssl=True)
db_connection = client.DB_NAME
db_connection.authenticate(name=MongoMarketPlaceAuth.name, password=MongoMarketPlaceAuth.password)
MarketPlace = db_connection
class MarketPlaceObjects(object):
def __init__(self, collection, fields={}, default_filter={}):
self.collection_name = collection
self.fields = fields
self.default_filter = default_filter
if MarketPlace[collection].count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.objects = MarketPlace[collection]
我然后有一个继承我的主要类的类:
class Products(MarketPlaceObjects):
def __init__(self):
super(Products, self).__init__(collection='FlatProduct')
当用于像这样:
from products import Products
p = Products()
p.objects.find_one()
返回描述产品所有方面的字典。 我想要做的是弄清楚是怎么
p.objects.find_one()
,而不是返回字典或词典列表就可以返回一个产品对象(从单个返回字典)或产品对象的列表(从返回的词典列表中)。
因为我不确定如何使用我自己的Product类来包装PyMongo集合类的find_one()或find()方法,所以我很困难。
更新(2017年7月25日): 这是我落得这样做。还需要一些优化:为市场
泛型类:
class CollectionObjectInstance(object):
def __init__(self, response):
for key, value in response.items():
if isinstance(value, dict):
self.__dict__[key] = CollectionObjectInstance(value)
else:
self.__dict__[key] = value
class CollectionObjectsManager(object):
serializer = CollectionObjectInstance
collection = None
default_projection = {}
default_filter = {}
def __init__(self, **kwargs):
self.__dict__ = kwargs
def find(self, filter={}, projection={}):
filter = self.default_filter.update(filter)
projection = self.default_projection.update(projection)
res = self.collection.find(filter, projection)
for o in res:
yield self.serializer(o)
def find_one(self, filter={}, projection={}):
filter = self.default_filter.update(filter)
projection = self.default_projection.update(projection)
res = self.collection.find_one(filter, projection)
return self.serializer(res)
class MarketPlaceCollection(object):
collection_name = None
serializer = None
objects_manager = CollectionObjectsManager
def __init__(self, *args, **kwargs):
if self.collection_name is None:
raise Exception('collection_name must be defined in class')
if self.serializer is None:
raise Exception('serializer must be defined in class')
collection = MarketPlace[self.collection_name]
if collection.count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.collection = collection
self.objects = self.objects_manager(**self.__dict__, **self.__class__.__dict__)
产品执行使用继承:
from marketplace import MarketPlaceCollection, CollectionObjectInstance
from settings import BASE_URL
URL_SUFFIX = 'product/'
CASH_PRICE_FEE = 50
LEASE_TERM_WEEKS = 52
class Product(CollectionObjectInstance):
def url(self):
url = BASE_URL + URL_SUFFIX + self.slug
return url
class Products(MarketPlaceCollection):
collection_name = 'FlatProduct'
serializer = Product
当你调用p.objects
你收集名单本身,就行了,可归因self.objects = MarketPlace[collection]
。您的Products
不再控制.objects
属性中的方法或属性 - 它是由pymongo返回的对象。
因此,要控制Products.objects
的方法和属性,必须使用所需的方法创建另一个类,并在尝试检索Products.objects
时返回该类的对象。
尽管Python具有“属性”装饰器和描述符协议,并且您的objects
属性的更复杂的自动化可以使用它们,但在这种情况下,它可以以非常直接的方式制作。只要有接收集合另一个类,并代理其他属性的集合,通过实施它__getattr__
:
class ObjectList(object):
def __init__(self, collection, cls):
self.collection = collection
self.cls = cls
def find_one(self, *args, **kw):
raw_list = self.collection.find_one(*arg, **kw)
objects = [self.cls(**obj) for obj in raw_list]
return objects[0] if len(objects) == 1 else objects
def __getattr__(self, attr):
"""this is called automatically by Python when a
normal attribute is not found in this object
"""
return getattr(self.collection, attr)
class MarketPlaceObjects(object):
def __init__(self, collection, cls, fields=None, default_filter=None):
self.collection_name = collection
self.fields = fields if fields else {}
self.default_filter = default_filter if defaut_filter else {}
if MarketPlace[collection].count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.objects = ObjectList(MarketPlace[collection], cls)
class Products(MarketPlaceObjects):
def __init__(self):
super(Products, self).__init__(collection='FlatProduct', cls=Product)
谢谢!在我看到您的答案之前,我最终编写了一个解决方案。但是,我肯定会重写我的代码以采用您使用的一些技术。我的代码目前看起来非pythonic哈哈。 –
除了你的问题,还有就是在你的代码的Python begginers一个常见的错误:你不应该使用像{}}这样的可变对象作为函数或方法的默认参数。这是因为这些dictioanaries是在模块加载时创建的,并且在每次调用该函数或方法时都会重新使用。使用'None'作为默认值,并在方法体内使用'if'语句将参数分配给空dict。 – jsbueno
真的!我试图避免ifs,因为我认为它的广告开销。你认为如果使用if,然后分配空字典,性能会更好? –