python深入_Python深入(上)

作者:Vamei 出處:http://www.cnblogs.com/vamei?歡迎轉載,也請保留這段聲明。謝謝!

到現在為止,Python學習已經可以告一段落。下面的部分,我想討論Python的高級語法和底層實現。這一部分的內容并不是使用Python所必須的。但如果你想從事一些大型的Python開發(比如制作Python工具、寫一個框架等),你會希望對這一部分內容有所的了解。

一、特殊方法與多范式

Python?一切皆對象,但同時,Python還是一個多范式語言(multi-paradigm),你不僅可以使用面向對象的方式來編寫程序,還可以用面向過程的方式來編寫相同功能的程序(還有函數式、聲明式等,我們暫不深入)。Python的多范式依賴于Python對象中的特殊方法(special method)。

特殊方法名的前后各有兩個下劃線。特殊方法又被成為魔法方法(magic method),定義了許多Python?語法和表達方式,正如我們在下面的例子中將要看到的。當對象中定義了特殊方法的時候,Python也會對它們有“特殊優待”。比如定義了__init__()方法的類,會在創建對象的時候自動執行__init__()方法中的操作。

(可以通過dir()來查看對象所擁有的特殊方法,比如dir(1))。

1、運算符

Python的運算符是通過調用對象的特殊方法實現的。比如:

'abc' + 'xyz' # 連接字符串

實際執行了如下操作:

'abc'.__add__('xyz')

所以,在Python中,兩個對象是否能進行加法運算,首先就要看相應的對象是否有__add__()方法。一旦相應的對象有__add__()方法,即使這個對象從數學上不可加,我們都可以用加法的形式,來表達obj.__add__()所定義的操作。在Python中,運算符起到簡化書寫的功能,但它依靠特殊方法實現。

Python不強制用戶使用面向對象的編程方法。用戶可以選擇自己喜歡的使用方式(比如選擇使用+符號,還是使用更加面向對象的__add__()方法)。特殊方法寫起來總是要更費事一點。

2、內置函數

與運算符類似,許多內置函數也都是調用對象的特殊方法。比如:

len([1,2,3]) # 返回表中元素的總數

實際上做的是:

[1,2,3].__len__()

相對與__len__(),內置函數len()也起到了簡化書寫的作用。

3、表(list)元素引用

下面是我們常見的表元素引用方式:

li =[1, 2, 3, 4, 5, 6]

print(li[3])

上面的程序運行到li[3]的時候,Python發現并理解[]符號,然后調用__getitem__()方法。

li =[1, 2, 3, 4, 5, 6]

print(li.__getitem__(3))

4、函數

我們已經說過,在Python中,函數也是一種對象。實際上,任何一個有__call__()特殊方法的對象都被當作是函數。比如下面的例子:

class SampleMore(object):

def __call__(self, a):

return a + 5

add = SampleMore() # A function object

print(add(2)) # Call function

map(add, [2, 4, 5]) # Pass around function object

add為SampleMore類的一個對象,當被調用時,add執行加5的操作。add還可以作為函數對象,被傳遞給map()函數。

當然,我們還可以使用更“優美”的方式,想想是什么。

二、上下文管理器

上下文管理器(context manager)是Python2.5開始支持的一種語法,用于規定某個對象的使用范圍。一旦進入或者離開該使用范圍,會有特殊操作被調用 (比如為對象分配或者釋放內存)。它的語法形式是with...as...

1、關閉文件

我們會進行這樣的操作:打開文件,讀寫,關閉文件。程序員經常會忘記關閉文件。上下文管理器可以在不需要文件的時候,自動關閉文件。

下面我們看一下兩段程序:

# without context manager

f = open("new.txt", "w")

print(f.closed) # whether the file is open

f.write("Hello World!")

f.close()

print(f.closed)

以及:

# with context manager

with open("new.txt", "w") as f:

print(f.closed)

f.write("Hello World!")

