Python進階語法——函數(shù)式編程魔种、模塊,面向對象

一粉洼、 Python進階學習

![1561517114609.png](https://upload-images.jianshu.io/upload_images/18575213-055b0d93ec1ac882.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

一节预、函數(shù)式編程

1.1函數(shù)式編程

1561517114609.png
1561517172562.png
![1561517281088.png](https://upload-images.jianshu.io/upload_images/18575213-acd06f8057bd7dfc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

1.2高階函數(shù)

1.2.1

![1561517550621.png](https://upload-images.jianshu.io/upload_images/18575213-08d529dcc74f60b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

import math
def add(x, y, f):
return f(x) + f(y)
print add(25, 9, math.sqrt)

1.2.2python中map()函數(shù)

map()是 Python 內(nèi)置的高階函數(shù),它接收一個函數(shù) f 和一個 list属韧,并通過把函數(shù) f 依次作用在 list 的每個元素上安拟,得到一個新的 list 并返回。

def f(x):
return x*x
print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
輸出結果:

[1, 4, 9, 10, 25, 36, 49, 64, 81]
注意:map()函數(shù)不改變原有的 list宵喂,而是返回一個新的 list糠赦。


1561518419092.png

利用map()函數(shù),可以把一個 list 轉換為另一個 list锅棕,只需要傳入轉換函數(shù)拙泽。

1.2.3python中reduce()函數(shù)

reduce()函數(shù)也是一個高階函數(shù),接收的參數(shù)一個函數(shù) f裸燎,一個list顾瞻,但行為和 map()不同,reduce()傳入的函數(shù) f 必須接收兩個參數(shù)德绿,reduce()對list的每個元素反復調用函數(shù)f荷荤,并返回最終結果值。

(1)編寫一個f函數(shù)脆炎,接收x和y梅猿,返回x和y的和:

def f(x, y):
return x + y
調用 reduce(f, [1, 3, 5, 7, 9])時,reduce函數(shù)將做如下計算:

先計算頭兩個元素:f(1, 3)秒裕,結果為4袱蚓;
再把結果和第3個元素計算:f(4, 5),結果為9几蜻;
再把結果和第4個元素計算:f(9, 7)喇潘,結果為16;
再把結果和第5個元素計算:f(16, 9)梭稚,結果為25颖低;
由于沒有更多的元素了,計算結束弧烤,返回結果25忱屑。
上述計算實際上是對 list 的所有元素求和。
雖然Python內(nèi)置了求和函數(shù)sum(),但是莺戒,利用reduce()求和也很簡單伴嗡。

reduce()還可以接收第3個可選參數(shù),作為計算的初始值从铲。如果把初始值設為100瘪校,計算:

reduce(f, [1, 3, 5, 7, 9], 100)
結果是125

(2)編寫一個f函數(shù),接收x和y名段,返回x和y的積:

def prod(x, y):
return x * y
print reduce(prod, [2, 4, 5, 7, 12])

1.2.4python中filter()函數(shù)

filter()函數(shù)是 Python 內(nèi)置的另一個有用的高階函數(shù)阱扬,filter()函數(shù)接收一個函數(shù) f 和一個list,這個函數(shù) f 的作用是對每個元素進行判斷伸辟,返回 True或 False麻惶,filter()根據(jù)判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list自娩。

eg:請利用filter()過濾出1~100中平方根是整數(shù)的數(shù)用踩,即結果應該是:
import math
def is_sqr(x):
if math.sqrt(x)%1==0 :
return x
print filter(is_sqr, range(1, 101))

注意:s.strip(rm) 刪除 s 字符串中開頭、結尾處的 rm 序列的字符

當rm為空時忙迁,默認刪除空白符(包括'\n', '\r', '\t', ' ')脐彩,如下:
a='\t\t123\r\n'
a.strip()
結果:'123'

1.2.5python中自定義排序函數(shù)

Python內(nèi)置的 sorted()函數(shù)可對list進行排序:

sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]

但 sorted()也是一個高階函數(shù),它可以接收一個比較函數(shù)來實現(xiàn)自定義排序姊扔,比較函數(shù)的定義是惠奸,傳入兩個待比較的元素 x, y,如果 x 應該排在 y 的前面恰梢,返回 -1佛南,如果 x 應該排在 y 的后面,返回 1嵌言。如果 x 和 y 相等嗅回,返回 0。

要實現(xiàn)倒序排序摧茴,只需要編寫一個reversed_cmp函數(shù):

def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
這樣绵载,調用 sorted() 并傳入 reversed_cmp 就可以實現(xiàn)倒序排序:

參數(shù)先寫list,再寫f函數(shù)?涟住M薇!9喝埂懂版!

sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]
sorted()也可以對字符串進行排序,字符串默認按照ASCII大小來比較:

sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
'Zoo'排在'about'之前是因為'Z'的ASCII碼比'a'小躏率。

任務
對字符串排序時躯畴,有時候忽略大小寫排序更符合習慣民鼓。請利用sorted()高階函數(shù),實現(xiàn)忽略大小寫排序的算法私股。

輸入:['bob', 'about', 'Zoo', 'Credit']
輸出:['about', 'bob', 'Credit', 'Zoo']

1.2.6返回函數(shù)

請注意區(qū)分返回函數(shù)和返回值:

def myabs():

return abs   # 返回函數(shù)

def myabs2(x):
return abs(x) # 返回函數(shù)調用的結果摹察,返回值是一個數(shù)值

eg:
def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum

調用calc_sum()并沒有計算出結果,而是返回函數(shù):

f = calc_sum([1, 2, 3, 4])
f
eg:請利用filter()過濾出1~100中平方根是整數(shù)的數(shù)倡鲸,即結果應該是:
>import math
def is_sqr(x):
if math.sqrt(x)%1==0 :
return x
print filter(is_sqr, range(1, 101))

>>注意:s.strip(rm) 刪除 s 字符串中開頭、結尾處的 rm 序列的字符

>當rm為空時黄娘,默認刪除空白符(包括'\n', '\r', '\t', ' ')峭状,如下:
a='\t\t123\r\n'
a.strip()
結果:'123'

###1.2.5python中自定義排序函數(shù)
Python內(nèi)置的 sorted()函數(shù)可對list進行排序:
>sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]

