Python简介
- Python是一种动态解释型编程语言,在模块载入时将源码编译成字节码, 这些字节码被虚拟机PVM解释执行,其中解释执行是Python性能较低的主要原因;
- Python使用C语言编写,可以和C,C++,Java等语言结合使用:Java在Python上的实现Jython,具体参考:https://docs.python.org/2/tutorial/index.html,和.NET互通的IronPython,https://ironpython.codeplex.com/
编译执行
编译通常发生在模块载入的时候,编译器先将源码编译成字节码,保存在pyc文件中,如果使用-O参数,可生成pyo文件,是一种简单优化后的pyc文件;
对于pyc文件,编译过程如下:
- 核对文件Magic标记,Magic为一个特殊数字,由Python版本号计算得出,作为pyc文件检查的标记;
- 检查时间戳和源码文件修改时间是否相同,以确定是否需要重新编译;
- 载入模块;
对于py文件,编译过程如下:
- 对源码进行AST(抽象语法树)分析;
- 将分析结果编译成PyCodeObject;
- 将 Magic、源码?件修改时间、PyCodeObject 保存到 pyc 文件中;
- 载入模块;
执行可使用eval和exec函数,eval()用来执行一个表达式,exec用来执行一个代码片段,execfile()可动态执行一个py文件;
Pyhton基础与实践
主要介绍Python语言中一些基础但又很重要的知识,python对象、函数、类、正则表达式、编码转换等。
对象
一切皆对象
Python中一切皆为对象,每个对象都包含一个标准头,头信息由 "引用计数" 和 "类型指针" 组成。
"引用计数"为PVM中主要的垃圾回收机制,每当对象被引用时增加,超出作用域或调用del手工释放后递减,计数为0时被回收;
通过"类型指针"可明确知道对象的类型,指向Type对象,包含了其继承关系以及静态成员信息;
可使用sys.getrefcount(x)来查看对象的引用计数;
type(x)和x.__class__可查看对象类型;
hex(id(x))返回对象内存地址;
对于变长对象,其头部会多出一个记录元素数量的字段;
x=10 sys.getrefcount(x) #查看x引用计数,形参会增加一次计数; import types types(x) #查看x的类型信息; x.__class__ #__class__通过类型指针来获取对象类型;
对象类型
不可变类型:None,bool,int,float,long,complex,string,unicode,tuple,frozenset;
可变类型:list,dict,set
#bool int(True) # 1 int(False) # 0 #float ‘‘‘float默认采用双精度,可能不能精确表示十进制小数‘‘‘ float(‘0.1‘)*5 == float(‘0.5‘) # False round(‘2.675‘,2) # 2.67 #Decimal可精确控制位数,一般用Decimal代替float from decimal import Decimal Decimal(‘0.1‘)*5 == Decimal(‘0.5‘) # True #str,unicode ‘‘‘需要注意编码问题,使用decode(),encode()方法,一个项目中使用不同类型的编码,很容易造成错误‘‘‘ import logging logger = logging.getLogger(‘test‘) logger.info(‘%s is not %s‘ % (u‘测试汉字‘, ‘测试汉字‘)) #Error,混用两种不同类型编码 #python2.x默认编码为ascii,一般情况下需要进行转码操作,大部分情况下,我们在Python脚本头部都会将默认编码设为utf-8 # -*- coding: utf-8 -*- import sys sys.getdefaultencoding() # ascii #字符串拼接,一般情况下:join > ‘%s%s‘ > +,字符串前面加‘r‘,表示不转义; #dict #对于大字典,建议用迭代器代替keys(),values(),items()方法,降低内存开销 d={‘a‘:‘xxx‘.....} d.iterkeys(),d.itervalues(),d.iteritems() #求两个dict差集 d1 = {‘a‘:1, ‘b‘:2} d2 = {‘b‘:2, ‘c‘:3} v1 = d1.viewitems() v2 = d2.viewitems() v1 & v2, v1 | v2, v1 - v2, vi ^ v2 # 相当于set #dict是哈希表,默认是无序的,如需有序字典,可使用OrderedDict from collections import OrderedDict od = OrderedDict() od[‘a‘] = ‘qqq‘ od[‘b‘] = ‘bbb‘ for k,v in od.items(): print k,v # 按添加顺序输出 #set #判重公式: (a is b) or (hash(a) == hash(b) and eq(a,b)) #要将自定义类型放入set,需要重写__hash__和__eq__方法 class User(Object): def __init__(self, name): self.name = name def __hash__(self): return hash(self.name) def __eq__(self, other): if not other or not isinstance(other, User): return false return self.name == other.name
表达式
正则表达式
正则表达式基本在任何语言中都出现,对于开发来说,是必备的技能之一,Python正则表达式详见https://docs.python.org/2/library/re.html;
#IP地址匹配 import re def check_ip(ip): pattren = r‘^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|[0-9])\.XXX$‘ #不全,剩下类似 if re.match(pattern, ip): return True return False #由zimbra邮箱同步数据到AD的脚本中正则表达式应用实例: def get_mail_attrs(self, mail_info): pattern = r‘^cn:|^displayName|^mail:|^zimbraACE:.*ownDistList$|^(?!zimbra).*@‘ attrs = {} attrs[‘managedBy‘] = [] split_info = mail_info.split(‘\n‘) for line in split_info: if re.match(pattern, line): item = line.strip().split(‘: ‘) if item[0] == ‘zimbraACE‘: _id = item[1].split()[0] if _id in self.id_mail: _mail = self.id_mail[_id] attrs[‘managedBy‘].append(_mail) else: print ‘Error, %s has no mail‘ % _id elif len(item) > 1: attrs[item[0]] = item[1] else: if ‘members‘ not in attrs: attrs[‘members‘] = [] attrs[‘members‘].append(item[0]) #在字符串中使用正则表达式,如果不使用‘r‘标记,需要使用双重转义;
语句
注意循环和异常中的else,如:while...else...,for...else...,try...except...else...finally...,else在循环正常退出时执行,在except没有捕捉到异常时执行;
列表推导式
#举例说明列表推导式的应用 def test(x): return x**2 a = [test(x) for x in xrange(10) if x%2] b = [text(x) for x in open(‘number.txt‘, ‘r‘)] #生成字典 c = {c:ord(c) for c in ‘abc‘}d = {d:chr(d) for d in ‘123‘} #enumerate使用 for idx,num in enumerate([x for x in range(10)]): print "index[{0}] = {1}".format(idx, num)
函数
函数在同一名字空间中是不能重载的(由 __dict__[name] 唯一性决定),且总是有返回值,默认返回None;
引用传递
Python中都是按引用传递的,不管是赋值还是函数传参,不管是可变类型还是不可变类型;
按引用传递与按值传递的区别:引用传递传递的是内存地址,而值传递传递的是当前值的一个副本;
a = 10 b = 10 hex(id(a)) == hex(id(b)) #True a is b #True #函数参数传递,需要注意顺序,默认参数必须在位置参数之后,*args和**kwargs必须在默认参数之后; def test(a, b, c=10, d=‘ww‘, *args, **kwargs): print args,kwargs #如默认参数是使用def创建函数时生成的对象,以后调用函数会复用此对象,如第一次调用test后,a为[1],第二次调用后,a为[1,1]; def test(a=[]): a.append(1) print hex(id(a)) print a #对于可变对象,可使用deepcopy来进行深度复制,copy.deepcopy(x);
名字空间
python名字空间可理解为系统和自定义对象的name/object字典;
Python变量是一个字符串对象,它和目标对象一起在名字空间中构成一个 name/object 关联项,名字空间决定了对象的作用域和生存周期;
变量没有类型,对象有,变量的作用仅仅是在某个时刻与名字空间中的目标对象进行关联;
globals()获取模块级别名字空间,locals()获取当前上下文名字空间;
可以通过<module>.__dict__访问其他模块的名字空间;
对象查询顺序遵循LEGB原则,即locals -> enclosing -> globals -> __builtins__
常用函数
Python有许多常用函数可直接调用,如lambda,map,zip等,具体使用不再详细介绍。
类
Python 2.X版本中类模型有两种,Classic Class和New-Style Class,Classic Class支持多继承,但已被Python 3.0抛弃,大家在使用类时建议多使用New-Style Class,即继承object的类。
类中访问成员时,成员查找顺序: instance.__dict__ -> class.__dict__ -> baseclass.__dict__;
Python的内置类方法:getattr(obj, name[, default]),setattr(obj, name, value),hasattr(obj, name),delattr(obj, name);
Python的内置类属性:__dict__,__name__,__doc__,__module__,__bases__等;
属性
Python内置函数property()可以实现属性;
class Test(object): def get_name(self): return self.__name def set_name(self, value): self.__name = value def del_name(self): del self.__name name = property(get_name, set_name, del_name) class Test2(object): user_id = property(lambda self: self._user_id) user_name = property(lambda self: self._user_id, lambda self,value: setattr(self, ‘_user_name‘, value))
垃圾回收
Python的垃圾回收主要以引用计数为主,标记清除和分代回收为辅,理解垃圾回收的过程有助于编写代码不易造成内存泄露;
优先级:引用计数 > 标记清除 和分代回收
JSON与time模块
#JSON与Python对象之间的转换 json.dumps(x) #encoding的过程,将Python对象x编码转换为JSON字符串 json.loads(x) #decoding的过程,将JSON字符串x解码转换为Python对象 #time模块 #Python有两种表示时间的方式,时间戳以及数组形式。 #常用函数 time.clock() #第一次执行获取当前程序的执行时间,之后获取从第一次到当前程序运行所花费时间; time.sleep() #单位为秒 time.ctime() #将时间戳转换为时间字符串 time.localtime([seconds]) #将时间戳转换为当前时区的数组形式 time.mktime(tuple) #将数组形式time对象转换为时间戳 time.strftime(format[, tuple]) #将数组形式time对象转换为指定格式化形式 time.strptime(string, format) #将时间字符串根据指定格式转换为数组形式time对象 time.time() #获取当前时间的时间戳 #获取当前文件所在绝对路径 os.path.dirname(os.path.abspath(__file__))