2011-01-27 25 views
5

Tôi sử dụng Boto để truy cập Amazon S3. Và để tải tệp lên, tôi có thể gán chức năng gọi lại. Vấn đề là tôi không thể truy cập các biến cần thiết từ hàm gọi lại đó cho đến khi tôi làm cho chúng toàn cầu. Mặt khác, nếu tôi làm cho chúng toàn cầu, chúng là toàn cầu cho tất cả các nhiệm vụ Celery khác (cho đến khi tôi khởi động lại Celery), khi việc tải lên tệp được thực thi từ một nhiệm vụ Celery.Làm thế nào để truy cập (và chỉnh sửa) các biến từ một chức năng gọi lại?

Đây là chức năng tải lên tệp JSON có thông tin về tiến trình chuyển đổi video.

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

Và đây là 2 chức năng gọi lại để tải lên khung được tạo bởi ffmpeg trong quá trình chuyển đổi video và tệp JSON với thông tin tiến trình.

# 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 

Về mặt lý thuyết, tôi có thể chuyển biến upload_frame sang hàm upload_json, nhưng sẽ không chuyển thành json_upload_callback khi Boto thực hiện.

Trong thực tế, tôi có thể viết một cái gì đó như thế này.

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 

Tuy nhiên, không cho phép bạn chỉnh sửa giá trị từ hàm, chỉ cho phép bạn đọc giá trị.

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

my_function = myfunc() 
my_function("hello") 

Công trình này hoạt động.

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

Và điều này cho phép UnboundLocalError: biến cục bộ 'stuff' được tham chiếu trước khi gán.

Cảm ơn.

+0

dụ của bạn không hiển thị như thế nào uploading_frame được sử dụng, vì vậy rất khó để hiểu tại sao bạn sự kiện muốn nó. Tạo một ví dụ đơn giản hơn mà không cần bất kỳ thứ gì liên quan đến S3, rõ ràng hơn cho thấy vấn đề có lẽ cũng sẽ giúp ích. – dkagedal

Trả lời

12

Trong đóng gói Python 2.x là chỉ đọc. tuy nhiên bạn có thể sử dụng một đóng cửa hơn một giá trị có thể thay đổi ... tức là

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

Nếu bạn đang thay vì sử dụng Python 3.x từ khóa nonlocal thể được sử dụng để xác định rằng một biến được sử dụng ở chế độ đọc/ghi trong một kết thúc là không phải là một địa phương nhưng phải được chụp từ phạm vi kèm theo:

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

Cảm ơn bạn rất nhiều! Điều đó hoạt động! – aruseni

+0

Trong đóng cửa Python 3 không chỉ đọc, nhưng bạn phải chỉ định các biến được sửa đổi với 'nonlocal'. –

0

Một cách đơn giản để làm những điều này là sử dụng một chức năng địa phương

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

này sẽ tạo ra một chức năng mới mỗi khi bạn gọi myfunc, và nó sẽ có thể sử dụng các địa phương "công cụ" bản sao.

+0

Vui lòng xem phần cập nhật ở trên. – aruseni

+0

Cảm ơn bạn đã trả lời. – aruseni

+1

[Tính năng này không hoạt động.] (Http://codepad.org/p3N4gXLC) –

3

Bạn có thể tạo chức năng một phần qua functools.partial. Đây là một cách để gọi một hàm với một số biến được nướng sẵn trong cuộc gọi. Tuy nhiên, để thực hiện công việc đó, bạn cần chuyển một giá trị có thể thay đổi được - ví dụ: danh sách hoặc dict - vào hàm, thay vì chỉ là một 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

Cảm ơn bạn rất nhiều! Điều đó hoạt động! – aruseni

Các vấn đề liên quan