Python基础总结与实践

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__))

  

posted @ 2015-02-07 16:03  冰轮封雪  阅读(3204)  评论(0编辑  收藏  举报