但 sorted()也是一個高階函數(shù),它可以接收一個比較函數(shù)來實現(xiàn)自定義排序逼争,比較函數(shù)的定義是优床,傳入兩個待比較的元素 x, y,如果 x 應該排在 y 的前面誓焦,返回 -1胆敞,如果 x 應該排在 y 的后面,返回 1杂伟。如果 x 和 y 相等移层,返回 0。

要實現(xiàn)倒序排序赫粥,只需要編寫一個reversed_cmp函數(shù):

>def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
這樣观话,調用 sorted() 并傳入 reversed_cmp 就可以實現(xiàn)倒序排序:
>>參數(shù)先寫list,再寫f函數(shù)T狡健F祷住!G嘏选晦溪!

>> sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]
sorted()也可以對字符串進行排序,字符串默認按照ASCII大小來比較:

>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
'Zoo'排在'about'之前是因為'Z'的ASCII碼比'a'小挣跋。

任務
對字符串排序時三圆,有時候忽略大小寫排序更符合習慣。請利用sorted()高階函數(shù)浆劲,實現(xiàn)忽略大小寫排序的算法嫌术。

輸入:['bob', 'about', 'Zoo', 'Credit']
輸出:['about', 'bob', 'Credit', 'Zoo']
###1.2.6返回函數(shù)
請注意區(qū)分返回函數(shù)和返回值:
>def myabs():
return abs # 返回函數(shù)
def myabs2(x):
return abs(x) # 返回函數(shù)調用的結果,返回值是一個數(shù)值

>>eg:
>def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum

調用calc_sum()并沒有計算出結果牌借,而是返回函數(shù):

>> f = calc_sum([1, 2, 3, 4])
>> f
<function lazy_sum at 0x1037bfaa0>
對返回的函數(shù)進行調用時度气,才計算出結果:
f()
10

