当前位置: 首页 > 科技观察

一份Python全局配置规范及其神奇修改

时间:2023-03-13 01:05:15 科技观察

一、模块还是全局很多初学者有一个误区,就是在Python中需要配置一个全局参数时,首先想到的是global关键字,但是其实global并不是这样做的,global的作用是将局部范围内的变量声明为全局的,这样就可以在局部修改全局变量。但是这种用法其实是很不好的。根据函数规范,纯函数的输入只应由输入参数决定,执行过程中不应引用外部变量。此外,global不用于全局配置。在Python中,模块是天然的单例。该模块在项目初始化后执行一次,以后不会重复执行,符合单例模式的特点。因此,利用模块的这一特性,将整个工程文件中需要配置的选项配置到一个模块中,通过import导入需要的模块,才是Python开启全局配置的正确方式。尽管这个规范在Django等开源框架中已经被论证了无数次,但是“如何在Python中设置全局变量”的问题仍然是Python社区的月刊。通过模块配置全局变量的例子如下,在configs.py中定义CONFIG_A和CONFIG_B。在user.py中使用import导入。这实际上是Python中的一个基本操作。刚开始没什么好说的,但是在本文的最后,我展示了一个根据json配置的动态模块,供大家参考。2.单例字典在讲模块之前,我想说说我尝试过的另一种方式,就是自定义单例字典。具体方法是这样的。先从collections模块继承MutableMapping,重写相关接口。这是Python中自定义数据类型的基本操作。定制完成后,写一个装饰器,将继承的类转换为单例类。单例模式的写法可以看Stackoverflow上关于单例模式的高票回答。我习惯使用第一种写函数装饰器的方式:这种写法非常容易理解。使用类变量实例来保存类生成的实例。每次调用该类时,检查该类是否在实例字典中。如果不是则生成一个实例并将其放入实例字典中。但是这种写法有个问题。装饰后返回的不是类,而是函数。虽然Python语法强调万物皆对象,但是函数无法享受继承等类的特性。如果需要返回单例类,需要使用元类方法,或者第四类装饰器。当然,就这点而言,这个类继承了一个MutableMapping,不能继承其他的元类。元类的写法在这里不适用。3.单例字典的问题使用单例字典进行全局配置看起来比模块更酷,但实际上并没有那么好用。原因是单例模式本身的一个缺点,违反了单一职责原则,相关设计模式的教程中有提到。而且,字典在这方面还有一个缺点,就是不知道要使用的key是否存在于字典中。单例字典是我在项目之初引入的,在项目的迭代过程中给我造成最大困扰的。一开始几乎所有的配置都写到这个字典里,然后在程序运行的过程中又重新添加了这个字典。它由散布在整个程序中的各种实例修改。运行后无法知道字典里有什么,也不知道字典里的某个内容是否被修改了。不过有了GIL,就不用考虑锁的问题了,这可能是唯一的幸事。后期对这个庞大的字典进行重构,重构的过程是这样进行的:1.从各个方法到init方法中收集各个类中字典的引用点。不应该2.统一所有参考点的名称。不应该3.将子函数中直接引用单例字典的参数放到函数的参数列表中,调用者会得到单例字典的内容,传递参数的方法传递给被调用的函数。这是为了满足函数编程中纯函数的原则。不应该这样用:应该这样用4.将一个单例字典分成多个单例字典,将一些单例字典转成模块。这不是一个例子。4.动态模块该模块的使用非常简单。它配置在文件中,可以直接导入。需要注意的是,引用的条目最好在同一个地方。但是,模块的一个缺点是不方便动态修改。具体来说,在项目中,项目通过工厂模式生成了一系列的产品,每个产品需要的配置参数都不一样。这里的一种方式是通过同一个模块配置每个产品,然后在初始化时根据一个以产品名称命名的json文件修改模块的参数。这样引用模块的方法不变,只是根据json文件的内容配置模块的内容。详细代码见github。主要用于动态修改模块的语句如下:其实setattr是一个常用的函数,用来动态给对象添加功能。d.tiems()是从json文件中读取的字典对象。五。动态模块的优点现在有一种配置模块的方案是导入configs模块,调用update_config_by_name函数,即动态修改函数,根据对应的json文件修改模块的值。与在每个类初始化时直接调用json配置变量相比,这种方案是有好处的。configs模块的定义有助于代码的静态检查,形成类似C语言中.h文件和.c文件的关系,在头文件中定义相关变量,在.h文件中实现或使用。c文件。这里,变量在configs模块中定义。变量的值由json文件决定,然后通过import在其他模块中实现,这个东西是全局共享的。当然,这个全局意义指的是整个解释器。这段代码还有一个坑,一般出现在单元测试中。看两段代码:在单元测试中,由于deepcopy问题,CONFIG_X的值也会根据导入的level不同而有不同的变化。这是一个仍在处理错误。