我如何在Python中引用函数体外的类方法?

时间:2009-05-22 13:06:21

标签: python

我想在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 个答案:

答案 0 :(得分:2)

我建议减少类的数量 - 记住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 :(得分:1)

我开始接受python在类定义中的函数式编程时不是很直观。见this question。第一种方法的问题是Observer在构建类之前不存在作为命名空间。第二个问题是你创建了一个类方法,它在创建命名空间之前并没有真正做到它应该做的事情。 (我不知道为什么你要尝试第三种。)在这两种情况下,直到Observer的类定义都被填充后才会发生这些事情。

这可能听起来像一个悲伤的约束,但它真的不是那么糟糕。只需在类定义后注册即可。一旦你意识到在模块体内的类上执行某些初始化例程并且在类的主体之外进行某些初始化例程并不坏,python就会变得更加友好。尝试: class Observer:

# 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的任何地方只执行一次(禁止进程分叉以及其他一些不相关的边界情况)。

答案 2 :(得分:0)

糟糕。对于那个很抱歉。 我所要做的就是在类定义之外移动订阅

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的副作用,人们不会立即想到这一点。

答案 3 :(得分:0)

你在做什么应该工作:

>>> 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...