1.2.7閉包(Closure)

1、定義
內(nèi)層函數(shù)引用了外層函數(shù)的變量(參數(shù)也算變量)膨报,然后返回內(nèi)層函數(shù)的情況磷籍,稱為閉包(Closure)适荣。
2、特點
返回的函數(shù)還引用了外層函數(shù)的局部變量院领,要確保引用的局部變量在函數(shù)返回后不能變弛矛。舉例如下:
希望一次返回3個函數(shù),分別計算1x1,2x2,3x3:

def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()

你可能認為調用f1()比然,f2()和f3()結果應該是1丈氓,4,9强法,但實際結果全部都是 9
原因就是當count()函數(shù)返回了3個函數(shù)時万俗,這3個函數(shù)所引用的變量 i 的值已經(jīng)變成了3。由于f1饮怯、f2闰歪、f3并沒有被調用,所以蓖墅,此時他們并未計算 i*i库倘,當 f1 被調用時:

f1()
9

因為f1現(xiàn)在才計算i*i,但現(xiàn)在i的值已經(jīng)變?yōu)?
因此论矾,返回函數(shù)不要引用任何循環(huán)變量教翩,或者后續(xù)會發(fā)生變化的變量。
修改后:

def count():
fs = []
for i in range(1, 4):
def f(j):
def g():
return j*j
return g
fi=f(i)
fs.append(fi)
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()

1.2.8匿名函數(shù)lambda

關鍵字lambda 表示匿名函數(shù)拇囊,冒號前面的 x 表示函數(shù)參數(shù)迂曲。
匿名函數(shù)有個限制,就是只能有一個表達式寥袭,不寫return路捧,返回值就是該表達式的結果。
使用匿名函數(shù)传黄,可以不必定義函數(shù)名杰扫,直接創(chuàng)建一個函數(shù)對象:

sorted([1, 3, 9, 5, 0], lambda x,y : -cmp(x,y))
[9, 5, 3, 1, 0]

返回函數(shù)的時候,也可以返回匿名函數(shù):

myabs = lambda x : -x if x < 0 else x
myabs(-1)
1

1.2.9decorator裝飾器

1膘掰、裝飾器定義

Python的 decorator 本質上就是一個高階函數(shù)章姓,它接收一個函數(shù)作為參數(shù),然后识埋,返回一個新函數(shù)凡伊。
不用裝飾器:


1561535968062.png

使用裝飾器:


1561536060596.png
![1561536294538.png](https://upload-images.jianshu.io/upload_images/18575213-9b1a6698cf579312.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2、編寫無參數(shù)的decorator
要讓 @log 自適應任何參數(shù)定義的函數(shù)窒舟,可以利用Python的 *args 和 **kw系忙,保證任意個數(shù)的參數(shù)總是能正常調用:

def log(f):
def fn(*args, *kw):
print 'call ' + f.name + '()...'
return f(
args, **kw)
return fn

eg:請編寫一個@performance,它可以打印出函數(shù)調用的時間惠豺。

計算函數(shù)調用的時間可以記錄調用前后的當前時間戳银还,然后計算兩個時間戳的差风宁。
import time
def performance(f):
def fn(*args, *kw):
t1 = time.time()
r = f(
args, *kw)
t2 = time.time()
print 'call %s() in %fs' % (f.name, (t2 - t1))
return r
return fn
performance
def factorial(n):
return reduce(lambda x,y: x
y, range(1, n+1))
print factorial(10)

3、帶參數(shù)的decorator
如果有的函數(shù)非常重要蛹疯,希望打印出'[INFO] call xxx()...'戒财,有的函數(shù)不太重要,希望打印出'[DEBUG] call xxx()...'捺弦,這時饮寞,log函數(shù)本身就需要傳入'INFO'或'DEBUG'這樣的參數(shù),類似這樣:

@log('DEBUG')
def my_func():
pass

把上面的定義翻譯成高階函數(shù)的調用羹呵,就是:

my_func = log('DEBUG')(my_func)

上面的語句看上去還是比較繞骂际,再展開一下:

log_decorator = log('DEBUG')
my_func = log_decorator(my_func)

eg:@performance只能打印秒,請給 @performace 增加一個參數(shù)冈欢,允許傳入's'或'ms':


1561539338978.png

三層嵌套:最外層要先返回一個decorator,第二層返回wrapper盈简,第三層返回原來的函數(shù)f

1.2.10完善的decorator

decorator“改造”后的函數(shù)凑耻,和原函數(shù)相比,除了功能多一點外柠贤,有沒有其它不同的地方香浩?

(1)在沒有decorator的情況下,打印函數(shù)名:

def f1(x):
pass
print f1.name
輸出: f1

(2)有decorator的情況下臼勉,再打印函數(shù)名:

def log(f):
def wrapper(*args, *kw):
print 'call...'
return f(
args, **kw)
return wrapper
@log
def f2(x):
pass
print f2.name
輸出: wrapper

解決方案:
Python內(nèi)置的functools可以用來自動化完成這個“復制”的任務:

import functools
def log(f):
@functools.wraps(f)
def wrapper(*args, *kw):
print 'call...'
return f(
args, **kw)
return wrapper
二邻吭、模塊
模塊名沖突:

1561600539881.png

引用模塊:


![1561600680685.png](https://upload-images.jianshu.io/upload_images/18575213-d98ca2ccec31aed9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

包可以有多層:
但每一層必須 包含一個文件__init.py

![![![1561603309443.png](https://upload-images.jianshu.io/upload_images/18575213-e987af8cefcec89c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](https://upload-images.jianshu.io/upload_images/18575213-c420429ca6c80562.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](https://upload-images.jianshu.io/upload_images/18575213-847063dea88323c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2.2導入模塊

若干種方式:(eg :os.path)

import os
import os.path
from os import path
from os.path import isdir, isfile

[圖片上傳失敗...(image-bf3006-1562071047270)]
2、動態(tài)導入模塊

try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try 的作用是捕獲錯誤宴霸,并在捕獲到指定錯誤時執(zhí)行 except 語句囱晴。

導入新版本的新特性:
當新版本的一個特性與舊版本不兼容時,該特性將會在舊版本中添加到future中瓢谢,以便舊的代碼能在舊版本中測試新特性畸写。

from future import unicode_literals
s = 'am I an unicode?'
print isinstance(s, unicode)

3、導入第三方模塊
python內(nèi)置了許多模塊氓扛,但仍有外部模塊枯芬,可以導入使用
eg:pip

三、面向對象

1561603249167.png

1561603309443.png

3.1實例化屬性:

請定義Person類的init方法采郎,除了接受 name千所、gender 和 birth 外,還可接受任意關鍵字參數(shù)蒜埋,并把他們都作為屬性賦值給實例淫痰。
要定義關鍵字參數(shù),使用 **kw理茎;
除了可以直接使用self.name = 'xxx'設置一個屬性外黑界,還可以通過 setattr(self, 'name', 'xxx') 設置屬性管嬉。
參考代碼:

class Person(object):
def init(self, name, gender, birth, **kw):
self.name = name
self.gender = gender
self.birth = birth
for k, v in kw.iteritems():
setattr(self, k, v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
print xiaoming.name
print xiaoming.job

3.2屬性的訪問限制:

[圖片上傳中...(1561606531797.png-a6873d-1562070557388-0)]

(1)以雙下劃線開頭的屬性‘__xxx'不能直接被外部訪問。
(2)以"xxx"的形式定義朗鸠,那它又可以被外部訪問了蚯撩,以"xxx"定義的屬性在Python的類中被稱為特殊屬性,有很多預定義的特殊屬性可以使用烛占,通常我們不要把普通屬性用"xxx"定義胎挎。
(3)以單下劃線開頭的屬性"_xxx"雖然也可以被外部訪問,但是忆家,按照習慣犹菇,他們不應該被外部訪問。

3.3類屬性

實例屬性每個實例各自擁有芽卿,互相獨立揭芍,而類屬性有且只有一份。
定義類屬性可以直接在 class 中定義:
class Person(object):
address = 'Earth'
def init(self, name):
self.name = name
因為類屬性是直接綁定在類上的卸例,所以称杨,訪問類屬性不需要創(chuàng)建實例,就可以直接訪問:
print Person.address
=> Earth
p1 = Person('Bob')
print p1.address
=> Earth

類屬性和實例屬性名沖突:

當實例屬性和類屬性重名時筷转,實例屬性優(yōu)先級高姑原,它將屏蔽掉對類屬性的訪問。
千萬不要在實例上修改類屬性呜舒,它實際上并沒有修改類屬性锭汛,而是給實例綁定了一個實例屬性。

定義實例方法:

雖然私有屬性無法從外部訪問袭蝗,但是唤殴,從類的內(nèi)部是可以訪問的。除了可以定義實例的屬性外呻袭,還可以定義實例的方法眨八。
實例的方法就是在類中定義的函數(shù)

它的第一個參數(shù)永遠是 self,指向調用該方法的實例本身左电,其他參數(shù)和一個普通函數(shù)是完全一樣的.

定義類方法:
方法也分實例方法和類方法廉侧。
在class中定義的全部是實例方法,實例方法第一個參數(shù) self 是實例本身篓足。
在class中定義類方法:

class Person(object):
count = 0
@classmethod
def how_many(cls):
return cls.count
def init(self, name):
self.name = name
Person.count = Person.count + 1
print Person.how_many()
p1 = Person('Bob')
print Person.how_many()
通過標記一個 @classmethod段誊,該方法將綁定到 Person 類上,而非類的實例栈拖。類方法的第一個參數(shù)將傳入類本身连舍,通常將參數(shù)名命名為 cls,上面的 cls.count 實際上相當于 Person.count涩哟。
可以通過一個類方法獲取類的私有屬性索赏。

四盼玄、繼承

4.1繼承

1561620022645.png
1561620429253.png

判斷數(shù)據(jù)類型:
函數(shù)isinstance()可以判斷一個變量的類型,既可以用在Python內(nèi)置的數(shù)據(jù)類型如str潜腻、list埃儿、dict,也可以判斷類的對象的類型

isinstance(p, Person)
True
isinstance(p, Student)
False

PS:以上是2019-06-26到2019-06-07學習廖雪峰老師python進階課程記錄~

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末融涣,一起剝皮案震驚了整個濱河市童番,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌威鹿,老刑警劉巖剃斧,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異忽你,居然都是意外死亡幼东,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門科雳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筋粗,“玉大人,你說我怎么就攤上這事炸渡。” “怎么了丽已?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵蚌堵,是天一觀的道長。 經(jīng)常有香客問我沛婴,道長吼畏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任嘁灯,我火速辦了婚禮泻蚊,結果婚禮上,老公的妹妹穿的比我還像新娘丑婿。我一直安慰自己性雄,他們只是感情好,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布羹奉。 她就那樣靜靜地躺著秒旋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诀拭。 梳的紋絲不亂的頭發(fā)上迁筛,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音耕挨,去河邊找鬼细卧。 笑死尉桩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贪庙。 我是一名探鬼主播蜘犁,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼插勤!你這毒婦竟也來了沽瘦?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤农尖,失蹤者是張志新(化名)和其女友劉穎析恋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盛卡,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡助隧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了滑沧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片并村。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖滓技,靈堂內(nèi)的尸體忽然破棺而出哩牍,到底是詐尸還是另有隱情,我是刑警寧澤令漂,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布膝昆,位于F島的核電站,受9級特大地震影響叠必,放射性物質發(fā)生泄漏荚孵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一纬朝、第九天 我趴在偏房一處隱蔽的房頂上張望收叶。 院中可真熱鬧,春花似錦共苛、人聲如沸判没。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哆致。三九已至,卻和暖如春患膛,著一層夾襖步出監(jiān)牢的瞬間摊阀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留胞此,地道東北人臣咖。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像漱牵,于是被迫代替她去往敵國和親夺蛇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容