前言
Python 没有 const
关键字,想要创建常量只能自己想办法。
这篇笔记介绍的是使用私有变量、单例模式、只读属性和不可变类型创建一个 Constant
类,在其中储存和调用所需要的常量值。
私有变量[1]
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线 __
,在Python中,实例的变量名如果以 __
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
单例模式[2]
class Constant(object):
"""
A singleton class to store all constants.
"""
__instance = None
def __new__(cls, *args, **kw):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args, **kw)
return cls.__instance
只读属性[3]
Python 中的属性[4]和 C# 中的属性是同一个概念。
class People:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if isinstance(age, int):
self.__age = age
else:
raise ValueError
@age.deleter
def age(self):
print("删除年龄数据!")
obj = People("jack", 18)
print(obj.age)
obj.age = 19
print("obj.age: ", obj.age)
del obj.age
---------------------------
打印结果:
18
obj.age: 19
删除年龄数据!
那么如何将一个普通的方法转换为一个“伪装”的属性呢?
- 首先,在普通方法的基础上添加
@property
装饰器,例如上面的age()
方法。这相当于一个get
方法,用于获取值,决定类似result = obj.age
执行什么代码。该方法仅有一个self
参数。 - 写一个同名的方法,添加
@xxx.setter
装饰器(xxx表示和上面方法一样的名字),比如例子中的第二个方法。这相当于编写了一个set
方法,提供赋值功能,决定类似obj.age = ....
的语句执行什么代码。 - 再写一个同名的方法,并添加
@xxx.delete
装饰器,比如例子中的第三个方法。用于删除功能,决定del obj.age
这样的语句具体执行什么代码。
简而言之,就是分别将三个方法定义为对同一个属性的获取、修改和删除。还可以定义只读属性,只需要使用 @property
声明 get
方法,不定义 setter
方法就是一个只读属性。
class Constant(object):
def __init__(self):
self.__val = 1
@property
def val(self):
return self.__val
不可变类型
常量是不可变类型的子集,区别在于不可变类型的变量名可以重新绑定到其他类型上,而常量名和常量值都是不可变的。
a = (1, 2, 3) # 元组是一个不可变类型
print(a)
a = 1 # 原本绑定到不可变类型的变量名可以重新绑定到其他值
print(a)
---------------------------
输出:
(1, 2, 3)
1
不可变字典
可变类型 list
和 set
对应的不可变类型分别为 tuple
和 frozenset
。但在 PEP 416 中拒绝了不可变字典的要求。因此我们使用 Python 3.3 中引入的 MappingProxyType
和私有变量搭配实现不可变字典的返回。
from types import MappingProxyType
class Constant(object):
"""
A singleton class to store all constants.
"""
__instance = None
def __new__(cls, *args, **kw):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args, **kw)
return cls.__instance
def __init__(self):
self.__dict1 = {a:1, b:2}
@property
def dict1(self):
return MappingProxyType(self.__dict1).copy()
使用常量
Constant
是一个类,所以我们需要先实例化才能使用它。
const = Constant()
dict1 = const.dict1