# -*- coding: utf-8 -*- ''' 感觉楼主的这篇和上次用 python 实现 define 的那篇帖子,想说的都是 一个东西,就是静态语言中的 const,第一次初始化后不能修改的东西。 说起来,python 对象中其实是有这样的东西,就是 imutable object 。 不过常量针对的是名字而非对象,所以在 python 中常量的准确定义应该 是:在第一次绑定后不能重新绑定其他对象的名字。 遗憾的是 python 中没有这样的东西。 其实和类型检查、访问控制等东西一样,静态语言中常量是通过编译器在 编译时进行检查,而 python 就算实现那也只能是在运行时进行计算,势 必损耗性能,我想这也是 python 中没有这样的东西的原因。 但是正如 python 中的访问控制是通过对名字的约定来做的一样,其实常 量也比较适合这样做。 如果实在要用动态语言模拟 const,那么关键在于对名字的绑定进行控制。 下面总结一下各种做法: ''' def a_const_value(): ''' 方法1是通过使用函数替代对名字的直接访问,好像是比较傻的方法。 不过 ruby 中函数调用可以省略括号就有点像了 >>> a_const_value() 'const' ''' return 'const' class Temp(object): ''' class 中通过 property 可以做得更漂亮: >>> t = Temp() >>> t.a_const_value 'const' >>> t.a_const_value = 'another value' Traceback (most recent call last): ... AttributeError: can't set attribute ''' @property def a_const_value(self): return 'const' class ConstError(Exception): pass class Consts(object): ''' 方法2是将常量名字放入一个 class 中统一进行管理: >>> consts = Consts() >>> consts.a = 2 >>> consts.a 2 >>> consts.a = 3 Traceback (most recent call last): ... ConstError: can't rebind const name 不过需要注意的是,仍然可以通过 __dict__ 直接访问常量: >>> consts.__dict__['a'] = 3 >>> consts.a 3 ''' def __setattr__(self, name, value): if name in self.__dict__: raise ConstError, 'can\'t rebind const name' else: self.__dict__[name] = value class ConstBase(object): ''' 或者让 class 自己指定那些是常量: >>> class Temp(ConstBase): ... __consts__ = {'a':None, 'b':2} ... def __init__(self, a): ... self.a = a ... >>> t = Temp(2) >>> t.a 2 >>> t.b 2 >>> t.a = 3 Traceback (most recent call last): ... ConstError: can't rebind const name >>> t.b = 3 Traceback (most recent call last): ... ConstError: can't rebind const name >>> t.c = 5 >>> t.c 5 使用这种方式,也可以直接通过 __dict__ 对常量进行修改: >>> t.__dict__['a']= 3 >>> t.a 3 ''' __consts__ = {} def __setattr__(self, name, value): if name in self.__consts__: if self.__consts__[name] == None: self.__consts__[name] = value else: raise ConstError, 'can\'t rebind const name' else: super(ConstBase, self).__setattr__(name, value) def __getattr__(self, name): if name in self.__consts__: return self.__consts__[name] else: return super(ConstBase, self).__getattr__(name, value) if __name__ == '__main__': import doctest doctest.testmod()