2012-11-11 3 views
3

필자는 옵션에 따라 다른 클래스에 추가 할 수있는 메소드가있는 클래스가 있습니다. 내 최초의 솔루션이나 mixin을 사용했지만,이 조금 추한 얻을 수 있습니다 : Python (2.7) : 클래스 메소드를 동적으로 추가하기

class Schedule(Enumerator, Humanizer, Inferer, ...): 
    ... 

그래서 나는 아마도 내가 같은 효과를 달성하기 위해 클래스 장식을 사용할 수 있습니다, 헤이 생각했다.

import inspect 

def inferer(original_class): 
    from myproj.lib.inferer import Inferer 
    methods = inspect.getmembers(Inferer, predicate=inspect.ismethod) 
    for method in methods: 
     setattr(original_class, method[0], types.MethodTypes(method[1], original_class)) 
    return original_class 

... 장식 클래스에 적절 방법과 classmethods을 추가 할 것 : 여기

@enumerator 
@humanizer 
@inferer 
class Schedule(object): 
    ... 

그리고

은 장식 기능의 샘플입니다. 그러나 데코 레이팅 된 클래스에서 이러한 추가 된 메서드 (또는 classmethods) 중 하나를 호출하면 오류가 발생합니다. 방법에 대한

:

>>> Schedule().humanize() 
TypeError: unbound method humanize() must be called with Humanizer instance as first argument (got type instance instead) 

... 어떤이는 classmethods로 추가됩니다 표시하는 것? classmethods를 들어

:

>>> schedule = Schedule.infer(foo) 
TypeError: infer() takes exactly 2 arguments (3 given) 

참고 추론의 정의 :

class Inferer(object): 
    @classmethod 
    def infer(cls, dates): 
     ... 

내가 그것을 호출하기 때 어떤 인수를 보여 infer에 몇 줄을 추가 Schedule.infer() 등 :

cls: <class 'myproj.lib.inferer.Inferer'> 
dates: <class 'myproj.Schedule'> 

그럼 내 질문 :

데코레이터 기능에서 이러한 추가 된 메서드와 클래스 메서드가 이상하게 작동하게하려면 어떻게됩니까? 아니면, 더 잘 넣어,이 추가 기능을 제대로 처리하기 위해 데코레이터 기능을 수정하는 방법은 무엇입니까?

언제든지 설명해 드릴 수 있는지 알려 주시기 바랍니다.

+2

그래서 ... 전통적인 구문이보기 싫어서 데코레이터를 사용하는 유일한 이유는 무엇입니까? 이것은 미학적 인 것만으로도 엄청난 양의 작업과 추가적인 코드 취약성처럼 들립니다. –

+0

왜 이런 장식을 사용하는 것이 믹스 인을 사용하는 것보다 덜 추악 할 (문제가있는) 것이라고 생각하는지 모르겠습니다. 그것은 당신이하려는 일을 성취하기 위해 메타 클래스를 사용해야 할 수도 있다고 말했습니다. 몇 년 전에 필자는 함수 콜렉션에서 즉석에서 클래스를 생성하는 시스템을 설정하고 그것을 위해 메타 클래스를 사용했던 것을 기억합니다. (모든 세부 사항을 지금은 기억하지 마십시오.) –

+0

나는 동의한다 : 믹스 인은 더 간단하고 명확 해 보이고 실제로 작동한다. 왜이 모든 곤경에 빠지겠습니까? –

답변

4

이것은 좋은 아이디어 였다고합시다. 이것은 달성 할 수있는 한 가지 방법입니다. 그래도 내가 조언 할 수는 없다.

class Inferer(object): 
    @classmethod 
    def foo(cls): 
     return "bar" + cls.__name__ 

inferer = horrible_class_decorator_factory(Inferer) 

@inferer 
class X(object): 
    pass 

X.foo() 
"barX" 

나는이 하나에 덧글로 해요 :

def horrible_class_decorator_factory(mixin): 
    def decorator(cls): 
     d = cls.__dict__.copy() 
     bases = tuple([b for b in cls.__bases__ if b != object] + [mixin]) 
     return type(cls.__name__, bases, d) 
    return decorator 

이제 당신은 이런 식으로 뭔가를 할 수 있습니다. 네가 할 수 있다고해서 네가해야한다는 뜻은 아니다.

+0

이유가 무엇입니까? 코멘트 작성자와 여러분으로부터 들었을 때, 그것은 끔찍한 아이디어이고 허약합니다 (BTW의 지적한 함수 이름 덕분입니다). 특히 도움이됩니다. – JEEND0

+0

Python은 읽기 쉽고 이해하기 쉽도록 만들어졌으며, 일단 가장 기본적인 구문으로 어지럽게 시작하면 코드가 나 빠지거나 명확하지 않을 수 있습니다. 당신의 미학 감각 때문에 일을 정말로 유혹 할 수 있습니다. 언어를 고안 한 사람들은 많은 생각을했습니다. 그들은 당신에게 많은 내성적이고 커스터마이징하는 힘을주었습니다. 그러나 당신 자신을 걸만한 충분한 밧줄 이상입니다. – BenTrofatter

+0

왜 이것이 나쁜지에 대한 좋은 예를 생각해보십시오. 이 믹스 중 몇 가지를 가지고 있다고 가정 해 봅시다. 어떤 이유로 든 기본 클래스에서 상속 받았다고 가정 해 봅시다. 나는 어떤 종류의 기초 수업도 점검하지 않았다. 갑자기, 나는 MRO (method resolution order) 문제를 도입했다. Django Model 기본 클래스를 살펴 보겠습니다. 매우 빠르게 복잡해집니다. – BenTrofatter