python的解释器级别对象的实现方法
admin
2023-07-31 01:47:51
0

最近在重构项目代码, 有个需求是需要声明一个变量, 然后任何import了这个变量的模块, 当这个变量在其它地方更改了值以后, 这个变化都能反映出来, 乍看好像有点麻烦, 其实很简单.

就通常的想法来讲, 你用Dict, list或一个类实例都能实现. 因为在使用它们时, 本质上还是一种引用的方式, 而不是像其它变量是值复制, 所以它们的修改或变化是肯定能反映出来的

比如tornado的options, 没记错的话, 文档里写的什么解释器级别变量, 很高端的样子, 其实实现不难, 直接跳到代码

options = OptionParser()
\"\"\"Global options object.

All defined options are available as attributes on this object.
\"\"\"

Global的对象, 因为OptionParser的实例就一个options, 每次使用是怎么使用的呢

from tornado.options import options

每次都import的是这个实例, 而包括define在内的函数, 其实都是在对这个唯一的实例在进行操作而已, 代码中有这段

def define(name, default=None, type=None, help=None, metavar=None,
           multiple=False, group=None, callback=None):
    \"\"\"Defines an option in the global namespace.

    See `OptionParser.define`.
    \"\"\"
    return options.define(name, default=default, type=type, help=help,
                          metavar=metavar, multiple=multiple, group=group,
                          callback=callback)

另外一个令人容易想到的解释器级别的东西就是logger, logging.getLogger()也是声明解释器级别的对象, 而且还是线程安全的. 我们只需要在某个模块中声明一个logger, 然后在其它模块里

import logging

logger = logging.getLogger(\'xxname\')

就行了

直接看代码

def getLogger(self, name):
        \"\"\"
        Get a logger with the specified name (channel name), creating it
        if it doesn\'t yet exist. This name is a dot-separated hierarchical
        name, such as \"a\", \"a.b\", \"a.b.c\" or similar.

        If a PlaceHolder existed for the specified name [i.e. the logger
        didn\'t exist but a child of it did], replace it with the created
        logger and fix up the parent/child references which pointed to the
        placeholder to now point to the logger.
        \"\"\"
        rv = None
        if not isinstance(name, basestring):
            raise TypeError(\'A logger name must be string or Unicode\')
        if isinstance(name, unicode):
            name = name.encode(\'utf-8\')
        _acquireLock()
        try:
            if name in self.loggerDict:
                rv = self.loggerDict[name]
                if isinstance(rv, PlaceHolder):
                    ph = rv
                    rv = (self.loggerClass or _loggerClass)(name)
                    rv.manager = self
                    self.loggerDict[name] = rv
                    self._fixupChildren(ph, rv)
                    self._fixupParents(rv)
            else:
                rv = (self.loggerClass or _loggerClass)(name)
                rv.manager = self
                self.loggerDict[name] = rv
                self._fixupParents(rv)
        finally:
            _releaseLock()
        return rv

这个getLogger函数最终调用的是Manager类的实例函数getLogger, 当你用的这个name不存在时, 通常是日志初始化时, 会声明一个Logger对象, 然后放到ManagerloggerDict中进行管理.

当你在别的地方也声明了这个name的logger时, Manager会发现loggerDict中已经有了, 直接拿出来用就行了. 其中还包括一些日志层级, hierarchy那些东西的处理, 不过这不是本文重点.

至于线程安全, 很简单, 代码里给加了线程锁. 这样打日志就不会东一块西一块了, 可惜多进程的日志标准库没有给进程安全的实现, 当然自己统一上传用socket处理或者用个process queue处理都是可以的.

如果想在允许多次实例化的情况下, 实现这种解释器级别变量呢?
那就是单例模式了, 在实例已经存在时调用一个函数对自己进行重载或更新即可

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...