Как мне обратиться к методу класса вне тела функции в Python? - PullRequest
1 голос
/ 22 мая 2009

Я хочу сделать одноразовую регистрацию обратного вызова в Observer. Я не хочу делать регистрацию внутри init или другой функции. Я не знаю, есть ли эквивалент уровня класса для init

    class Observer:

        @classmethod
        def on_new_user_registration(new_user):
            #body of handler...

        # first I try

        NewUserRegistered().subscribe \
          (Observer.on_new_user_registration) #gives NameError for Observer

        #so I try

        NewUserRegistered().subscribe(on_new_user_registration) #says not callable

        #neither does this work

        NewUserRegistered().subscribe(__metaclass__.on_new_user_registration)


class BaseEvent(object):
    _subscriptions = {}

    def __init__(self, event_info = None):
        self.info = event_info

    def fire(self):
        for callback in self._subscriptions[event_type]:
            callback(event_info)

    def subscribe(self, callback):
        if not callable(callback):
            raise Exception(str(callback) + 'is not callable')
        existing = self._subscriptions.get(self.__class__, None)
        if not existing:
            existing = set()
            self._subscriptions[self.__class__] = existing
        existing.add(callback)

    class NewUserRegistered(BaseEvent):
        pass

Ответы [ 4 ]

2 голосов
/ 22 мая 2009

Предлагаю сократить количество классов - помните, что Python - это не Java. Каждый раз, когда вы используете @classmethod или @staticmethod, вы должны остановиться и подумать об этом, поскольку эти ключевые слова встречаются в Python довольно редко.

Делать так, как это работает:

class BaseEvent(object):
    def __init__(self, event_info=None):
        self._subscriptions = set()
        self.info = event_info

    def fire(self, data):
        for callback in self._subscriptions:
            callback(self.info, data)

    def subscribe(self, callback):
        if not callable(callback):
            raise ValueError("%r is not callable" % callback)
        self._subscriptions.add(callback)
        return callback

new_user = BaseEvent()

@new_user.subscribe
def on_new_user_registration(info, username):
    print "new user: %s" % username

new_user.fire("Martin")

Если вам нужен класс Observer, то вы можете сделать это следующим образом:

Наблюдатель класса:

@staticmethod
@new_user.subscribe
def on_new_user_registration(info, username):
    print "new user: %s" % username

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

Но вы, конечно, можете сделать это:

class Observer:
    def on_new_user_registration(self, info, username):
        print "new user: %s" % username

o = Observer()
new_user.subscribe(o.on_new_user_registration)

где мы используем границу o.on_new_user_registration в качестве аргумента для подписки.

1 голос
/ 22 мая 2009

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

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

# Define the other classes first

class Observer:
    @classmethod
    def on_new_user_registration(new_user):
        #body of handler...
NewUserRegistered().subscribe(Observer.on_new_user_registration)

В связи с тем, как модули работают в python, вам гарантируется, что эта регистрация будет выполняться один раз и только один раз (за исключением процесса разветвления и, возможно, некоторых других не относящихся к делу граничных случаев), куда бы ни импортировался Observer.

0 голосов
/ 22 мая 2009

То, что вы делаете, должно работать:

>>> class foo:
...     @classmethod
...     def func(cls):
...             print 'func called!'
...
>>> foo.func()
func called!
>>> class foo:
...     @classmethod
...     def func(cls):
...             print 'func called!'
...     foo.func()
...
func called!

Следует отметить, что методы класса принимают аргумент cls вместо аргумента self. Таким образом, определение вашего класса должно выглядеть так:

class Observer:

    @classmethod
    def on_new_user_registration(cls, new_user):
        #body of handler...
0 голосов
/ 22 мая 2009

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

class Observer:

        @classmethod
        def on_new_user_registration(new_user):
            #body of handler...

#after end of class

NewUserRegistered().subscribe(Observer.on_new_user_registration)

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

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