I use Boto to access Amazon S3. And for file uploading I can assign a callback function. The problem is that I cannot access the needed variables from that callback function until I make them global. In another hand, if I make them global, they are global for all other Celery tasks, too (until I restart Celery), as the file uploading is executed from a Celery task.
我使用Boto访问Amazon S3。对于文件上传,我可以分配一个回调函数。问题是我无法从该回调函数访问所需的变量,直到我将它们设为全局变量。另一方面,如果我将它们设置为全局,那么它们也是所有其他Celery任务的全局(直到我重新启动Celery),因为文件上载是从Celery任务执行的。
Here is a function that uploads a JSON file with information about video conversion progress.
这是一个上传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")
And here are 2 callback functions for uploading frames generated by ffmpeg during the video conversion and a JSON file with the progress information.
这里有2个回调函数,用于上传视频转换过程中ffmpeg生成的帧和带有进度信息的JSON文件。
# 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
Theoretically, I could pass the uploading_frame variable to the upload_json function, but it wouldn’t get to json_upload_callback as it’s executed by Boto.
从理论上讲,我可以将uploaded_frame变量传递给upload_json函数,但是由于它是由Boto执行的,它不会到达json_upload_callback。
In fact, I could write something like this.
事实上,我可以写这样的东西。
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
Which, however, doesn’t let you edit the value from the function, just lets you read the value.
但是,这不允许您编辑函数中的值,只是让您读取值。
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")
And this gives an UnboundLocalError: local variable 'stuff' referenced before assignment.
这给出了一个UnboundLocalError:在赋值之前引用的局部变量'stuff'。
Thanks.
3 个解决方案
#1
12
In Python 2.x closures are read-only. You can however use a closure over a mutable value... i.e.
在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")
If you are instead using Python 3.x the keyword nonlocal
can be used to specify that a variable used in read/write in a closure is not a local but should be captured from the enclosing scope:
如果您使用的是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")
#2
3
You could create a partial function via functools.partial
. This is a way to call a function with some variables pre-baked into the call. However, to make that work you'd need to pass a mutable value - eg a list or dict - into the function, rather than just a bool.
您可以通过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]
#3
0
A simple way to do these things is to use a local function
执行这些操作的一种简单方法是使用本地函数
def myfunc():
stuff = 17
def lfun(arg):
print "got arg", arg, "and stuff is", stuff
stuff += 1
def register_callback(lfun)
This will create a new function every time you call myfunc, and it will be able to use the local "stuff" copy.
这将在每次调用myfunc时创建一个新函数,并且它将能够使用本地“stuff”副本。
#1
12
In Python 2.x closures are read-only. You can however use a closure over a mutable value... i.e.
在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")
If you are instead using Python 3.x the keyword nonlocal
can be used to specify that a variable used in read/write in a closure is not a local but should be captured from the enclosing scope:
如果您使用的是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")
#2
3
You could create a partial function via functools.partial
. This is a way to call a function with some variables pre-baked into the call. However, to make that work you'd need to pass a mutable value - eg a list or dict - into the function, rather than just a bool.
您可以通过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]
#3
0
A simple way to do these things is to use a local function
执行这些操作的一种简单方法是使用本地函数
def myfunc():
stuff = 17
def lfun(arg):
print "got arg", arg, "and stuff is", stuff
stuff += 1
def register_callback(lfun)
This will create a new function every time you call myfunc, and it will be able to use the local "stuff" copy.
这将在每次调用myfunc时创建一个新函数,并且它将能够使用本地“stuff”副本。