print(f.closed)

兩段程序實際上執行的是相同的操作。我們的第二段程序就使用了上下文管理器 (with...as...)。上下文管理器有隸屬于它的程序塊。當隸屬的程序塊執行結束的時候(也就是不再縮進),上下文管理器自動關閉了文件 (我們通過f.closed來查詢文件是否關閉)。我們相當于使用縮進規定了文件對象f的使用范圍。

上面的上下文管理器基于f對象的__exit__()特殊方法(還記得我們如何利用特殊方法來實現各種語法?參看特殊方法與多范式)。當我們使用上下文管理器的語法時,我們實際上要求Python在進入程序塊之前調用對象的__enter__()方法,在結束程序塊的時候調用__exit__()方法。對于文件對象f來說,它定義了__enter__()和__exit__()方法(可以通過dir(f)看到)。在f的__exit__()方法中,有self.close()語句。所以在使用上下文管理器時,我們就不用明文關閉f文件了。

2、自定義

任何定義了__enter__()和__exit__()方法的對象都可以用于上下文管理器。文件對象f是內置對象,所以f自動帶有這兩個特殊方法,不需要自定義。

下面,我們自定義用于上下文管理器的對象,就是下面的myvow:

# customized object

class VOW(object):

def __init__(self, text):

self.text = text

def __enter__(self):

self.text = "I say: " + self.text # add prefix

return self # note: return an object

def __exit__(self,exc_type,exc_value,traceback):

self.text = self.text + "!" # add suffix

with VOW("I'm fine") as myvow:

print(myvow.text)

print(myvow.text)

我們的運行結果如下:

I say: I'm fine

I say: I'm fine!

我們可以看到,在進入上下文和離開上下文時,對象的text屬性發生了改變(最初的text屬性是"I'm fine")。

__enter__()返回一個對象。上下文管理器會使用這一對象作為as所指的變量,也就是myvow。在__enter__()中,我們為myvow.text增加了前綴 ("I say: ")。在__exit__()中,我們為myvow.text增加了后綴("!")。

注意: __exit__()中有四個參數。當程序塊中出現異常(exception),__exit__()的參數中exc_type, exc_value, traceback用于描述異常。我們可以根據這三個參數進行相應的處理。如果正常運行結束,這三個參數都是None。在我們的程序中,我們并沒有用到這一特性。

由于上下文管理器帶來的便利,它是一個值得使用的工具。

三、對象的屬性

Python一切皆對象(object),每個對象都可能有多個屬性(attribute)。Python的屬性有一套統一的管理方案。

1、屬性的__dict__系統

對象的屬性可能來自于其類定義,叫做類屬性(class attribute)。類屬性可能來自類定義自身,也可能根據類定義繼承來的。一個對象的屬性還可能是該對象實例定義的,叫做對象屬性(object attribute)。

對象的屬性儲存在對象的__dict__屬性中。__dict__為一個詞典,鍵為屬性名,對應的值為屬性本身。我們看下面的類和對象。chicken類繼承自bird類,而summer為chicken類的一個對象。

class bird(object):

feather = True

class chicken(bird):

fly = False

def __init__(self, age):

self.age = age

summer = chicken(2)

print(bird.__dict__)

print(chicken.__dict__)

print(summer.__dict__)

下面為我們的輸出結果:

{'__dict__': , '__module__': '__main__', '__weakref__': , 'feather': True, '__doc__': None}

{'fly': False, '__module__': '__main__', '__doc__': None, '__init__': }

{'age': 2}

第一行為bird類的屬性,比如feather。第二行為chicken類的屬性,比如fly和__init__方法。第三行為summer對象的屬性,也就是age。有一些屬性,比如__doc__,并不是由我們定義的,而是由Python自動生成。此外,bird類也有父類,是object類(正如我們的bird定義,class bird(object))。這個object類是Python中所有類的父類。

