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))
垃圾回收
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__))