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

如何在Python中引用函数体外部的类方法?,python,Python,我想在Observer中进行一次性回调注册。我不想在init或其他函数中进行注册。我不知道init是否有类级别的等价物 class Observer: @classmethod def on_new_user_registration(new_user): #body of handler... # first I try NewUserRegistered().subscribe \

我想在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

我已经接受python在类定义中进行函数编程时不是很直观。看见第一个方法的问题是,在类构建之前,观察器不作为名称空间存在。第二种方法的问题是,您创建了一个类方法,它在创建名称空间之后才真正执行它应该执行的操作。(我不知道为什么要尝试第三种方法。)在这两种情况下,在填充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)
@staticmethod
@new_user.subscribe
def on_new_user_registration(info, username):
    print "new user: %s" % username
由于模块在python中的工作方式,您可以保证无论在哪里导入观察器,都会执行一次且仅执行一次注册(禁止进程分叉和其他一些不相关的边界情况)。

oops。很抱歉。 我所要做的就是将订阅移到类定义之外

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

您正在做的应该是:

>>> 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参数而不是自参数。因此,您的类定义应该如下所示:

class Observer:

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

我建议减少类的数量——记住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类,那么您可以这样做:

class Observer:

    @classmethod
    def on_new_user_registration(cls, new_user):
        #body of handler...
班级观察员:

# 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)
@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\u new\u user\u registration
作为订阅参数。

您使用的是什么版本的Python?在Python2.5中,在类中调用class方法对我来说很有效。这很奇怪。我使用的是2.5.1,下面的例子给了我NameError,这很可能是2.5.1中的一个bug。我想这足以阻止您使用我的语法。:-)但是请注意,
self
cls
都是完全任意的——它们只是(非常强大的)约定。不过我还是建议假装他们是语言强制的。没有什么理由不这样做。