动态地将类方法添加到类中
我有以下代码段:
FEED_TYPES = [
('fan_mail', 'Fan Mail'),
('review', 'Review'),
('tip', 'Tip'),
('fan_user', 'Fan User'),
('fan_song', 'Fan Song'),
('fan_album', 'Fan Album'),
('played_song', 'Played Song'),
('played_album', 'Played Album'),
('played_radio', 'Played Radio'),
('new_event', 'New Event'),
]
class Feed:
@classmethod
def do_create(cls, **kwargs):
print kwargs
@classmethod
def create(cls, type, **kwargs):
kwargs['feed_type'] = type
cls.do_create(**kwargs)
for type_tuple in FEED_TYPES:
type, name = type_tuple
def notify(self, **kwargs):
print "notifying %s" % type
self.create(type, **kwargs)
notify.__name__ = "notify_%s" % type
setattr(Feed, notify.__name__, classmethod(notify))
Feed.create("FanMail", to_profile="Gerson", from_profile="Felipe")
Feed.notify_fan_mail(to_profile="Gerson2", from_profile="Felipe2")
想法是为每种Feed类型动态创建一个类方法(例如 notify_fan_mail ).效果几乎很好,唯一的问题是 print 语句始终打印"notify new_event",无论我调用哪种方法(与 notify_new_mail , notify_review ,等等.
The idea is to dynamically create one class method (like notify_fan_mail) for each feed type. It works almost great, the only problem is that the print statement always prints "notifying new_event", regardless of the method I call (same for notify_new_mail, notify_review, etc.).
我意识到这是因为它使用的是分配给type的最后一个值.我的问题是:如何动态创建对 type 类型使用正确值的方法?
I realize it's because it's using the last value assigned to type. My question is: how can I dynamically create methods that would use the correct value for type?
此外,如果我在Python文件中有此确切的代码,这是向Feed类添加方法的正确方法,还是还有一种更优雅的方法?
Also, if I have this exact code in a Python file, is that the correct way to add methods to the Feed class, or is there a more elegant way?
使用闭包保留kind
的值:
for type_tuple in FEED_TYPES:
kind, name = type_tuple
def make_notify(kind):
def notify(self, **kwargs):
print "notifying %s" % kind
self.create(kind, **kwargs)
return notify
notify = make_notify(kind)
notify.__name__ = "notify_%s" % kind
setattr(cls, notify.__name__, classmethod(notify))
顺便说一句,不要使用type
作为变量名,因为它会掩盖同名的内置变量.
By the way, don't use type
as a variable name since it shadows the builtin of the same name.
一种修改Feed
的更优雅的方法是创建一个类装饰器.这样可以更清楚地看到您有修改Feed
原始定义的代码.
A more elegant way to modify Feed
is to create a class decorator. This makes it clearer that you have code modifying the original definition of Feed
.
FEED_TYPES = [
('fan_mail', 'Fan Mail'),
('review', 'Review'),
('tip', 'Tip'),
('fan_user', 'Fan User'),
('fan_song', 'Fan Song'),
('fan_album', 'Fan Album'),
('played_song', 'Played Song'),
('played_album', 'Played Album'),
('played_radio', 'Played Radio'),
('new_event', 'New Event'),
]
def add_feed_types(cls):
for type_tuple in FEED_TYPES:
kind, name = type_tuple
def make_notify(kind):
def notify(self, **kwargs):
print "notifying %s" % kind
self.create(kind, **kwargs)
return notify
notify = make_notify(kind)
notify.__name__ = "notify_%s" % kind
setattr(cls, notify.__name__, classmethod(notify))
return cls
@add_feed_types
class Feed:
@classmethod
def do_create(cls, **kwargs):
print kwargs
@classmethod
def create(cls, kind, **kwargs):
kwargs['feed_type'] = kind
cls.do_create(**kwargs)
Feed.create("FanMail", to_profile="Gerson", from_profile="Felipe")
Feed.notify_fan_mail(to_profile="Gerson2", from_profile="Felipe2")