2011-10-12 2 views
5

콜백 함수 세트를 지정하는 클래스가 있습니다 (여기에 cb1cb2으로 표시). 나는 어떤 사건 이후에 내가 부르고 싶은 이들의지도를 유지한다.사전의 콜백에 대한 파이썬 참조

class Foo: 
    cb1 = None 
    cb2 = None 

    def test(self, input): 
     for (name, callback) in map: 
      if name == input: 
       if callback: callback() 
       ... 

    map = {'one':cb1, 'two':cb2} 

def mycallback(): 
    print "mycallback()" 

f = Foo() 
f.cb1 = mycallback # Register our callback 
f.test('one')  # Nothing happens 

문제를 발견 할 수 있습니까? 어떻게됩니까

는, 클래스가 초기화 될 때, (모두 None 있습니다)을 cb1cb2지도로 복사하는 것입니다. 따라서 사용자가 콜백을 (cb1에 할당하여) 등록한 후에도지도의 값은 여전히 ​​None이고 아무 것도 호출되지 않습니다.

파이썬에는 '참조로 된'것이 없으므로 어떻게 수정해야합니까?

+0

Nitpick : 모든 것이 파이썬에서 '참조'전달됩니다. * name *이 아니라 참조에 의한 것입니다. 이름을 다른 객체에 다시 바인딩하면 이름이 가리키는 것과 다른 참조가 업데이트되지 않습니다. –

답변

9

클래스가 명시 적으로 등록을 처리하게하지 마시겠습니까?

import collections 

class Foo(object): 
    handlers = None 

    def __init__(self): 
     self.handlers = collections.defaultdict(set) 

    def register(self, event, callback): 
     self.handlers[event].add(callback) 

    def fire(self, event, **kwargs): 
     for handler in self.handlers.get(event, []): 
      handler(**kwargs) 

foo = Foo() 
foo.register('one', mycallback) 
foo.fire('one') 
+0

네 말이 맞아. 내 사전은 실제로 내가 제시 한 것보다 훨씬 복잡합니다. 구문 분석을위한 함수 및 다른 것들에 대한 참조가 있으므로 처음에는 이것을 호환 가능한 솔루션으로 간과했습니다. 그러나 지금은 그것을 보는 것이 가장 확실한 방법입니다. 고맙습니다! –

1

등록 기능을 추가하십시오.

def register(self, name, cb): self.map[name] = cb 

대신의 :

f.cb1 = mycallback 

사용 : 푸 클래스에서 반대로

f.register('one', mycallback) 
+0

감사합니다. 다른 사람이 당신을 때렸다. BTW, 내 영업 오타가 있었는지 -'fcb1 = mycallback' 대신에'cb1 = mycallback'을 사용 했으므로 대답을 편집하여 수정할 수 있습니다. –

-1

, 모든 파이썬에서 "참조"입니다. 그러나 None에 대한 참조를 사전에 복사하고 원래 슬롯을 변경해도 참조에 아무런 변화가 없습니다. 여분의 간접 참조 수준을 유지하려는 경우 가장 간단한 방법은 문자열을 저장하는 것입니다. 모든 콜백이이 클래스의 속성 인 경우 map을 제거하고 콜백 속성 이름 목록을 저장하십시오. callback_names = ['cb1', 'cb2']을 입력 한 다음 getattr(self, callback_name)()을 사용하여 콜백을 호출합니다. 지도가 필요하면 map = {'one': 'cb1', 'two': 'cb2'}을 할 수 있습니다.

속성을 사용하여 멋지게 할 수도 있지만 불필요하게 복잡해 보입니다.

0

델리게이트 설명자와 속성 속임수가 있습니다.

+0

영리하지만, 나는 질문자가 실제로 이런 복잡한 해결책이 필요하지 않다고 생각합니다. –

0

왜 실제로 실행하는 데 사용되는 것보다 콜백을 사용자 정의하기 위해 다른 변수를 설정해야합니까? 같은 변수를 사용하면 문제가 사라집니다. 이 같이 수있는 몇 가지 문법적으로

:

class CallbackMap(object): 
    pass 

class Foo(object): 
    callbacks = CallbackMap() 

    def test(self, input): 
     callback = getattr(Foo.callbacks, input) 
     if callback: callback() 

# setup defaults 
Foo.callbacks.one = None 
Foo.callbacks.two = some_default_callback 

# customize 
def mycallback(): 
    print "mycallback()" 

f = Foo() 
Foo.callbacks.one = mycallback # Register our callback 
f.test('one') # works 
관련 문제