写在前面:
这篇文章主要介绍了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.modulesThis 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 。其作用主要为配置文件参数的默认值。
第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.存在的小问题(该问题并不影响该解决方案的使用),具体请参考:
2.常量和变量需要区分清楚,如果常量被修改,被删除都会抛出异常,如图:
以上《Python常量》All
作者:sunst发布于: 2021-01-23 17:03 && 修改于:2021-01-23 17:24