胡琪

为今天工作,为明天投资,为未来孵化一些东西

在python中定义常量需要注意的坑

在很多高级语言中都会提供常量的关键字用来定义常量,如c++中的const,java中的final,但是python语言因为变量无类型,所以也就不存在这样的修饰符。但是在实际项目的很多场合下都需要使用到常量,因此我们只能通过自己定义类的方式来定义一个符合常量规则的类,使得该类定义的成员属性满足常量的属性。我们知道常量一般符合以下两个规则:

  1. 常量的各个字母使用大写字母表示,中间以下划线连接:如MAX_COUNT
  2. 常量的值一旦绑定则不可以再修改

其中第一条算是一种约定,这样更符合代码规范,第二条则是常量必须满足的要求,因此我们可以通过对常量的值进行修改或者命名不符合上述规范时抛出异常来到达常量的要求。我们知道在python中当我们对类的属性进行赋值的时候回自动调用object类的__setattr__()函数。该函数的定义如下:

object.__setattr__(self, name, value)

其中的name表示属性的名称,value是试图赋值给name的值,其中object类的object.__dict__以dict的形式保存了所有的写的属性(Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name is the attribute name, value is the value to be assigned to it)

因此我们可以通过定义一个类const(默认继承自object),对其object.__setattr__()方法进行重写,在对属性值进行赋值的时候进行判断,如果该属性存在,则表示这是对常量的重赋值操作,是不允许的,因此抛出异常给出提示,如果属性不存在,则表示是新定义一个常量,可以进行赋值操作。代码如下:

这样当我们要在其他.py文件中使用常量时只需要导入constant模块即可:

当试图修改常量MAX_COUNT的值时,将抛出异常:

《在python中定义常量需要注意的坑》这样就达到了不可更改常量的值的目的。但是通常我们建议将常量放到一个单独的文件中,这样更加利于后期维护,因此我们可以定义一个constant.py,在该文件中定义一系列常量,如果以后要修改常量的值直接在该文件中修改,在其他需要使用常量的地方import即可。如constant.py模块代码如下:

然后如果要在另一个模块test.py使用该常量MAX_COUNT或者BASE_URL则只需要import constant,代码如下:

注意此时不能使用from constant import Const,否则回出现ImportError: cannot import name Const
《在python中定义常量需要注意的坑》

如果要是使用from constant import Const,则前面的constant.py中的sys.modules[__name__] = Const()语句要注释掉或者修改为非__name__属性的情况:

其中’Const’可以是任何内容字符串,但是此时相当于sys.modules语句不起作用了,因此已经不具备前面说的常量的含义了。所以这种方式是不可取的。之所以是这样是因为当执行sys.modules[__name__] =Const这条语句的时候本质上是卸载了之前的constant模块,因此执行from constant import Const的时候constant本质上是None对象,之所以是这样是因为当constant模块被删除后其引用为0,被回收了,返回Node,因此是不能那个导入Const类的。http://stackoverflow.com/questions/5365562/why-is-the-value-of-name-changing-after-assignment-to-sys-modules-name。但是import constant却可以,import constant导入即使执行sys.modules[__name__]为其重新赋值,constant模块仍然在sys.modules中。http://stackoverflow.com/questions/7121802/module-name-in-sys-modules-and-globals

sys.modules

该对象是保存了已经加载的模块的dict,执行该函数会从dict中删除与之对应的模块(This 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__] =Const的时候会经过以下几个步骤:

  1. 原本sys.modules[__name__]<module 'constant' from 'constant.py'>
  2. 执行sys.modules[__name__] = Const会constant module卸载
  3. 此时如果以from constant import Const的方式在其它模块导入,sys.modules中constant不存在,为None,因此会出现cannot import name Const的错误,但是如果以import constant导入,则sys.modules中存在constant,因此不会出错。

这里涉及到import导入机制和sys.modules模块。

 

打赏

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注