【Python】程式設計筆記5
文章目錄
- 函數語言程式設計(Functional Programming)
- 模組
函數語言程式設計(Functional Programming)
函數語言程式設計:思想更接近於數學計算,抽象程度很高的程式設計正規化,純粹的函數語言程式設計語言編寫的函式沒有變數。
特點:允許把函式本身作為引數傳入另一個函式,還允許返回一個函式。
Python 允許使用變數,因此,Python 不是純函數語言程式設計語言。
一、高階函式(Higher-order function)
函式本身也可以賦值給變數,即:變數可以指向函式。例如:函式名。
f = abs
print(f(-10))
輸出結果
10
高階函式:一個函式就可以接收另一個函式作為引數。(既然變數可以指向函式,函式的引數能接收變數)
def add(x, y, f):
return f(x) + f(y)
print(add(-5, 6, abs))
輸出結果
11
二、map/reduce
Python 中內建了 map() 和 reduce() 函式。
1、map() 函式
map()函式:接收兩個引數,一個是函式,一個是 Iterable。map 將傳入的函式依次作用到序列的每個元素,並把結果作為新的 Iterator 返回。
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))
## 把這個 list 所有數字轉為字串
print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
輸出結果
[1, 4, 9, 16, 25, 36, 49, 64, 81]
['1', '2', '3', '4', '5', '6', '7', '8', '9']
2、reduce() 函式
reduce()函式:把一個函式作用在一個序列 [x1, x2, x3, ...]
上,這個函式必須接收兩個引數, reduce 把結果繼續和序列的下一個元素做累積計算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
把序列[1, 3, 5, 7, 9]變換成整數 13579 的 reduce 實現:
from functools import reduce
def fn(x, y):
return x * 10 + y
print(reduce(fn, [1, 3, 5, 7, 9]))
輸出結果
13579
str 型別 ==》int 型別
from functools import reduce
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
return reduce(fn,map(char2num,s))
# 13579
print(str2int('13579'))
利用 lambda 函式進一步簡化:
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s):
return reduce(lambda x,y:10 * x + y, map(char2num, s))
str ==》float
def str2float(s):
def char2num(s):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
def fnMuti(x, y):
return 10 * x + y
def fnDivid(x, y):
return x / 10 + y
dotIndex = s.index('.')
return reduce(fnMuti, map(char2num, s[:dotIndex])) + reduce(fnDivid, list(map(char2num, s[dotIndex + 1:]))[::-1])/10
print('str2float(\'123.456\') =', str2float('123.456'))
輸出結果
str2float('123.456') = 123.456
三、filter
filter() 函式用於過濾序列。接收兩個引數:一個函式和一個序列,filter() 把傳入的函式依次作用於每個元素,然後根據返回值是 True ,則保留,為 False 則丟棄該元素。
def is_odd(n):
return n % 2 == 1
print(list(filter(is_odd, [1,2,4,5,6,9,10,15])))
# 結果: [1, 5, 9, 15]
==》filter() 函式返回結果是 Iterator,是一個惰性序列,需要使用 list() 函式獲取所有的結果並返回 list。
1、用 filter 求素數
實現方法:埃氏篩法。列出從 2 開始的所有自然數,構造一個序列:取序列第一個數並篩掉其的倍數,依次類推…
# 生成器,且是一個無限序列
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
# 過濾函式
def _not_divisible(n):
return lambda x : x % n > 0
# 用於不斷返回素數的生成器
def primes():
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it)
yield n
it = filter(_not_divisible(n), it) # 構造新的序列
# 設定一個退出迴圈的條件
for n in primes():
if n < 1000:
print(n)
else:
break
四、sorted
通常規定,對於兩個元素 x 和 y,如果認為 x < y,則返回-1,如果認為 x == y,則返回 0,如果認為 x > y,則返回 1
1、數字
## 原始
print(sorted([36, 5, -12, 9, -21]))
## sorted()函式也是一個高階函式,它還可以接收一個 key 函式來實現自定義的排序。
## key 指定的函式將作用於 list 的每一個元素上,並根據 key 函式返回的結果進行排序。
print(sorted([36, 5, -12, 9, -21], key=abs))
輸出結果
[-21, -12, 5, 9, 36]
[5, 9, -12, -21, 36]
2、字串
## 預設情況下,對字串排序,是按照 ASCII 的大小比較的
print(sorted(['bob', 'about', 'Zoo', 'Credit']))
## 可實現忽略大小寫的排序
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower))
## reverse 為 true 表示反向排序
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower, reverse = True))
輸出結果
['Credit', 'Zoo', 'about', 'bob']
['about', 'bob', 'Credit', 'Zoo']
['Zoo', 'Credit', 'bob', 'about']
五、返回函式
1、函式作為返回值
例如:返回求和的函式
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f1 = lazy_sum(1,3,5,7,9)
f1
f1() # 函式需要呼叫才能執行
# 呼叫 lazy_sum()時,每次呼叫都會返回一個新的函式,即使傳入相同的引數
f2 = lazy_sum(1,3,5,7,9)
f1 == f2
輸出結果
<function __main__.sum>
25
False
分析:在函式 lazy_sum 中又定義了函式 sum,並且,內部函式 sum 可以引用外部函式 lazy_sum 的引數和區域性變數,當 lazy_sum 返回函式 sum 時,相關引數和變數都儲存在返回的函式中,這種稱為“閉包( Closure) ”的程式結構擁有極大的威力。
2、閉包
返回函式不要引用任何迴圈變數, 或者後續會發生變化的變數。
3、匿名函式
4、裝飾器
裝飾器”( Decorator):在程式碼執行期間動態增加功能的方式。
5、偏函式
模組
模組:Python中一個.py檔案就是一個模組(Module)
==》提高了程式碼的可維護性;複用性;避免函式名和變數名衝突。
包(Package):按目錄來組織模組的方法。例如:a.py(a模組) 與 b.py(b模組)與其他模組衝突,則選擇一個頂層包名,例如mycompany,則 a 模組變成 mycompany.a、b模組變成 mycompany.b
==》每一個包目錄下面都會有一個__init__.py 的檔案,這個檔案是必須存在的,用於標識包。
1、使用模組
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
'a test module' ## 表示模組的文件註釋,任何模組程式碼的第一個字串都被視為模組的文件註釋
__author__ = '盛夏光年'
import sys
def test():
args = sys.argv
if len(args)==1:
print("Hello world!")
elif len(args) == 2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__ == '__main__':
test()
2、作用域
- 正常的函式和變數名是公開的( public),可以被直接引用,比如: abc,x123, PI 等;
- 類似__xxx__這樣的變數是特殊變數,可以被直接引用,但是有特殊用途;
- 類似_xxx 和__xxx 這樣的函式或變數就是非公開的( private),不應該被直接引用,比如_abc, __abc 等;
注意: Python 並沒有一種方法可以完全限制訪問 private 函式或變數
3、第三方庫
eg: Pillow、numpy、Jinja2
檢視搜尋目錄:
import sys
print(sys.path)
新增搜尋目錄——方法1:
import sys
sys.path.append('/Users/michael/my_py_scripts')
==》這種方法是在執行時修改,執行結束後失效。
新增搜尋目錄——方法2:
設定環境變數 PYTHONPATH