一、python基础知识

常量和变量

变量命名由字母、数字、下划线组成,不能以数字开头,并且对字母大小写敏感。

所谓的常量就是不能改变的量,比如常用的数学常数 PI 就是一个常量,在python中,通常用全部大写的标识符来表示常量,如:PI=3.1415926

但事实上PI仍然是一个变量,python没有任何机制保证PI不会被修改,所以,用全部大写的标识符表示常量只是一个习惯上的用法,

实际上,PI的值仍然可以被修改。

Python常量

与C/C++不同,Python在语法上并没有定义常量,尽管PEP 8定义了常量的命名规范为大写字母和下划线组成。

在实际项目中,常量首次赋值后, 无法阻止其他代码对其进行修改或删除。

现存的办法

幸运的是该问题在2001年就有人给出了解决方案Constants in Python,基本内容如下:



class _const:
    class ConstError(TypeError):
        pass

    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,否则创建该属性。
  • 将_const实例化的对象赋值sys.modules[__name__],const模块被绑定成_const对象。__name__在首次载入const过程中为'const',而sys.modules是模块名与已加载模块的dict。

如何使用const模块呢?



import const const.magic = 23



若再次赋值const.magic,



const.magic = 88



则将抛出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.magic已经赋值):



del const.magic



则将抛出ConstError的异常。

配置文件与常量

实际项目中,为了让应用程序灵活部署,一般会用配置文件存储应用程序的各种参数;而这些参数通常都以常量语义存在于应用程序中。

在上述代码基础上,根据应用程序的实际情况将常量划分为3类:

  • 特殊含义的数值或字符串,如 ETC_FSTAB = “/etc/fstab” 。其作用为
  • 避免程序中到处出现类似特殊值,因为人为输入特殊值的低级错误将耗费不必要的调试/测试时间
  • 另一方面, 神秘数值(magic number),如 LUN_BLOCK_SIZE = 4096,将影响程序的可读性。
  • 应用程序参数的默认值,如 URLOPEN_DEFAULT_TIMEOUT = 15 。其作用主要为配置文件参数的默认值。
  • 通过配置文件载入的参数,如通过ConfigParser.SafeConfigParser解析形如ini文件的参数。

第1和2类常量作为_const类的类属性,第3类常量可以在__init__方法中初始化。如:



class _const:
    ETC_FSTAB = "/etc/fstab"
    LUN_BLOCK_SIZE = 4096
    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__也将无法初始化(绑定)对象属性。

python 变量

在Python中,变量的概念基本上和初中代数的方程变量是一致的。



例如,对于方程式 y=x*x x就是变量。当x=2时,计算结果是4,当x=5时,计算结果是25

只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型。

在Python程序中,变量是用一个变量名表示,变量名必须是大小写英文、数字和下划线(_)的组合,且不能用数字开头,比如:



a = 1



变量a是一个整数。



t_007 = 'T007'



变量t_007是一个字符串。

在Python中,等号=是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,例如:



a = 123 # a是整数 print a a = 'imooc' # a变为字符串 print a



这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。

