日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python深入_Python深入(上)

發布時間:2023/12/20 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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')

總結

以上是生活随笔為你收集整理的python深入_Python深入(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。