-
Notifications
You must be signed in to change notification settings - Fork 1
/
const.html
136 lines (118 loc) · 8.42 KB
/
const.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<html>
<head>
<title>c:\const.py.html</title>
<meta name="Generator" content="Vim/7.0">
<meta http-equiv="content-type" content="text/html; charset=GBK">
</head>
<body bgcolor="#000000" text="#cccccc">
<pre>
<font color="#80a0ff"># -*- coding: utf-8 -*-</font>
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffa0a0">感觉楼主的这篇和上次用 python 实现 define 的那篇帖子,想说的都是</font>
<font color="#ffa0a0">一个东西,就是静态语言中的 const,第一次初始化后不能修改的东西。</font>
<font color="#ffa0a0">说起来,python 对象中其实是有这样的东西,就是 imutable object 。</font>
<font color="#ffa0a0">不过常量针对的是名字而非对象,所以在 python 中常量的准确定义应该</font>
<font color="#ffa0a0">是:在第一次绑定后不能重新绑定其他对象的名字。</font>
<font color="#ffa0a0">遗憾的是 python 中没有这样的东西。</font>
<font color="#ffa0a0">其实和类型检查、访问控制等东西一样,静态语言中常量是通过编译器在</font>
<font color="#ffa0a0">编译时进行检查,而 python 就算实现那也只能是在运行时进行计算,势</font>
<font color="#ffa0a0">必损耗性能,我想这也是 python 中没有这样的东西的原因。</font>
<font color="#ffa0a0">但是正如 python 中的访问控制是通过对名字的约定来做的一样,其实常</font>
<font color="#ffa0a0">量也比较适合这样做。</font>
<font color="#ffa0a0">如果实在要用动态语言模拟 const,那么关键在于对名字的绑定进行控制。</font>
<font color="#ffa0a0">下面总结一下各种做法:</font>
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffff00">def</font> <font color="#40ffff">a_const_value</font>():
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffa0a0"> 方法1是通过使用函数替代对名字的直接访问,好像是比较傻的方法。</font>
<font color="#ffa0a0"> 不过 ruby 中函数调用可以省略括号就有点像了</font>
<font color="#ffa0a0"> >>> a_const_value()</font>
<font color="#ffa0a0"> 'const'</font>
<font color="#ffa0a0"> </font><span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffff00">return</font> <span style="background-color: #000000"><font color="#cccccc">'</font></span><font color="#ffa0a0">const</font><span style="background-color: #000000"><font color="#cccccc">'</font></span>
<font color="#ffff00">class</font> <font color="#40ffff">Temp</font>(object):
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffa0a0"> class 中通过 property 可以做得更漂亮:</font>
<font color="#ffa0a0"> >>> t = Temp()</font>
<font color="#ffa0a0"> >>> t.a_const_value</font>
<font color="#ffa0a0"> 'const'</font>
<font color="#ffa0a0"> >>> t.a_const_value = 'another value'</font>
<font color="#ffa0a0"> Traceback (most recent call last):</font>
<font color="#ffa0a0"> ...</font>
<font color="#ffa0a0"> AttributeError: can't set attribute</font>
<font color="#ffa0a0"> </font><span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ff80ff">@</font><font color="#40ffff">property</font>
<font color="#ffff00">def</font> <font color="#40ffff">a_const_value</font>(self):
<font color="#ffff00">return</font> <span style="background-color: #000000"><font color="#cccccc">'</font></span><font color="#ffa0a0">const</font><span style="background-color: #000000"><font color="#cccccc">'</font></span>
<font color="#ffff00">class</font> <font color="#40ffff">ConstError</font>(Exception):
<font color="#ffff00">pass</font>
<font color="#ffff00">class</font> <font color="#40ffff">Consts</font>(object):
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffa0a0"> 方法2是将常量名字放入一个 class 中统一进行管理:</font>
<font color="#ffa0a0"> >>> consts = Consts()</font>
<font color="#ffa0a0"> >>> consts.a = 2</font>
<font color="#ffa0a0"> >>> consts.a</font>
<font color="#ffa0a0"> 2</font>
<font color="#ffa0a0"> >>> consts.a = 3</font>
<font color="#ffa0a0"> Traceback (most recent call last):</font>
<font color="#ffa0a0"> ...</font>
<font color="#ffa0a0"> ConstError: can't rebind const name</font>
<font color="#ffa0a0"> 不过需要注意的是,仍然可以通过 __dict__ 直接访问常量:</font>
<font color="#ffa0a0"> >>> consts.__dict__['a'] = 3</font>
<font color="#ffa0a0"> >>> consts.a</font>
<font color="#ffa0a0"> 3</font>
<font color="#ffa0a0"> </font><span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffff00">def</font> <font color="#40ffff">__setattr__</font>(self, name, value):
<font color="#ffff00">if</font> name <font color="#ffff00">in</font> self.__dict__:
<font color="#ffff00">raise</font> ConstError, <span style="background-color: #000000"><font color="#cccccc">'</font></span><font color="#ffa0a0">can</font><font color="#ffa500">\'</font><font color="#ffa0a0">t rebind const name</font><span style="background-color: #000000"><font color="#cccccc">'</font></span>
<font color="#ffff00">else</font>:
self.__dict__[name] = value
<font color="#ffff00">class</font> <font color="#40ffff">ConstBase</font>(object):
<span style="background-color: #000000"><font color="#cccccc">'''</font></span>
<font color="#ffa0a0"> 或者让 class 自己指定那些是常量:</font>
<font color="#ffa0a0"> >>> class Temp(ConstBase):</font>
<font color="#ffa0a0"> ... __consts__ = {'a':None, 'b':2}</font>
<font color="#ffa0a0"> ... def __init__(self, a):</font>
<font color="#ffa0a0"> ... self.a = a</font>
<font color="#ffa0a0"> ...</font>
<font color="#ffa0a0"> >>> t = Temp(2)</font>
<font color="#ffa0a0"> >>> t.a</font>
<font color="#ffa0a0"> 2</font>
<font color="#ffa0a0"> >>> t.b</font>
<font color="#ffa0a0"> 2</font>
<font color="#ffa0a0"> >>> t.a = 3</font>
<font color="#ffa0a0"> Traceback (most recent call last):</font>
<font color="#ffa0a0"> ...</font>
<font color="#ffa0a0"> ConstError: can't rebind const name</font>
<font color="#ffa0a0"> >>> t.b = 3</font>
<font color="#ffa0a0"> Traceback (most recent call last):</font>
<font color="#ffa0a0"> ...</font>
<font color="#ffa0a0"> ConstError: can't rebind const name</font>
<font color="#ffa0a0"> >>> t.c = 5</font>
<font color="#ffa0a0"> >>> t.c</font>
<font color="#ffa0a0"> 5</font>
<font color="#ffa0a0"> 使用这种方式,也可以直接通过 __dict__ 对常量进行修改:</font>
<font color="#ffa0a0"> >>> t.__dict__['a']= 3</font>
<font color="#ffa0a0"> >>> t.a</font>
<font color="#ffa0a0"> 3</font>
<font color="#ffa0a0"> </font><span style="background-color: #000000"><font color="#cccccc">'''</font></span>
__consts__ = {}
<font color="#ffff00">def</font> <font color="#40ffff">__setattr__</font>(self, name, value):
<font color="#ffff00">if</font> name <font color="#ffff00">in</font> self.__consts__:
<font color="#ffff00">if</font> self.__consts__[name] == None:
self.__consts__[name] = value
<font color="#ffff00">else</font>:
<font color="#ffff00">raise</font> ConstError, <span style="background-color: #000000"><font color="#cccccc">'</font></span><font color="#ffa0a0">can</font><font color="#ffa500">\'</font><font color="#ffa0a0">t rebind const name</font><span style="background-color: #000000"><font color="#cccccc">'</font></span>
<font color="#ffff00">else</font>:
super(ConstBase, self).__setattr__(name, value)
<font color="#ffff00">def</font> <font color="#40ffff">__getattr__</font>(self, name):
<font color="#ffff00">if</font> name <font color="#ffff00">in</font> self.__consts__:
<font color="#ffff00">return</font> self.__consts__[name]
<font color="#ffff00">else</font>:
<font color="#ffff00">return</font> super(ConstBase, self).__getattr__(name, value)
<font color="#ffff00">if</font> __name__ == <span style="background-color: #000000"><font color="#cccccc">'</font></span><font color="#ffa0a0">__main__</font><span style="background-color: #000000"><font color="#cccccc">'</font></span>:
<font color="#ff80ff">import</font> doctest
doctest.testmod()
</pre>
</body>
</html>