Python中的动态查找器和方法缺失
我正在尝试在Python中实现类似Rails动态查找器的功能(用于web应用/GAE)。动态查找器的工作方式是这样的:
- 你的Person类有一些字段:名字、年龄和电子邮件。
- 假设你想找到所有名字是“Robot”的用户。
Person类有一个叫“find_by_name”的方法,它接收名字并返回查询的结果:
@classmethod
def find_by_name(cls, name):
return Person.gql("WHERE name = :1", name).get()
我不想为每个属性都写一个这样的函数,我希望能有类似Ruby中的method_missing的方法,这样我就可以做到这一点。
到目前为止,我看到过这两篇博客文章:http://blog.iffy.us/?p=43 和 http://www.whatspop.com/blog/2008/08/method-missing-in-python.cfm,但我想听听最“合适”的做法是什么。
4 个回答
在编程中,有时候我们需要把一些数据存储起来,以便后续使用。这就像把东西放进一个盒子里,等需要的时候再拿出来。
有些时候,我们会用到一个叫做“数组”的东西。数组就像一个有很多小格子的盒子,每个格子里可以放一个数据。这样,我们就可以很方便地管理这些数据。
另外,还有一种叫做“对象”的东西。对象就像一个大盒子,里面可以放很多不同类型的数据和功能。比如,我们可以把一个人的名字、年龄和性别都放在一个对象里,这样就能把与这个人相关的信息集中在一起。
在编程时,我们还会用到“函数”。函数就像一个小机器,输入一些东西,它就能给你输出你想要的结果。这样,我们就可以把一些重复的工作放到函数里,随时调用,省时省力。
总之,编程就像是在用各种盒子和机器来整理和处理信息,让我们的工作变得更简单。
class Person(object):
def __getattr__(self, name):
if not name.startswith("find_by"): raise AttributeError(name)
field_name = name.split("find_by_",1)[1]
return lambda name: Person.gql("WHERE %s = :1" % field_name, name).get()
你可以使用一个叫做 'find_by' 的方法,配合一些关键词,就像Django那样:
class Person (object):
def find_by(self, *kw):
qspec = ' AND '.join('%s=%s' % kv for kv in kw.items())
return self.gql('WHERE ' + qspec)
person.find_by(name='Robot')
person.find_by(name='Robot', age='2')
走这条路的话,你可能会自己设计查询的语法。可以看看Django是怎么做的...
其实在这里用GQL并没有必要——这样反而让事情变得复杂。下面是一个简单的实现:
class FindableModel(db.Model):
def __getattr__(self, name):
if not name.startswith("find_by_"):
raise AttributeError(name)
field = name[len("find_by_"):]
return lambda value: self.all().filter(field, value)
注意,它返回的是一个查询对象,你可以在这个对象上调用 .get()、.fetch() 等方法;这样做更灵活,不过如果你想的话,也可以让它只返回一个单独的实体。