【问题标题】:access (read-only) global variable within class method在类方法中访问(只读)全局变量
【发布时间】:2015-01-17 01:20:21
【问题描述】:

我有加载配置选项的类 Config()。我创建了一个名为 cfg 的类的实例。
然后我有许多 A、B、C 类必须只读来自 cfg 的成员。

from mylib.config import *
from mylib.A import *
from mylib.B import *
from mylib.C import *

cfg = Config(filename)
a = A()
a.do_things()

例如在我的构造函数中:

def __init__(self):
     self.name = cfg.name

问题是我在运行时得到 "NameError: name 'cfg' is not defined" 行 self.name = cfg.name

我首先认为这是我在声明 cfg 之前导入 mylib.A、mylib.B 和 mylib.C 的东西 所以我搬家了

cfg = Config(filename)

在导入 mylib.A...B...C 之前。但还是同样的错误。

可能的解决方案:
1. 将对象“cfg”作为参数传递,但我必须更改所有 A、B、C 类中所有方法的签名,我觉得它不干净,因为它在所有方法中乘以相同的参数。
2. 为 A、B、C 类创建私有成员 _cfg。更好但也不是很好,数据成倍增加
3.将类定义+实例声明放在一个文件中,并在mylib.A,mylib.B和mylib.C中导入:AFAISI是最好的解决方案,但仍然不是我的口味,因为我混合了类定义和实例声明,我喜欢在类文件中只有类定义
4.为了避免类定义和实例化在同一个文件中,我可以创建一个'init.py'

from mylib.config import *
cfg = Config(filename)

然后在 mylib.A、mylib.B 和 mylib.C...在 mylib.config.py 类声明文件中导入,mylib.config 在 init.py 中导入),为了避免这种情况,我应该有 init.py 和 init_config.py 。

有没有更好/更清洁/更简单的东西?

【问题讨论】:

    标签: class python-3.x methods import global


    【解决方案1】:

    如何在mylib.config 中创建一个initialize 函数,该函数创建一个全局配置对象。

    config_obj = None
    #todo: pick a better name for this
    
    class Config:
        def __init__(self, filename):
            pass
            #todo: definition goes here.
    
    def initialize(filename):
        global config_obj
        config_obj= Config(filename)
    

    然后,在您的主文件中,在对模块 A B 或 C 执行任何操作之前调用该函数。

    from mylib.config import *
    from mylib.A import *
    from mylib.B import *
    from mylib.C import *
    
    initialize(filename)
    a = A()
    a.do_things()
    

    不要忘记import config 在任何模块中需要引用config_obj

    #mylib.a
    import config
    
    class Whatever:
        def __init__(self):
             self.name = config.cfg_obj.name
    

    请注意,您不应将import config 替换为from config import *,因为当主文件调用initialize 时,A 的cfg_obj 副本将无法正确更新。


    如果你不喜欢你的类模块有函数或全局变量,你可以将initialize设为Config类的静态方法,它返回Config的单例实例。

    #singleton Config class. Only one instance of it should ever exist.
    #Users, please don't call Config(filename). use get_instance() instead.
    class Config:
        instance = None
        def __init__(self, filename):
            pass
            #definition goes here...
    
        @staticmethod
        def initialize(filename):
            if Config.instance is not None:
                msg = "singleton Config has already been initialized"
                raise Exception(msg)
            #this is the only place Config(filename) should ever be called.
            Config.instance = Config(filename)
            return Config.instance
    
        @staticmethod
        def get_instance():
            if Config.instance is None: 
                msg = "can't get instance because it hasn't been initialized yet"
                raise Exception(msg)
            return Config.instance
    

    (可能有更好的方法来制作singleton in Python。我只是为了说明目的而采用了一种简单的方法。)

    然后你在主文件中初始化:

    from mylib.config import *
    from mylib.A import *
    from mylib.B import *
    from mylib.C import *
    
    Config.initialize(filename)
    a = A()
    a.do_things()
    

    并获取模块中的实例:

    #mylib.a
    import config
    
    class Whatever:
        def __init__(self):
             self.name = config.Config.get_instance().name
    

    (通过这种方法,如果您愿意,我认为您可以在模块中from config import *。)

    【讨论】:

    • 您的提议看起来像是我的第三个解决方案,其中包含封装和“全局”使用,有两件事没有必要恕我直言(我可能错了)......我尽量避免在 mylib.config 中混合声明和定义。
    • @comte,好的,如果您使用单例模式,您可以将所有内容放在类中。已编辑。
    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 2011-10-29
    相关资源
    最近更新 更多