写在前面:

这篇文章主要介绍了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