可以看到,Python中的屬性是分層定義的,比如這里分為object/bird/chicken/summer這四層。當我們需要調用某個屬性的時候,Python會一層層向上遍歷,直到找到那個屬性。(某個屬性可能出現再不同的層被重復定義,Python向上的過程中,會選取先遇到的那一個,也就是比較低層的屬性定義)。

當我們有一個summer對象的時候,分別查詢summer對象、chicken類、bird類以及object類的屬性,就可以知道summer對象所有的__dict__,就可以找到通過對象summer可以調用和修改的所有屬性了。下面兩種屬性修改方法等效:

summer.__dict__['age'] = 3

print(summer.__dict__['age'])

summer.age = 5

print(summer.age)

(上面的情況中,我們已經知道了summer對象的類為chicken,而chicken類的父類為bird。如果只有一個對象,而不知道它的類以及其他信息的時候,我們可以利用__class__屬性找到對象的類,然后調用類的__base__屬性來查詢父類) 。

2、特性

同一個對象的不同屬性之間可能存在依賴關系。當某個屬性被修改時,我們希望依賴于該屬性的其他屬性也同時變化。這時,我們不能通過__dict__的方式來靜態的儲存屬性。Python提供了多種即時生成屬性的方法。其中一種稱為特性(property)。特性是特殊的屬性。比如我們為chicken類增加一個特性adult。當對象的age超過1時,adult為True;否則為False:

class bird(object):

feather = True

class chicken(bird):

fly = False

def __init__(self, age):

self.age = age

def getAdult(self):

if self.age > 1.0: return True

else: return False

adult = property(getAdult) # property is built-in

summer = chicken(2)

print(summer.adult)

summer.age = 0.5

print(summer.adult)

特性使用內置函數property()來創建。property()最多可以加載四個參數。前三個參數為函數,分別用于處理查詢特性、修改特性、刪除特性。最后一個參數為特性的文檔,可以為一個字符串,起說明作用。

我們使用下面一個例子進一步說明:

class num(object):

def __init__(self, value):

self.value = value

def getNeg(self):

return -self.value

def setNeg(self, value):

self.value = -value

def delNeg(self):

print("value also deleted")

del self.value

neg = property(getNeg, setNeg, delNeg, "I'm negative")

x = num(1.1)

print(x.neg)

x.neg = -22

print(x.value)

print(num.neg.__doc__)

del x.neg

上面的num為一個數字,而neg為一個特性,用來表示數字的負數。當一個數字確定的時候,它的負數總是確定的;而當我們修改一個數的負數時,它本身的值也應該變化。這兩點由getNeg和setNeg來實現。而delNeg表示的是,如果刪除特性neg,那么應該執行的操作是刪除屬性value。property()的最后一個參數("I'm negative")為特性negative的說明文檔。

3、使用特殊方法__getattr__

我們可以用__getattr__(self, name)來查詢即時生成的屬性。當我們查詢一個屬性時,如果通過__dict__方法無法找到該屬性,那么Python會調用對象的__getattr__方法,來即時生成該屬性。比如:

class bird(object):

feather = True

class chicken(bird):

fly = False

def __init__(self, age):

self.age = age

def __getattr__(self, name):

if name == 'adult':

if self.age > 1.0: return True

else: return False

else: raise AttributeError(name)

summer = chicken(2)

print(summer.adult)

summer.age = 0.5

print(summer.adult)

print(summer.male)

每個特性需要有自己的處理函數,而__getattr__可以將所有的即時生成屬性放在同一個函數中處理。__getattr__可以根據函數名區別處理不同的屬性。比如上面我們查詢屬性名male的時候,raise AttributeError。

(Python中還有一個__getattribute__特殊方法,用于查詢任意屬性。__getattr__只能用來查詢不在__dict__系統中的屬性)

__setattr__(self, name, value)和__delattr__(self, name)可用于修改和刪除屬性。它們的應用面更廣,可用于任意屬性。

4、即時生成屬性的其他方式