静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。例如Java是静态语言,赋值语句如下(// 表示注释):



int a = 123; // a是整数类型变量 a = "mooc"; // 错误:不能把字符串赋给整型变量



和静态语言相比,动态语言更灵活,就是这个原因。

请不要把赋值语句的等号等同于数学的等号。比如下面的代码:



x = 10 x = x + 2



如果从数学上理解x = x + 2那无论如何是不成立的,在程序中,赋值语句先计算右侧的表达式x + 2,得到结果12,再赋给变量x。由于x之前的值是10,重新赋值后,x的值变成12。

Python变量在内存中的表示

最后,理解变量在计算机内存中的表示也非常重要。当我们写:a = 'ABC'时,Python解释器干了两件事情:

1. 在内存中创建了一个'ABC'的字符串;

2. 在内存中创建了一个名为a的变量,并把它指向'ABC'

也可以把一个变量a赋值给另一个变量b,这个操作实际上是把变量b指向变量a所指向的数据,例如下面的代码:



a = 'ABC' b = a a = 'XYZ' print b



最后一行打印出变量b的内容到底是'ABC'呢还是'XYZ'?如果从数学意义上理解,就会错误地得出b和a相同,也应该是'XYZ',但实际上b的值是'ABC',让我们一行一行地执行代码,就可以看到到底发生了什么事:

执行a = 'ABC',解释器创建了字符串  'ABC'和变量 a,并把a指向 'ABC':

python常量如何定义 python 常量_python

执行b = a,解释器创建了变量 b,并把b指向 a 指向的字符串'ABC':

python常量如何定义 python 常量_python常量如何定义_02

执行a = 'XYZ',解释器创建了字符串'XYZ',并把a的指向改为'XYZ',但b并没有更改:

python常量如何定义 python 常量_下划线_03

所以,最后打印变量b的结果自然是'ABC'了。

通过Python函数id( )可以更形象看到,id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。



>>> x = 2
>>> z=x
>>> id(x)
13397072
>>> id(z)
13397072



 Python中各类型的命名规范

  • 文件名 :全小写,可使用下划线
  • 包名:小写字母,单词之间用_分割(和模块名一样 ),应该是简短的、小写的名字。如果下划线可以改善可读性可以加入
  • 模块名:小写字母,单词之间用_分割 

  ad_stats.py 

  • 类名: 总是使用单词首字母大写的单词串,内部类可以使用额外的前导下划线

  ConfigUtil 

  MyClass

变量

  • 全局变量 (类变量,在java中相当于static变量): 大写字母,单词之间用_分割

  对于from M import *导入语句,如果想阻止导入模块内的全局变量可以使用旧有的规范,在全局变量上加一个前导的下划线。 
  *注意*:应避免使用全局变量

  NUMBER 
  COLOR_WRITE 

  • 普通变量: 小写字母,单词之间用_分割

  this_is_a_var 

  • 实例变量:以_开头,其他和普通变量一样  

  _price    
  _instance_var 

  • 私有实例变量(外部访问会报错): 以__开头(2个下划线),其他和普通变量一样

  __private_var 

  • 专有变量: __开头,__结尾,一般为python的自有变量,不要以这种方式命名

  __doc__ 
  __class__ 

  变量*注意*:  

  1.不论是类成员变量还是全局变量,均不使用 m 或 g 前缀(其他语言才会使用)。 
  2.私有类成员使用单一下划线前缀标识,多定义公开成员,少定义私有成员。 
  3.变量名不应带有类型信息,因为Python是动态类型语言。如 iValue、names_list、dict_obj 等都是不好的命名。 

函数&方法

  • 普通函数: 小写字母,单词之间用_分割(和普通变量一样)*注意*:混合大小写仅被允许用于这种风格已经占据优势的时候,以便保持向后兼容。

  get_name() 
  count_number() 
  ad_stat() 

  • 私有函数:__开头 (外部访问会报错)

  __get_name() 

  • 函数和方法的参数 

  总使用“self”作为实例方法的第一个参数。总使用“cls”作为类方法的第一个参数。 
  如果一个函数的参数名称和保留的关键字冲突,通常使用一个后缀下划线好于使用缩写或奇怪的拼写。 

  • 常量 

  常量名所有字母大写,由下划线连接各个单词如MAX_OVERFLOW,TOTAL。 

  • 异常 

  以“Error”作为后缀。 

  • 缩写 

  命名应当尽量使用全拼写的单词,缩写的情况有如下两种: 
  1.常用的缩写,如XML、ID等,在命名时也应只大写首字母,如XmlParser。 
  2.命名中含有长单词,对某个单词进行缩写。这时应使用约定成俗的缩写方式。 
  例如: 
  function 缩写为 fn 
  text 缩写为 txt 
  object 缩写为 obj 
  count 缩写为 cnt 
  number 缩写为 num,等。

  • 前导后缀下划线 

  一个前导下划线:表示非公有。 
  一个后缀下划线:避免关键字冲突。 
  两个前导下划线:当命名一个类属性引起名称冲突时使用。 
  两个前导和后缀下划线:“魔”(有特殊用途)对象或者属性,例如__init__或者__file__。绝对不要创造这样的名字,而只是使用它们。 
  *注意*:关于下划线的使用存在一些争议。 
  Python 用下划线作为变量前缀和后缀指定特殊变量。 

  xxx 不能用'from module import *'导入 
  __xxx__ 系统定义名字 
  __xxx 类中的私有变量名 

   核心风格:避免用下划线作为变量名的开始。