Поиск метода Python, статический или экземпляр - PullRequest
9 голосов
/ 02 июня 2011

До того момента, как примерно час назад, я был убежден, что в python Foo ().bar () является не чем иным, как короткой рукой для Foo.bar (Foo () ), которая передает экземпляр в качестве первого параметра.В этом примере последние две строки делают (очевидно) одно и то же:

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

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

Но теперь у меня есть класс Animal, у которого есть статический метод populate (), который возвращает список всех животных, известных человеку.Также у каждого экземпляра 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, вызываемого над экземпляром этого класса, какой путь вы бы выбрали?

(Да, этодолжно быть одно и то же имя.)

Ответы [ 3 ]

2 голосов
/ 02 июня 2011

О разнице между Foo (). Bar (), Foo.bar (Foo ()) и Foo.bar () (в качестве ответа, потому что я зарегистрировался вчера и пока не могу оставлять комментарии) - это потому, чтоконцепции Python (<3.0) о «связанных» и «несвязанных» методах - строго требуется, чтобы, за исключением @staticmethod или @classmethod, вызовы методов имели экземпляр, связанный с ними.Нет более простого способа объяснить это, чем просто что-то, что вы должны запомнить.К счастью, это изменилось в Python 3 - концепция «связанных» и «несвязанных» методов как отдельных элементов исчезла, и Foo.bar () прекрасно работает для вашего примера. </p>

2 голосов
/ 02 июня 2011

Статические методы и методы класса специальные дескрипторы .Поскольку аргументы метода дескриптора __get__() включают в себя как класс, так и любой соответствующий экземпляр, они могут связывать аргументы метода любым удобным для них способом.

0 голосов
/ 02 июня 2011

qnx.populate() сначала просматривает экземпляр qnx для populate.Если этого нет, то за __mro__ следуют до тех пор, пока не будет найдено что-то под названием * 1005.

Animals.populate(qnx) пропускает первый шаг в поиске выше

...