即時生成屬性還可以使用其他的方式,比如descriptor ( descriptor類實際上是property()函數的底層,property()實際上創建了一個該類的對象 ) 。有興趣可以進一步查閱。

作業

嘗試下面的操作,看看效果,再想想它的對應運算符:

(1.8).__mul__(2.0)

True.__or__(False)

嘗試下面的操作,想一下它的對應內置函數:

(-1).__abs__()

(2.3).__int__()

嘗試看下面的操作,想想它的對應:

li.__setitem__(3, 0)

{'a':1, 'b':2}.__delitem__('a')

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457659.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457659.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457659.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

06_JS對象

JS對象 創建對象 構造函數:var obj new Object()對象字面量:var obj {}; 不同:對象字面量可以在創建的同時為對象設置屬性,最后一個屬性后面不要加逗號 對象操作 添加屬性:對象名.新屬性名 值修改屬性&#xf…

BZOJ4107 : [Wf2015]Asteroids

首先將速度相減,變成A在動而B不動,若速度為0則顯然永遠不會相交。 枚舉A的每個點以及B的每條線段,計算這三個點共線的時刻。 將時刻排序,對于每個區間進行三分,用半平面交計算相交面積。 注意特判相交面積為0但是存在交…

Web Service 性能測試工具比較

背景 希望選擇一款Web Service性能測試工具,能真實模擬大量用戶訪問網站時的請求,從而獲取服務器當前的請求處理能力(請求數/秒)。以微信服務器為例,每個用戶用獨立的登錄token,做各種操作,比如…

python中的常量是什么意思_第14p,Python中的常量與注釋。

大家好,我是楊數Tos,這是《從零基礎到大神》系列課程的第14篇文章,第二階段的課程:Python基礎知識:常量與注釋。學習本課程,建議先看一遍:【計算機基礎知識】課程。一、Python中的常量1、什么是…

07_JS函數

