Python 包装一个类';子类方法
我的主类定义如下:Python 包装一个类';子类方法,python,mongodb,class,generics,Python,Mongodb,Class,Generics,我的主类定义如下: 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, passwor
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()
它可以返回一个产品对象(来自单个返回的词典)或一个产品对象列表(来自返回的词典列表),而不是返回词典或词典列表
因为我不确定如何用我自己的产品类包装PyMongo集合类的find_one()或find()方法,所以我的日子不好过
更新(2017-07-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]
行中的属性所示。您的产品
不再控制.objects
属性中的方法或属性-它是pymongo返回的对象
因此,要控制产品.objects
的方法和属性,您必须使用所需的方法创建另一个类,并在尝试检索产品.objects
时返回该类的对象
尽管Python有“属性”装饰器和描述符协议,而且对象
属性的更复杂自动化可以利用它们,但在这种情况下,可以以非常简单的方式实现。只需使用另一个类来接收集合,并通过在其中实现\uuu getattr\uuuu
将其他属性代理到集合:
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)
除了您的问题之外,Python中还有一个常见错误:您不应该使用像
{}
这样的可变对象作为函数或方法的默认参数。这是因为这些词汇表是在加载模块时创建的,并在每次调用该函数或方法时重复使用。使用None
作为默认值,并在方法体中使用if
语句将参数指定给空dict。True!我尽量避免使用ifs,因为我认为这会增加广告开销。您认为使用if然后分配空dict性能更好吗?谢谢!在我看到你的答案之前,我最终编写了一个解决方案。然而,我肯定会重写我的代码,以吸收您使用的一些技术。我的代码现在看起来不是pythonic哈哈。