“你怎么看?”;标记“;一组Python方法供以后使用?(这些装饰师可以改进吗?)

“你怎么看?”;标记“;一组Python方法供以后使用?(这些装饰师可以改进吗?),python,decorator,Python,Decorator,我想将一些方法(在本例中是类方法,但不一定)标记为相关的,以便可以一起使用它们。我不想在all\u fruit中创建一个硬编码的方法列表,因为我不想在添加新类型的水果时遗漏它。理想情况下,我可以这样做: class Food: @classmethod @fruitdecorator def apples(clss, amount): return '%d apple(s)' % amount @classmethod @fruitdec

我想将一些方法(在本例中是类方法,但不一定)标记为相关的,以便可以一起使用它们。我不想在
all\u fruit
中创建一个硬编码的方法列表,因为我不想在添加新类型的水果时遗漏它。理想情况下,我可以这样做:

class Food:
    @classmethod
    @fruitdecorator
    def apples(clss, amount):
        return '%d apple(s)' % amount

    @classmethod
    @fruitdecorator
    def oranges(clss, amount):
        return '%d orange(s)' % amount

    @classmethod
    def carrots(clss, amount):
        return '%d carrot(s)' % amount

    @classmethod
    def all_fruit(clss, amount):
        pass # somehow return all methods decorated by @fruitdecorator

for method in Food.all_fruit():
    print method(Food, 2)
    # '2 apples'
    # '2 oranges'
我找到了decorator,它让我做以下的事情,这是可以的,但我想知道它是否可以简化。在这种情况下,我必须定义这个东西,并在之前、之后调用它,然后在fruit_baseket类方法中使用它,这似乎有点乏味。(我对非装饰解决方案持开放态度,但它们似乎是将“标记”和函数定义紧密联系在一起的最佳方式。)


装饰器接受一个函数并返回一个函数。我认为您的解决方案可能太笼统了,除非您认为还需要
vegetabledecorator
saldecarator
标记

Fruit_methods = []

def fruit(f):
    Fruit_methods.append(f)
    return f
或者,更一般地说:

import collections
Food_methods = collections.defaultdict(list)

def food_type(type):
    def store(f):
        Food_methods[type].append(f)
        return f
    return store

可以使用元类以更干净、更复杂的方式来实现这一点。如果您让decorator以某种方式标记其函数(例如,通过添加特殊属性),那么元类可以创建一个列表作为类变量,并用修饰函数填充它(它可以通过查找特殊属性来判断哪些函数被修饰)。下面是一个示例实现

class FoodMeta(type):
    def __new__(meta, name, bases, dct):
        fruit_methods = []
        for key, value in dct.items():
            if hasattr(value, 'fruity'):
                fruit_methods.append(value)
        dct['fruit_methods'] = fruit_methods
        return super(FoodMeta, meta).__new__(meta, name, bases, dct)

def fruitdecorator(f):
    def inner(*args, **kwargs):
        # do whatever
        pass
    inner.fruity = True
    return inner

class Food(object):
    __metaclass__ = FoodMeta

    @fruitdecorator
    @classmethod
    def apples(clss, amount):
        return '%d apple(s)' % amount

    @fruitdecorator
    @classmethod
    def oranges(clss, amount):
        return '%d orange(s)' % amount

    @classmethod
    def carrots(clss, amount):
        return '%d carrot(s)' % amount

    @classmethod
    def fruit_basket(clss, amount):
        basket = [xx(clss, amount) for xx in clss.fruit_methods]
        return basket

Food.fruit_methods # [Food.apples, Food.oranges]

在这个解决方案中需要注意的一个关键问题是,修饰符的顺序很重要:
groutdecorator
必须在外部进行(即,apply after)
classmethod
。这是因为
classmethod
decorator没有保留方法上的
furty
属性,因此元类一开始就不知道它已注册。

您使用的是哪种Python版本?在3.6版本中,使用
\uuuuu set\u name\uuuuu
(与名称相反,它并不局限于设置名称)。好问题:我正在使用2.7.10,并正在寻找最佳解决方案。话虽如此,我愿意接受升级的诱人理由。
class FoodMeta(type):
    def __new__(meta, name, bases, dct):
        fruit_methods = []
        for key, value in dct.items():
            if hasattr(value, 'fruity'):
                fruit_methods.append(value)
        dct['fruit_methods'] = fruit_methods
        return super(FoodMeta, meta).__new__(meta, name, bases, dct)

def fruitdecorator(f):
    def inner(*args, **kwargs):
        # do whatever
        pass
    inner.fruity = True
    return inner

class Food(object):
    __metaclass__ = FoodMeta

    @fruitdecorator
    @classmethod
    def apples(clss, amount):
        return '%d apple(s)' % amount

    @fruitdecorator
    @classmethod
    def oranges(clss, amount):
        return '%d orange(s)' % amount

    @classmethod
    def carrots(clss, amount):
        return '%d carrot(s)' % amount

    @classmethod
    def fruit_basket(clss, amount):
        basket = [xx(clss, amount) for xx in clss.fruit_methods]
        return basket

Food.fruit_methods # [Food.apples, Food.oranges]