JS函數 函數聲明 使用構造函數 var fun new Function();使用關鍵字 function 函數名(形參){// 函數體 }匿名函數 var fun1 function(){name "fun1" }函數參數 實參,形參都可以是任意數據類型,瀏覽器執行時不會檢查實參類型和數量&…

cocoapods的安裝(這真是一個神奇的東西,每次安裝的方法都不一樣,而且很容易出現各種各樣的錯誤)...

文章開始之前,建議安裝一個顯示網速的插件,不然你不知道到底有沒有下載,也讓生活有一點盼頭 1.因為眾所周知的原因(我dang的行為真的是讓人失望),先更換一下ruby鏡像源 $ gem sources --remove https://rub…

轉】MyEclipse使用總結——在MyEclipse中設置jsp頁面為默認utf-8編碼

原博文出自于:http://www.cnblogs.com/xdp-gacl/p/3496161.html        感謝! 在MyEclispe中創建Jsp頁面,Jsp頁面的默認編碼是“ISO-8859-1”,如下圖所示: 在這種編碼下編寫中文是沒有辦法保存Jsp頁面的&#…

sum怎么用python_python sum()函數和.sum(axis=0)函數的使用

參考:《Machine Learning in Action》第二章#####################################################################sum函數:sum()函數是內建函數help(sum)函數功能:返回一個數字序列(非字符串)的和,并加上參數start的值(默認為…

08_JS工廠方法和構造函數

工廠方法和構造函數 工廠方法 工廠方法用來批量產生對象 function CreatCar(name,prase){// new 一個對象var obj new Object();obj.name name;obj.parse prase;obj.print function(){console.log(this.name " : " this.parse)};// 返回對象return obj; };va…

華為機試題【10】-求數字基root

題目描述: 求整數的Root:給定正整數,求每位數字之和;如果和不是一位數,則重復; 輸入:輸入任意一個或多個整數 輸出:輸出各位數字之和,直到和為個位數為止(輸入異常,則返回-1),多行,每行對應一個輸入數據的結果。 樣例…

國內開源鏡像站

搜狐開源鏡像站:http://mirrors.sohu.com/ 網易開源鏡像站:http://mirrors.163.com/開源中國:http://mirrors.oschina.net/首都在線科技股份有限公司:http://mirrors.yun-idc.com/阿里云開源鏡像:http://mirrors.aliyu…

python update skeleton 不自動_python編程筆記(1)-數據類型

斷斷續續學了一些,但是后邊一直沒有使用,就又忘記了。為了縮短學習周期,這次學習的方法:先學主要框架(數據類型、條件、循環、函數、類、numpy、pandas、sklearn),后期直接看朋友code 實操了&am…

09_JS原型對象

原型對象 在構造函數中,同一類相同的方法可以直接寫在構造函數里,但這樣每實例化一個對象都會產生一個新的該方法,但其實這個方法都是一樣的,這樣會浪費大量空間,另外,可以將相同的方法寫在構造函數外&…

[改善Java代碼]非穩定排序推薦使用List

我們知道Set與List的最大區別就是Set中的元素不可以重復(這個重復指的equals方法的返回值相等),其他方面則沒有太大的區別了,在Set的實現類中有一個比較常用的類需要了解一下:TreeSet,該類實現了類默認排序…

如何訪問另一臺電腦的共享文件夾_如何遠程控制另一臺電腦

在工作中,我們時常需要遠程控制一下另一臺電腦,如果這兩臺計算機在局域網內可以通過遠程桌面輕松實現,如果這兩臺計算機不在局域網內則通常需要借助第三方軟件來實現。遠程桌面使用分三步:1、被控制端要開啟遠程桌面功能&#xff…

10_JS數組

JS 數組 以索引為鍵的對象&#xff0c;性能高于對象 創建 new Array() var arr Array() for(var i 0;i<5;i){arr[i] i; };var arr Array(1,2,3,4,5,6)數組字面量 var arr [2,3,4,5,6,7,8];不同&#xff1a;傳入一個整數時&#xff0c;new把這個數當作數組長度&…

微軟Hololens學院教程- Holograms 101: Introduction with Device【微軟教程已經更新,本文是老版本】...

這是老版本的教程&#xff0c;為了不耽誤大家的時間&#xff0c;請直接看原文&#xff0c;本文僅供參考哦&#xff01;原文鏈接&#xff1a;https://developer.microsoft.com/EN-US/WINDOWS/HOLOGRAPHIC/holograms_101 這篇文章將通過一個完整的實例來了解設備的核心特性&#…

python seaborn boxplot_python - 如何將文本框添加到Seaborn Boxplot? - 堆棧內存溢出

我試圖在框圖中插入一個文本框&#xff0c;但是出了點問題。 讓我們先繪制箱線圖&#xff1a;import pandas as pdimport matplotlib.pyplot as pltimport seaborn as sbdf_data pd.read_hdf(data.h5, keyfdf_data)##print(df_data)fig, (ax1, ax2) plt.subplots(1,2,gridspe…

JS_11正則表達式和字符串方法

正則表達式和字符串方法 正則表達式 創建正則對象 構造函數字面量 匹配模式 i&#xff1a;忽略大小寫m&#xff1a;多行匹配g&#xff1a;全局匹配 正則語法 正則作用/a/檢查是否有a/a|b/檢查是否有a或b{}量詞&#xff0c;如{1,3}匹配1到3次&#xff0c;{m,}匹配m次以上…

qtableview點擊行將整行數據傳過去_可以實時獲取數據的Database Asset插件

前言&#xff1a;Goby之前開放的插件入口點較少&#xff0c;大家只能在掃描前、掃描后執行事件&#xff0c;無法參與掃描過程中來。為實現更多場景的應用及提高掃描效率&#xff08;如&#xff1a;后臺爆破子域名等&#xff09;&#xff0c;Goby開放了一些新的API&#xff1a;事…