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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM