一、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':
执行b = a
,解释器创建了变量 b,并把b指向 a 指向的字符串'ABC':
执行a = 'XYZ'
,解释器创建了字符串'XYZ',并把a的指向改为'XYZ',但b并没有更改:
所以,最后打印变量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 类中的私有变量名
核心风格:避免用下划线作为变量名的开始。