Python环境变量通过反射

标签 python reflection python-3.7

在 Python 3.7 中,我编写了一个 Environment 辅助类,它允许我通过反射加载操作系统环境变量。它还根据派生类中声明的类型提示,将环境变量转换为 native bool 值或元组。

它可以工作,但是 Visual Studio Code 中的 linter 给我这个问题报告:

Class 'Environment' has no '__annotations__' member

这是辅助类。

import os
from abc import ABC

class Environment(ABC):

    @classmethod
    def from_os(cls):
        convert = {
            bool: lambda d: d == "1",
            (): lambda d: tuple(d.split(',')),
            str: lambda d: d
        }
        values = [ 
            convert[value](os.environ[key]) 
            for key,value in cls.__annotations__.items() 
            ]
        return cls(*values)

同样,代码确实有效。我该怎么做才能让 Pylint 开心?也许有一种不同的方法可以迭代属性(和属性类型提示),以便在不使用 __annotations__ 的情况下获得相同的结果?

我可以通过欺骗和添加 pylint 抑制提示让 linter 停止提示:

   for key,value in cls.__annotations__.items() # pylint: disable=no-member

...但这不是我正在寻找的解决方案。

如果有帮助,下面是一个示例,说明如何使用我的助手类来获取任意一组环境变量:

from dataclasses import dataclass

@dataclass
class FWMonitoringEnv(Environment):
    # The names of these attributes are used
    # to find and load a corresponding environment variable.
    # This happens when "FWMonitoringEnv.from_os()" is called.
    preempt : bool
    split_routes : bool
    tag_key : str
    vpc_summary_route : str
    route_table_id : str
    fw_trust_enis : ()
    fw_mgmt_ips : ()
    api_key_name : str
    region : str

在代码的其他地方我简单地执行了这个:

env = FWMonitoringEnv.from_os()

虽然我正在做这件事,但我还想解决另一个代码卫生问题。有没有办法让我的 Environment 类强制派生类成为 @dataclass?例如,可以使用 Python 3.7 类型提示来完成吗?

最佳答案

您可以使用 https://docs.python.org/3/library/inspect.html#inspect.signature获取所有类注释的方法。

例子

pprint(inspect.signature(cls).parameters)

mappingproxy(OrderedDict([('preempt', <Parameter "preempt: bool">),
                          ('split_routes', <Parameter "split_routes: bool">),
                          ('tag_key', <Parameter "tag_key: str">),
                          ('vpc_summary_route',
                           <Parameter "vpc_summary_route: str">),
                          ('route_table_id', <Parameter "route_table_id: str">),
                          ('fw_trust_enis', <Parameter "fw_trust_enis: ()">),
                          ('fw_mgmt_ips', <Parameter "fw_mgmt_ips: ()">),
                          ('api_key_name', <Parameter "api_key_name: str">),
                          ('region', <Parameter "region: str">)]))

当合并到您的代码中时,它看起来如下:

    def from_os(cls):
        convert = {
            bool: lambda d: d == '1',
            (): lambda d: tuple(d.split(',')),
            str: lambda d: d
        }
        values = [ 
            convert[val.annotation](os.environ[val.name]) 
            for val in signature(cls).parameters.values()
            ]
        return cls(*values)

我相信这是让它“真实”的更好方法:-)

关于Python环境变量通过反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59218268/

相关文章:

python - 从文本文件中删除行?

python - 在 Python 3.7 中,sys.settrace 中的 'opcode' 事件是否提供有关字节码本身的任何信息?

python - 如何启动连接到您正在监听的套接字的进程?

python - 字符串变量作为pyplot中的 latex

c# - 通过描述属性查找枚举值

java - 如何调用位于另一个实例内部的实例的 getter 方法

Java - 调用类的所有方法

python - 如何显示使用@dataclass 类装饰器时生成的代码?

python - 输出格式不正确

python - 有没有直接的方法来忽略 python datetime 对象的一部分?