一粉洼、 Python進階學習
一节预、函數(shù)式編程
1.1函數(shù)式編程
1.2高階函數(shù)
1.2.1
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糠赦。
利用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ù)凡伊。
不用裝飾器:
使用裝飾器:
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: xy, 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':
三層嵌套:最外層要先返回一個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
二邻吭、模塊
模塊名沖突:
引用模塊:
包可以有多層:
但每一層必須 包含一個文件__init.py
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
三、面向對象
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繼承
判斷數(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進階課程記錄~