ссылки на методы класса в списках классов в Python - PullRequest
2 голосов
/ 29 августа 2009

Я пишу класс в Python 2.6.2, который содержит таблицу поиска. Большинство случаев достаточно просты, чтобы таблица содержала данные. Некоторые случаи более сложны, и я хочу иметь возможность вызывать функцию. Однако я сталкиваюсь с некоторыми проблемами при обращении к этой функции.

Вот пример кода:

class a:
    lut = [1,
           3,
           17,
           [12,34],
           5]

Где lut является статическим, и ожидается, что оно также будет постоянным.

и теперь я хочу сделать следующее:

class a:
    def spam0(self):
        return (some_calculation_based_on_self)

    def spam1(self):
        return (a_different_calculation_based_on_self)

    lut = [1,
           3,
           17,
           [12,34],
           5,
           self.spam0
           self.spam1]

Не компилируется, потому что self.spam0 и self.spam1 не определены. Я попытался использовать a.spam, но это также не определено. Как установить lut[5] для возврата ссылки на self.spam?

Редактировать: Это то, что я планирую сделать:

(продолжение определения class a): импортная проверка

# continue to somewhere in the definition of class a

def __init__(self, param):
    self.param = param

def eggs(self):
    tmp = lut[param]
    if (insect.isfunction(tmp)): # if tmp is self.spam()
        return tmp()             # should call it here
    return tmp

Поэтому я хочу либо вернуть простое значение, либо запустить дополнительный код, в зависимости от параметра.

Редактировать: lut не обязательно должно быть свойством класса, но методы spam0 и spam1 должны иметь доступ к членам класса, поэтому они должны принадлежать классу .

Я не уверен, что это лучший способ сделать это. Я все еще работаю над этим.

Ответы [ 7 ]

4 голосов
/ 29 августа 2009

В теле clas вы создаете класс; self нет, поэтому вы, очевидно, еще не можете сослаться на self.anything. Но и внутри этого тела пока нет a: имя a связывается после того, как тело класса готово. Таким образом, хотя это и не так очевидно, в теле класса a вы еще не можете сослаться на a.anything.

То, на что вы МОЖЕТЕ сослаться, это голые имена атрибутов класса, которые уже были связаны: например, вы можете просто использовать 5, spam] в конце списка lut. spam будет там как функция, как вы говорите, в какой-то момент, который вы хотите; не как метод, и, определенно, НЕ как метод класса (я не вижу classmethod НИКАКОГО ГДЕ в вашем коде, почему вы думаете, что метод класса волшебным образом возникнет, если вы явно не закроете функцию в classmethod встроенный, напрямую или декоратором?) - Я подозреваю, что использование вами «метода класса» на самом деле не относится к типу метода класса (хотя это, безусловно, сбивает с толку; -).

Итак, если вам позже понадобится вызвать эту функцию в каком-то экземпляре x из a, вы будете вызывать, например, a.lut[-1](x), с явно указанным аргументом.

Если вам нужно сделать что-то более тонкое, может быть возможно получить связанный или несвязанный метод некоторого вида в различных точках во время обработки (после создания класса или, если вам нужен метод связанного экземпляра, только после конкретный экземпляр создается). Но вы недостаточно четко и полностью объясняете, что именно вы хотите сделать, чтобы мы предложили очень подробную помощь по этим альтернативам на более позднем этапе.

2 голосов
/ 29 августа 2009

Пока вы находитесь в рамках класса, вы можете просто написать

class A:
    def spam(self):
        pass

    lut = [1, 2, 3, spam]

a = A()
print a.lut

дает

[1, 2, 3, <function spam at 0xb7bb764c>]

Не забывайте, что это функция в вашей таблице поиска, а не число, как вы, вероятно, предполагали. Вы, вероятно, хотите решить другую проблему.

1 голос
/ 02 сентября 2009

Помните, что в Python нет такой вещи, как статическая или постоянная. Просто сделайте его легким для чтения. Вот пример, который генерирует кэшированную версию lut для объекта:

class A(object):
    def __init__(self):
        self.__cached_lut = None

    def spam0(self):
        return (some_calculation_based_on_self)

    def spam1(self):
        return (a_different_calculation_based_on_self)

    @property
    def lut(self):
         if self.__cached_lut is None:
             self.__cached_lut = [1,
               3,
               17,
               [12,34],
               5,
               self.spam0()
               self.spam1()]
         return self.__cached_lut

a = A()
print a.lut
0 голосов
/ 29 августа 2009

Вы хотите, чтобы функция была связана с классом. Похоже, что ни один из ответов не относится к этому.

Это не будет сделано автоматически; когда вы делаете это:

class a:
    def spam(self): print self
    lut = [1, spam]

lut[1] - это сам спам, а не привязанный к объекту метод, поэтому вы не можете просто вызвать lut[1](); вам нужно будет позвонить lut[1](self).

Если вы специально хотите иметь возможность включать в список функции, которые можно вызывать напрямую, вам нужно организовать привязку функций, что означает обращение к ним из экземпляра, а не из класса. Для этого вы, вероятно, захотите инициализировать этот список из __init__:

class a:
    def spam(self): print self
    def __init__(self):
        self.lut = [1, self.spam]

и теперь self.lut[1]() правильно, так как это связанный метод.

Это все имеет то преимущество, что другие функции могут быть помещены в список для других целей, возможно, связаны с другими объектами или иным образом не ожидают параметр.

Недостатком является то, что вы не используете список между экземплярами; это может иметь или не иметь значения для вас.

0 голосов
/ 29 августа 2009

Trivial:

class a:
    @classmethod
    def spam(cls):
        # not really pass, but you get the idea
        pass

    lut = [1,
           3,
           17,
           [12,34],
           5,
           spam]


assert a().lut[-1] == a.spam
assert a.spam() is None
0 голосов
/ 29 августа 2009

Я не уверен, что понимаю вопрос. Это то, что вы имеете в виду?

class a:
    lut = [1,
           3,
           17,
           [12,34],
           5]

    def __init__(self):
        self.lut.append(self.spam)

    def spam(self, a):
        print "this is %s" % a

b = a()
b.lut[-1](4)

это выдаст: "это 4".

0 голосов
/ 29 августа 2009

Вам нужно переместить определение a.lut за пределы определения a.

class a():
    def spam():pass

a.lut = [1,2,3,a.spam]

Если подумать, это имеет смысл. Использование self не сработает, потому что self фактически определяется только для методов класса, для которых вы используете параметр "self". self не имеет специального значения в Python и не является зарезервированным словом; это просто обычный аргумент, передаваемый связанным методам класса, но он также может быть this или foo, или как вам угодно.

Ссылка на a.lut не работает, поскольку определение a еще не завершено. Как Python должен знать, в какой точке кода, что это такое? В области определения класса a сам a все еще не определен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...