2017-04-14 2 views
1

몇 가지 메소드 (이 경우 클래스 메소드)를 관련 항목으로 표시하여 함께 사용할 수 있습니다. all_fruit 안에 메서드의 하드 코드 된 목록을 만들고 싶지 않습니다. 왜냐하면 새로운 유형의 과일을 추가 할 때 놓치고 싶지 않기 때문입니다. 이상적으로, 나는 이런 식으로 뭔가를 할 수있을 것입니다 : 나중에 사용할 수 있도록 Python 메서드 그룹을 "표시"하는 방법은 무엇입니까? (이 데코레이터를 개선 할 수 있습니까?)

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' 

나는 나를 OK입니다 다음을 수행 할 수 these 장식 answers를 찾았지만 전혀 단순화 할 수 있는지 궁금 해서요. 이 경우 나는이 물건을 정의하고 그것을 전에, 후에 호출해야하고, 약간 지루하게 보이는 fruit_baseket 클래스 메소드에서 사용해야한다. (나는 비 장식 솔루션 열려있어 그러나 그들은 "마크"와 함께 가까운 함수 정의를 유지하는 가장 좋은 방법처럼 보인다.)

def MakeDecorator(): 
    registry = [] 
    def decorator(fn): 
     # print dir(fn) 
     registry.append(fn) 
     return fn 
    decorator.all = registry 
    return decorator 

fruitdecorator = MakeDecorator() 

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 fruit_basket(clss, amount): 
     basket = [xx(clss, amount) for xx in clss.fruit_methods] 
     return basket 


Food.fruit_methods = fruitdecorator.all 
print Food.fruit_basket(2) 
+0

어떤 Python 버전을 사용하고 있습니까? 3.6에서'__set_name__'을 사용하면 훨씬 쉽습니다 (이름과는 달리 이름 설정에만 국한되지 않습니다). – user2357112

+0

좋은 질문 : 저는 2.7.10을 사용하고 있으며 그걸로 최상의 솔루션을 찾고 있습니다. 즉, 나는 업그레이드해야 할 이유를 열어두고 있습니다. – zekel

답변

1

데코레이터는 기능을 소요하고 함수를 반환합니다. vegetabledecoratorsaladdecorator 마커가 필요하지 않으면 솔루션이 너무 일반적이라고 생각합니다. 더 일반적으로

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 
1

그것은 메타 클래스를 사용하여 좀 더 복잡한 방법 경우,보다 깨끗한에서이 작업을 수행 할 수 있습니다. 데코레이터 플래그가 어딘가에 (예를 들어, 특별한 속성을 추가함으로써) 기능한다면, 메타 클래스는 클래스 변수로리스트를 생성하고 데코 레이팅 된 함수로 채울 수 있습니다 (찾고있는 것을 장식 할 수 있습니다). 특수 속성). fruitdecoratorclassmethod (즉, 후 적용) 외부에 가야한다 : 샘플 구현은

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] 

이 솔루션에 주목해야 할 결정적인 것은 장식 문제의 순서가 있다는 것입니다 것입니다. 이는 classmethod 데코레이터가 메서드에 fruity 특성을 보존하지 않기 때문에 메타 클래스가 처음에 등록되었음을 알 수 없기 때문입니다.

관련 문제