2011-01-27 57 views
5

我使用Boto訪問Amazon S3。而對於文件上傳,我可以分配一個回調函數。問題是,我無法從該回調函數訪問所需的變量,直到我使它們成爲全局變量。另一方面,如果我使它們成爲全局的,它們對於所有其他Celery任務也是全局的(直到我重新啓動Celery),因爲文件上傳是從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 

從理論上講,我可以通過uploading_frame變量的upload_json功能,但它不會得到,因爲它是由寶途執行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") 

This Works。

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 2011-01-27 10:48:46

回答

12

在Python 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") 

如果您是不是使用Python 3.x中nonlocal可用於指定,在封閉的讀/寫使用的變量是關鍵詞不是本地的,但應該從封閉範圍被捕獲:

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") 
0

一個簡單的方法做這些事情是使用本地函數

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

這將創建一個新的功能,每次調用myfunc的時間,這將能夠使用本地的「東西」的副本。

+0

請參閱上面的更新。 – aruseni 2011-01-27 11:15:41

+0

謝謝你的回答。 – aruseni 2011-01-27 11:45:32

+1

[This does not work。](http://codepad.org/p3N4gXLC) – 2011-01-27 12:18:52

3

您可以通過functools.partial創建部分功能。這是一種調用函數,其中包含一些預先寫入調用的變量。但是,爲了完成這項工作,您需要將一個可變值(例如列表或字典)傳遞給該函數,而不僅僅是一個布爾值。

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]