2011-01-27 2 views
5

Boto를 사용하여 Amazon S3에 액세스합니다. 파일 업로드의 경우 콜백 함수를 할당 할 수 있습니다. 문제는 글로벌 변수가 될 때까지 해당 콜백 함수에서 필요한 변수에 액세스 할 수 없다는 것입니다. 다른 한편으로, 내가 글로벌하게 만들면 파일 업로드가 Celery 태스크에서 실행되기 때문에 셀로리를 재시작 할 때까지 다른 모든 셀러리 작업에 대해 전역 적입니다.콜백 함수에서 변수에 액세스 (및 편집)하는 방법은 무엇입니까?

다음은 비디오 변환 진행에 대한 정보가있는 JSON 파일을 업로드하는 기능입니다.

def upload_json(): 
    global current_frame 
    global path_to_progress_file 
    global bucket 
    json_file = Key(bucket) 
    json_file.key = path_to_progress_file 
    json_file.set_contents_from_string('{"progress": "%s"}' % current_frame, 
    cb=json_upload_callback, num_cb=2, policy="public-read") 

그리고 여기에 비디오 변환 및 진행 정보와 JSON 파일시는 FFmpeg에 의해 생성 된 프레임을 업로드 2 개 콜백 함수입니다.

# Callback functions that are called by get_contents_to_filename. 
# The first argument is representing the number of bytes that have 
# been successfully transmitted from S3 and the second is representing 
# the total number of bytes that need to be transmitted. 
def frame_upload_callback(transmitted, to_transmit): 
    if transmitted == to_transmit: 
     upload_json() 
def json_upload_callback(transmitted, to_transmit): 
    global uploading_frame 
    if transmitted == to_transmit: 
     print "Frame uploading finished" 
     uploading_frame = False 

이론적으로, 나는 upload_json 함수에 uploading_frame 변수를 전달할 수 있지만,이 BOTO에 의해 실행됩니다으로 json_upload_callback에 도착하지 않을 것입니다.

사실 이런 식으로 쓸 수 있습니다.

In [1]: def make_function(message): 
    ...:  def function(): 
    ...:   print message 
    ...:  return function 
    ...: 

In [2]: hello_function = make_function("hello") 

In [3]: hello_function 
Out[3]: <function function at 0x19f4c08> 

In [4]: hello_function() 
hello 

그러나이 값은 함수에서 값을 편집 할 수 없도록하기 때문에 값을 읽을 수 있습니다.

def myfunc(): 
    stuff = 17 
    def lfun(arg): 
     print "got arg", arg, "and stuff is", stuff 
    return lfun 

my_function = myfunc() 
my_function("hello") 

이것은 작동합니다.

def myfunc(): 
    stuff = 17 
    def lfun(arg): 
     print "got arg", arg, "and stuff is", stuff 
     stuff += 1 
    return lfun 

my_function = myfunc() 
my_function("hello") 

그리고 UnboundLocalError : 지역 변수 'stuff'가 할당 전에 참조됩니다.

감사합니다.

+0

귀하의 예 uploading_frame를 사용하는 방법을 보여줍니다하지 않는, 그래서 당신이 그것을 이벤트를 원하는 이유를 이해하기 어렵다 : 로컬되지하지만 바깥 범위에서 캡처해야합니다. 더 명확하게 문제를 보여주는 S3 관련 자료 없이도 간단한 예제를 작성하면 도움이 될 것입니다. – dkagedal

답변

12

파이썬 2.x 클로저는 읽기 전용입니다. 당신은 그러나 즉

def myfunc(): 
    stuff = [17] # <<---- this is a mutable object 
    def lfun(arg): 
     print "got arg", arg, "and stuff[0] is", stuff[0] 
     stuff[0] += 1 
    return lfun 

my_function = myfunc() 
my_function("hello") 
my_function("hello") 

대신 파이썬을 사용하는 경우 nonlocal가 폐쇄에 읽기/쓰기에 사용되는 변수가 지정하는 데 사용할 수있는 키워드를 3.X ... 변경 가능한 값보다 클로저를 사용할 수 있습니다

def myfunc(): 
    stuff = 17 
    def lfun(arg): 
     nonlocal stuff 
     print "got arg", arg, "and stuff is", stuff 
     stuff += 1 
    return lfun 

my_function = myfunc() 
my_function("hello") 
my_function("hello") 
+1

대단히 고마워요! 그게 효과가있어! – aruseni

+0

Python 3에서는 클로저가 읽기 전용이 아니지만 'nonlocal'을 사용하여 수정 된 변수를 지정해야합니다. –

0

이런 일을 할 수있는 간단한 방법이 새로운 기능 당신이이 myfunc를 호출 할 때마다 생성되며,이 지방의 "물건"복사를 사용할 수 있습니다 로컬 기능을

def myfunc(): 
    stuff = 17 
    def lfun(arg): 
     print "got arg", arg, "and stuff is", stuff 
     stuff += 1 
    def register_callback(lfun) 

을 사용하는 것입니다.

+0

위의 업데이트를 참조하십시오. – aruseni

+0

답변 해 주셔서 감사합니다. – aruseni

+1

[이 작동하지 않습니다.] (http://codepad.org/p3N4gXLC) –

3

functools.partial을 통해 부분 기능을 만들 수 있습니다. 이것은 미리 호출 된 일부 변수가있는 함수를 호출하는 방법입니다. 그러나, 그 일을하기 위해서 당신은 변경 가능한 값 (예 : 목록 또는 사전)을 bool이 아닌 함수에 전달해야합니다.

from functools import partial 
def callback(arg1, arg2, arg3): 
    arg1[:] = [False] 
    print arg1, arg2, arg3 

local_var = [True] 
partial_func = partial(callback, local_var) 

partial_func(2, 1) 
print local_var # prints [False] 
+0

대단히 감사합니다! 그게 효과가있어! – aruseni

관련 문제