Python中的动态查找器和方法缺失

5 投票
4 回答
4347 浏览
提问于 2025-04-15 11:51

我正在尝试在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=43http://www.whatspop.com/blog/2008/08/method-missing-in-python.cfm,但我想听听最“合适”的做法是什么。

4 个回答

0

在编程中,有时候我们需要把一些数据存储起来,以便后续使用。这就像把东西放进一个盒子里,等需要的时候再拿出来。

有些时候,我们会用到一个叫做“数组”的东西。数组就像一个有很多小格子的盒子,每个格子里可以放一个数据。这样,我们就可以很方便地管理这些数据。

另外,还有一种叫做“对象”的东西。对象就像一个大盒子,里面可以放很多不同类型的数据和功能。比如,我们可以把一个人的名字、年龄和性别都放在一个对象里,这样就能把与这个人相关的信息集中在一起。

在编程时,我们还会用到“函数”。函数就像一个小机器,输入一些东西,它就能给你输出你想要的结果。这样,我们就可以把一些重复的工作放到函数里,随时调用,省时省力。

总之,编程就像是在用各种盒子和机器来整理和处理信息,让我们的工作变得更简单。

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()
1

你可以使用一个叫做 '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是怎么做的...

8

其实在这里用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() 等方法;这样做更灵活,不过如果你想的话,也可以让它只返回一个单独的实体。

撰写回答