繁体   English   中英

为什么我的局部变量像全局变量一样被访问?

[英]Why is my local variable being accessed like it's a global variable?

我有这段代码,它以某种方式将config视为全局变量,即使它是局部变量。 我的同事刚刚注意到这一点,因为他们正在将脚本变成 Lambda function 并且 AWS 不断给他们一个NameError

错误消息: name 'config' is not defined

如果我在终端中运行以下命令,它就可以正常工作。 问题是,由于get_fields_for_issuetype function 中未定义config ,因此是否应该出错,还是我遗漏了什么? 为什么它工作得很好?

Lambda 代码和这个代码之间的唯一区别是 Lambda 代码有一个constants.py ,其中定义了ProjectConfigproject_configs ,然后导入到主代码中。

这是在我的终端中运行良好的代码:

import requests
from collections import namedtuple


BASE_URL = "https://example.com"

ProjectConfig = namedtuple("ProjectConfig", "projects required_fields tab_name")

project_configs = [
        ProjectConfig(
            projects=sorted(
                [
                    "AGNT",
                    "APS",
                    "CLOD",
                ]
            ),
            required_fields=[
                "Field 1",
                "Field 2",
            ],
            tab_name="Group_1_Fields",
        ),
        ProjectConfig(
            projects=sorted(
                [
                    "ABAGNT",
                    "ABAPS",
                    "ABCLOD",
                ]
            ),
            required_fields=[
                "Field 3",
                "Field 4",
            ],
            tab_name="Group_2_Fields",
        ),
    ]
    def auth():
        email = "email@email.com"
        pwd = "***"
    
        credentials = (email, pwd)
        session = requests.Session()
        session.auth = credentials
    
        return session

     def get_fields_for_issuetype(project_key, session):
        url = (BASE_URL + f"/something/something")

        response = session.get(url)
        data = response.json()
        project = data["projects"][0]

        proj_key = project["key"]
        name = project["name"] + f" ({proj_key}) - Issue Types"
        issuetypes = project["issuetypes"]

        for issuetype in issuetypes:
            issuetype_name = issuetype["name"]

            required_fields = config.required_fields.copy()


    def main(config):
        session = auth()
    
        for project in config.projects:
            table = get_fields_for_issuetype(project, session)


    if __name__ == "__main__":
        for config in project_configs:
            main(config)

这是变成 Lambda function 时不运行的代码:

app.py

import requests
from constants import API_TOKEN, BASE_URL, USER_NAME, project_configs


    def auth():
        email = USERNAME
        pwd = API_TOKEN
    
        credentials = (email, pwd)
        session = requests.Session()
        session.auth = credentials
    
        return session

     def get_fields_for_issuetype(project_key, session):
        url = (BASE_URL + f"/something/something")

        response = session.get(url)
        data = response.json()
        project = data["projects"][0]

        proj_key = project["key"]
        name = project["name"] + f" ({proj_key}) - Issue Types"
        issuetypes = project["issuetypes"]

        for issuetype in issuetypes:
            issuetype_name = issuetype["name"]

            required_fields = config.required_fields.copy()


    def main(config):
        session = auth()
    
        for project in config.projects:
            table = get_fields_for_issuetype(project, session)


    def lambda_handler(event, context):
        for config in project_configs:
            main(config)

constants.py

from collections import namedtuple

BASE_URL = "https://example.com"

ProjectConfig = namedtuple("ProjectConfig", "projects required_fields tab_name")

project_configs = [
        ProjectConfig(
            projects=sorted(
                [
                    "AGNT",
                    "APS",
                    "CLOD",
                ]
            ),
            required_fields=[
                "Field 1",
                "Field 2",
            ],
            tab_name="Group_1_Fields",
        ),
        ProjectConfig(
            projects=sorted(
                [
                    "ABAGNT",
                    "ABAPS",
                    "ABCLOD",
                ]
            ),
            required_fields=[
                "Field 3",
                "Field 4",
            ],
            tab_name="Group_2_Fields",
        ),
    ]
    

这个 function 在 scope 中没有config

def get_fields_for_issuetype(project_key, session):
    url = (BASE_URL + f"/something/something")
    
    ...

    for issuetype in issuetypes:
        issuetype_name = issuetype["name"]

        required_fields = config.required_fields.copy()

在您的本地代码中,您有以下内容:

if __name__ == "__main__":
    for config in project_configs:
        main(config)

这会将config放入上述 function 可以访问的 scope 中,因为它位于get_fields_for_issuetype()定义之外并且位于同一文件中。 您需要传递config才能在 Lambda function 中按预期工作。

您可以通过像这样定义 function 来了解其工作原理:

def f():
    def g():
        print(f"I have access to {x=}")
    x = "an outer scope variable"
    g()

Even though x is defined after the function g() , g() has access to it because the scope of x is visible to g() - they both are in the scope of function f() . 同样,当您使用原始文件时,您可以将其视为正在运行的不可见f() 事实上, if __name__ = "__main__"基本上表明你在一个名为__main__的 function 中。 get_fields_for_issuetype可以看到 function 因为这是定义它的地方。

if __name__ == "__main__":
    for config in project_configs:
        main(config)

这个就在底部。 这在全局 scope 处声明了一个名为config的变量。 for不会创建自己的 scope,所以这仍然是全局范围的。 当您在本地不存在这样的名称的 function 中使用config时,它将继承全局名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM