背景图来源:click
Bgwan:关于python读写文件那点事zhuanlan.zhihu.com![a4c6249c983f9895bae3c6efa3e7f0c2.png](https://i-blog.csdnimg.cn/blog_migrate/05f9226db0affaa4c923c1c64407accf.jpeg)
写在前面:
这篇文章主要介绍了Python中实现常量(Const)功能,python语言本身没有提供const,本文使用一个properties文件(类)来实现常量定义功能,并介绍了使用方法 同时作为livery1.2.x国际化的功能(AndroidLocalizePlugin
不好用)的技术支持,感兴趣的的朋友可以参考下
与C/C++不同,Python在语法上并没有定义常量,尽管PEP 8定义了常量的命名规范为大写字母和下划线组成。
在实际项目中,经常会遇到需要使用const的情形,常量首次赋值后, 无法阻止其他代码对其进行修改或删除。
解决办法
这个问题也是从网上参考而来,在2001年就有人给出了解决方案Constants in Python,基本内容如下:
class _const:
"""常量数据类"""
class ConstError(TypeError):
"""修改常量抛出此错误"""
pass
__PROPERTY_PATH = './translator.properties'
def __setattr__(self, name, value):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't rebind const instance attribute (%s)" % name
self.__dict__[name] = value
import sys
sys.modules[__name__] = _const()
其大致含义为:
- 通过_const的setattr对象方法判断该对象是否存在属性name,若存在则抛出自定义异常ConstError,否则创建该属性。
- sys.modules[name] = const()这条语句,将_const实例化的对象赋值sys.modules[name],const模块被绑定成_const对象。name在首次载入const过程中为'const',而sys.modules是模块名与已加载模块的dict。
具体再解释一下sys.modules
This is a dictionary that maps module names to modules which have already been loaded. This can be manipulated to force reloading of modules and other tricks. Note that removing a module from this dictionary is not the same as calling reload() on the corresponding module object.
翻译过来: 使用sys.modules[name]可以获取一个模块对象,并可以通过该对象获取模块的属性(translator.properties中的配置内容),使用sys.modules向系统字典中注入了一个const对象从而实现在执行import const时实际获取了一个const实例的功能,即一个const实例,这样整个工程需要使用的常量都应该定义在一个文件中
,如本次需求的配置文件:translator.properties
SOURCE = zh_CHS
TARGET = EN
SOURCE_FILE_PATH = C:/Users/sun/public/python/res/strings/values-zh-rCN/strings.xml
TARGET_FILE_PATH = C:/Users/sun/public/python/res/strings/values/strings.xml
SAVE_FILE_PATH = C:/Users/sun/public/python/res/strings/sunst0069translated/strings.xml
TRANSLATION_RECORD_PATH = C:/Users/sun/public/python/sunst0069record/strings
TRANSLATION_RECORD_FILE = result.xlsx
EDITOR = sunst0069
如何使用const模块呢?(本次需求国际化livery需要将中文翻译为英文)**
import const
const.SOURCE = zh_CHS
若再次赋值const.SOURCE为英文,
const.SOURCE = en
则将抛出ConstError的异常。
如何避免常量被删除?
实际项目中,常量并不希望被其他代码删除。在_const类中加入:
def __delattr__(self, name):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't unbind const const instance attribute (%s)" % name
raise AttributeError, "const instance has no attribute '%s'" % name
如此,删除已定义的常量(假设const.SOURCE已经赋值):
del const.SOURCE
则将抛出ConstError的异常。
配置文件与常量
实际项目中,为了让应用程序灵活部署,一般会用配置文件存储应用程序的各种参数;而这些参数通常都以常量语义存在于应用程序中。
在上述代码基础上,根据应用程序的实际情况将常量划分为3类:
- 特殊含义的数值或字符串,如 ETC_FSTAB = “/etc/apt” 。其作用为
(1).避免程序中到处出现类似特殊值,因为人为输入特殊值的低级错误将耗费不必要的调试/测试时间
(2).另一方面, 神秘数值(magic number),如 LUN_BLOCK_SIZE = 6699,将影响程序的可读性。 - 应用程序参数的默认值,如 URLOPEN_DEFAULT_TIMEOUT = 15 。其作用主要为配置文件参数的默认值。
- 通过配置文件载入的参数,如通过ConfigParser.SafeConfigParser解析形如ini文件的参数。
第1和2类常量作为_const类的类属性,第3类常量可以在init方法中初始化。如:
class _const:
ETC_FSTAB = "/etc/apt"
LUN_BLOCK_SIZE = 6699
URLOPEN_DEFAULT_TIMEOUT = 15
def __init__(self):
conf = ConfigParser.SafeConfigParser()
conf.read(self.CONF_PATH)
try:
self.URLOPEN_TIMEOUT = conf.getint("DEFAULT", "urlopen_timeout")
except:
self.URLOPEN_TIMEOUT = self.URLOPEN_DEFAULT_TIMEOUT
... ...
某些情况下,应用程序可能并不希望const模块在被外部调用时绑定新属性(常量),实现如下:
def __init__(self):
# Constant definition area
_const.__setattr__ = _const._setattr_impl
def _setattr_impl(self, name, value):
raise self.ConstError, "Can't bind const instance attribute (%s)" % name
其原理为_const对象初始化完成后将setattr设置为禁止绑定属性的实现。若在_const类中实现setattr为禁止绑定属性,则init也将无法初始化(绑定)对象属性。
总结
1.存在的小问题(该问题并不影响该解决方案的使用),具体请参考:
http://stackoverflow.com/questions/5365562/why-is-the-value-of-name-changing-after-assignment-to-sys-modules-name
2.常量和变量需要区分清楚,如果常量被修改,被删除都会抛出异常,如图:
![7c2b1ba6a9611192848ded9906fb9f16.png](https://i-blog.csdnimg.cn/blog_migrate/b6a9470f55a5905c59e5037320a7ad35.jpeg)
以上《Python常量》All
请尊重劳动成果,注意文中版权声明,Android专栏不定时更新,欢迎点击关注我知乎。也可以同时关注人工智能专栏,文艺语录专栏,本内容作者sunst0069,技术上有问题请沟通qyddai@gmail.com
作者:sunst 发布于: 2021-01-23 17:03 && 修改于:2021-01-23 17:24