Python方法查找,静态与实例

时间:2011-06-01 20:33:47

标签: python static monkeypatching

直到一小时前,我确信在python Foo ().bar ()中只不过是Foo.bar (Foo () )的简写,它将实例作为第一个参数传递。在这个例子中,最后两行(显然)做了同样的事情:

class Foo (object):
    def bar (self): print "baz"

qux = Foo ()
qux.bar ()
Foo.bar (qux)

但是现在我有一个Animal类,它有一个静态方法populate(),它返回man已知的所有动物的列表。此外,Animal的每个实例都有一个方法populate(),它使用随机值填充实例的属性。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import random

animals = [ ("Bella", "cow"), ("Spike", "dog"), ("José", "iguana"), ("Tux", "penguin") ]

class Animal (object):
    @staticmethod
    def populate (*args): return map (lambda x: Animal (*x), animals)

    def __init__ (self, name = None, species = None):
        def bar (): self.name, self.species = random.choice (animals)
        self.name = name
        self.species = species
        self.populate = bar

    def __repr__ (self): return "%s of species %s" % (self.name, self.species)

print Animal.populate ()
print Animal ("Pinky", "mouse")
qux = Animal ()
qux.populate ()
print qux

代码工作正常,但让我怀疑的是print Animal.populate (qux)调用静态填充方法(因此返回了一个列表并且没有填充糟糕的qux)。显然我坚信Foo ().bar ()只不过是Foo.bar (Foo () )的简称,这是错误的。

这为我提出了各种问题:

  1. 致电Foo ().bar ()时会发生什么?
  2. 致电Foo.bar (Foo () )时会发生什么?
  3. 两者之间是否存在内部差异?
  4. 我错过了python的一些基本概念吗?
  5. 如果你必须编写一个类,其静态populate方法除了在这个类的实例上调用的populate方法之外还有其它方法,那么这将是什么方式?
  6. (是的,它必须是同一个名字。)

3 个答案:

答案 0 :(得分:2)

静态方法和类方法是special descriptors。由于描述符的__get__()方法的参数包括类和任何相关实例,因此他们可以以任何他们喜欢的方式使用方法的参数。

答案 1 :(得分:2)

关于Foo()。bar(),Foo.bar(Foo())和Foo.bar()之间的区别(作为答案,因为我昨天注册了,还不能发表评论) - 这是因为Python(< 3.0)的'bound'和'unbound'方法的概念 - 它严格要求除了@staticmethod或@classmethod之外,方法调用都有一个与之关联的实例。解释它的方法并不比你必须要记住的东西更简单。 值得庆幸的是,这在Python 3中已经发生了变化 - “绑定”和“未绑定”方法的概念已经消失了,而且Foo.bar()在您的示例中运行良好。

答案 2 :(得分:0)

qnx.populate()首先查看qnx的实例populate。如果不存在,则会跟踪__mro__,直到找到名为populate的内容。

Animals.populate(qnx)正在跳过上述查找的第一步