脚本中的Python变量作用域问题

标签 python scope

我遇到了一些奇怪的情况,变量设置后无法在其他函数中访问。这是一个名为 html.py

的 Celery 任务文件
base_path = ''

@app.task(bind=True)
def status(self):
    """
    returns the count of files downloaded and the timestamp of the most recently downloaded file
    """

    num_count = 0
    latest_timestamp = ''
    for root, _, filenames in os.walk(base_path):
        for filename in filenames:
            file_path = root + '/' + filename
            file_timestamp = datetime.fromtimestamp(os.path.getctime(file_path))
            if latest_timestamp == '' or file_timestamp > latest_timestamp:
                latest_timestamp = file_timestamp
            num_count += 1

@app.task(bind = True)
def download(self, url='', cl_id=-1):
    if len(url) == 0 or cl_id < 0:
        return None

    base_path = settings.WGET_PATH + str(cl_id)

    log_paths = {
        'output' : wget_base_path + '/out.log',
        'rejected' : wget_base_path + '/rejected.log'
    }

    create_files(log_paths)
    wget_cmd = 'wget -prc --convert-links --html-extension --wait=3 --random-wait --no-parent ' \
                   '--directory-prefix={0} -o {1} --rejected-log={2} {3}'.\
        format(wget_base_path, log_paths['output'], log_paths['rejected'], url)

    subprocess.Popen(wget_cmd, shell = True)

当我通过以下方式调用时

from ingest.task import html
web_url = 'https://www.gnu.org/software/wget/manual/html_node/index.html'
ingest = html.download.delay(web_url, 54321)

wget 进程按预期启动。但是,文件顶部的 base_path 参数永远不会被设置,因此当我通过

调用 status
status = html.status.delay()

尽管 statusdownload 之后被调用,但 base_path 变量是一个空字符串。这是因为这些任务是在脚本中而不是在类中吗?

最佳答案

因为在函数download中这一行

base_path = settings.WGET_PATH + str(cl_id)

您只需创建一个名为 base_path 的局部变量。为了避免这种情况,您应该在函数中将 base_path 声明为 global。例如:

@app.task(bind = True)
def download(self, url='', cl_id=-1):
    if len(url) == 0 or cl_id < 0:
        return None

    global base_path
    base_path = settings.WGET_PATH + str(cl_id)
...

来自Python docs :

在执行期间的任何时候,至少有三个嵌套作用域,其命名空间可直接访问:

  • 首先搜索的最内层范围包含本地名称
  • 任何封闭函数的作用域(从最近的封闭作用域开始搜索)包含非本地名称,但也包含非全局名称
  • 倒数第二个作用域包含当前模块的全局名称
  • 最外面的范围(最后搜索)是包含内置名称的命名空间

如果名称被声明为全局名称,则所有引用和赋值都直接进入包含模块全局名称的中间作用域。否则,在最内层作用域之外找到的所有变量都是只读的(尝试写入此类变量只会在最内层作用域中创建一个新的局部变量,而保持同名的外部变量不变)。

关于脚本中的Python变量作用域问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36179424/

相关文章:

javascript - 为什么javascript解析未传递给函数并在该函数下面声明的变量

javascript - JQuery 事件之外的变量范围

javascript - 为什么来自用户脚本的窗口(和 unsafeWindow)与来自 &lt;script&gt; 标签的窗口(和 unsafeWindow)不同?

Python psycopg2 : Copy result of query to another table

python - 如何使用 python 中的循环将键和值分配给字典?

Python:什么是 'from import * safe' 模块?

c - 将本地堆栈变量放入全局列表中,以便其他线程可以使用它

python - interp2d 在使用时无法正确处理无序输入

python - 如何在 PyOpenGL 中使用顶点数组对象和 glDrawElements 进行绘制

java - 在当前上下文中不可访问