函數就是用來盛放代碼的容器python
具有某一功能的工具-->工具mysql
實現準備好工具的過程-->函數的定義sql
遇到應用場景,拿來就用shell
使用函數能夠解決代碼可讀性差以及拓展性差的問題express
先定義後引用編程
def 函數名(參數1,參數2,...): """文檔描述""" 函數體 return 值 # def: 定義函數的關鍵字; # 函數名:函數名指向函數內存地址,是對函數體代碼的引用。函數的命名應該反映出函數的功能; # 括號:括號內定義參數,參數是無關緊要的,且無需指定參數的類型; # 冒號:括號後要加冒號,而後在下一行開始縮進編寫函數體的代碼; # """文檔描述""": 描述函數功能,參數介紹等信息的文檔,非必要,可是建議加上,從而加強函數的可讀性; # 函數體:由語句和表達式組成; # return 值:定義函數的返回值,return是無關緊要的。
def say_hello(): # say_hello=函數的內存地址 print("======") print("hello world") print("======") print(say_hello) # <function say_hello at 0x00000241DA0273A0> say_hello() x = 10 # x=10的內存地址 print(x)
# 函數定義階段:只檢測語法,不執行代碼 def foo(): xxx print('from foo') # 函數調用階段:執行函數體代碼 foo()
示例1 def bar(): print('from bar') def foo(): print('from foo') bar() foo() # from foo | from bar 示例二 def bar(): print('from bar') foo() def foo(): print('from foo') bar() # from bar | from foo 示例三 def bar(): print('from bar') foo() bar() # 報錯,要先定義後引用 def foo(): print('from foo')
定義函數的三種形式閉包
# 無參函數 def f1(): print("hello") print("你好") print("Hi") f1() # hello | 你好 | Hi def login(): name = input('username>>>:').strip() pwd = input('password>>>:').strip() if name == "ccc" and pwd == '111': print('ok') else: print('error') login() # username>>>:
def login(name,pwd): if name == "ccc" and pwd == "123": print('ok') else: print('error') login("ccc","123") # ok login("ccc","1234") # error def f2(x, y): print(x) print(y) f2(111, 222) # 111 | 222 def add(x, y): print(x+y) add(10, 20) # 30 add(30, 40) # 70
def login(): pass def transfer(): pass def withdraw(): pass def check_balance(): pass
len("hello")
res = len("hello") + 10 print(res) # 15
def add(x, y): z = x + y return z print(add(5, 5)) # 10 res = add(add(1, 2), 3) print(res) # 6
Ⅰ 沒有return-->默認返回就是None def func(): print(111) res = func() # 111 print(res) # None Ⅱ return 值-->返回就是那一個值 def max2(x, y): if x > y: return x else: return y res = max2(100, 200) * 5 print(res) # 1000 Ⅲ return 值1,值2,值3--->返回的是一個元組 def func(): return [11, 22], 2, 3 res = func() print(res, type(res)) # ([11, 22], 2, 3) <class 'tuple'>
def func(): print(111) return 2201202 print(2222) return 11112222 print(3333) res = func() print(res) # 111 2201202
return就是函數的處理結果app
函數內沒有return關鍵字,或者說return後面沒有值-->None編程語言
return 值
return 值1,值2,值3--->(值1,值2,值3)函數式編程
能夠有多個return,但只要執行一次整個函數就會當即結束,而且返回值
def f1(): x = 10 def f2(): print('from f2') return f2 res = f1() # 即res=f2的內存地址 print(res) # <function f1.<locals>.f2 at 0x000001F5886D8700> res() # from f2
python3新增類型提示功能,例如咱們能夠爲函數增長類型提示信息,而不影響函數自己的執行:
註釋的通常規則是參數名後跟一個冒號(:),而後再跟一個expression,這個expression能夠是任何形式。
# Type hinting def add(x: int, y: int) -> int: res = x + y return res print(add.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
形參
在定義函數時,在括號內指定參數/變量名,稱之爲形式參數,簡稱形參
形參的本質就是變量名
實參
在調用函數時,括號內傳入的值,稱之爲實際參數,簡稱實參
實參的本質就是變量值
實參與形參的關係
在調用函數時,實參的值會綁定給形參,該綁定關係能夠在函數內使用
在函數調用結束後,會解除綁定關係
在定義函數時,按照從左往右的順序依次定義的變量名,稱之爲位置形參
特色:必須被傳值,多一個少一個都不行
def func(x, y): print(x, y) func(1, 2) func(1, 2, 3) # 報錯 func(1) # 報錯
在調用函數時,按照從左往右的順序依次傳入的值,稱之爲位置實參
特色:按照位置與形參一一對應
def func(x, y): print(x, y) func(1, 2) func(2, 1)
在定義函數時就已經爲某個形參賦值了,該形參就稱爲默認參數
特色:在調用階段能夠不用爲默認形參傳值
def func(x, y=111): print(x, y) func(1, 2) # 1 2 func(1) # 1 111
def register(name, age, gender="male"): print(name, age, gender) register("egon", 18) register("lxx", 38) register("hxx", 32, "female") register("李建國", 30) register("alex", 31) register("xxx", 18) # egon 18 male # lxx 38 male # hxx 32 female # 李建國 30 male # alex 31 male # xxx 18 male
在調用函數時,按照key=value的形式指定的實參,稱之爲關鍵字實參
特色:能夠打亂順序,仍能指名道姓爲指定的形參賦值
def func(x, y=2222): print(x, y) func(y=222, x=1212) # 1212 222 func(x=111) # 111 2222
位置實參和關鍵字實參能夠混用,注意點:
Ⅰ 位置實參必須放在關鍵字實參前面
Ⅱ 不能爲同一個形參重複賦值
def func(x, y=2222): print(x, y) func(1, y=2) # 1 2 func(y=2, 1) # 報錯 func(1, y=2, x=3) # 報錯
位置形參和默認形參能夠混用,注意點:
位置形參必須放在默認形參前面
def func(x, y=111): print(x, y) def func(y=111, x): # 報錯 print(x, y)
m = 222 def func(x, y=m): print(x, y) m = 666 func(111) # 獲得111 222
def register(name,hobby,hobbies=[]): hobbies.append(hobby) print('%s 的愛好是 %s' %(name, hobbies)) def register(name, hobby, hobbies=None): if hobbies is None: hobbies=[] hobbies.append(hobby) print('%s 的愛好是 %s' %(name, hobbies)) register("egon", "smoke") register("lxx", "dance") register("hxx", "drink")
可變長函數是指在調用函數時,傳入參數個數不固定,而實參是爲形參賦值的
所以必須有對應格式的形參來接受溢出的實參
def func(x, y, *z): print(x, y, z) func(1, 2, 3, 4, 5) # 1 2 (3, 4, 5) func(1, 2) # 1 2 () func(1) # 報錯 def my_sum(*args): res = 0 for i in args: res += i print(res) my_sum(1) # 1 my_sum(1, 2) # 3 my_sum(1, 2, 3) # 6
def func(x, y, **kwargs): print(x, y, kwargs) func(1, y=2, a=1, b=2, c=3) # 1 2 {'a': 1, 'b': 2, 'c': 3}
def func(a, b, c, d): print(a, b, c, d) func(*"hello") # 報錯,不對應 func(*"hell") # h e l l func(*[11, 22, 33, 44]) # 11 22 33 44 func(11, 22, *[33, 44]) # 11 22 33 44 func(11, 22, *{"k1": 111, "k2": 222}) # 11 22 k1 k2
在實參中帶**😗*會將緊跟其後的實參打散成關鍵字實參
注意**後面跟的必須是一個字典
def func(a, b, c, d): print(a, b, c, d) func(**{"k1": 333, "k2": 444}) # 報錯 func(**{"d": 333, "b": 444, "a": 111, "c": 222}) # 111 444 222 333 func(**[("d", 333), ("b", 444), ("a", 111), ("c", 222)]) # 報錯
在形參中,*必須在**前
在實參中,*必須在**前
def index(x, y, z): print('index------>', x, y, z) def wrapper(*arges, **kwargs): index(*arges, **kwargs) # wrapper(1, 2, 3, 4, a=1, b=2, c=3) # 不能一一對應 報錯 wrapper(1, 2, 3) # index------> 1 2 3 wrapper(z=3, y=2, x=1) # index------> 1 2 3 def wrapper(*arges,**kwargs): print(arges) print(kwargs) wrapper(1, 2, a=1,b=2,c=3) # (1, 2) {'a': 1, 'b': 2, 'c': 3}
在*與**之間定義的形參稱爲關鍵字形參
特色:必須按照key=value的形式傳值
def func(x, y=1, *args, a=666, b, **kwargs): print(x) print(y) print(args) print(a) print(b) print(kwargs) func(1, 2, 3, 4, 5, 6, 7, a=111, b=222, c=333) # 1 2 (3, 4, 5, 6, 7) 111 222 {'c': 333} func(1, 2, 3, 4, 5, 6, 7, b=222, c=333) # 1 2 (3, 4, 5, 6, 7) 666 222 {'c': 333} func(1, 2, 3, 4, 5, 6, 7, b=222, 333) # 報錯
def func(): print('from func')
def func(): print('from func') f = func f() # from func
def func(): print('from func') def bar(x): print(x) mmm = 11111 bar(mmm) # 11111 bar(func) # <function func at 0x000002D4F29B63A0>
def add(x): # x=函數func的內存地址 return x # return 函數func的內存地址 res = add(func) # res=add(func的內存地址) print(res) # <function func at 0x000002D4F29B63A0>
x = 10 l = [x, func] print(l) # [10, <function func at 0x000002C48C4463A0>] l[-1]() # from func
# 新的功能只須要在字典中加入便可,無需動循環 def login(): print('login') def register(): print('register') def transfer(): print('transfer') def withdraw(): print('withdraw') func_dic = { "1": [login, "登陸"], "2": [register, "註冊"], "3": [transfer, "轉帳"], "4": [withdraw, "提現"] } while True: print("0 退出") for k in func_dic: print(k, func_dic[k][-1]) choice = input("請輸入操做編號:").strip() if choice == "0": break if choice in func_dic: func_dic[choice][0]() else: print("輸入的操做不存在")
def f1(): print('from f1') def f2(): print('from f2') print(f2) f2() x=1111 f1() # from f1 # <function f1.<locals>.f2 at 0x00000274E0EB8700> # from f2
from math import pi def circle(radius, mode=0): def perimiter(radius): return 2 * pi *radius def area(radius): return pi * (radius ** 2) if mode == 0: return perimiter(radius) elif mode == 1: return area(radius) res1 = circle(10, mode=0) print(res1) # 62.83185307179586 res2 = circle(10, mode=1) print(res2) # 314.1592653589793
def max2(x, y): if x > y: return x else: return y def max4(a, b, c, d): res1 = max2(a, b) res2 = max2(res1, c) res3 = max2(res2, d) return res3 res = max4(1, 2, 3, 4) print(res) # 4
名稱空間namespace
名稱空間就是存放名字的地方
三類名稱空間(內置名稱空間、全局名稱空間、局部名稱空間)
Ⅰ 內置名稱空間:存放內置的名字
隨着解釋器啓動就產生,解釋器關閉就銷燬
input
len
Ⅱ 全局名稱空間:存放的是頂級的名字
運行頂級代碼前產生,文件運行完畢則銷燬
Ⅲ 局部名稱空間:在函數內定義的名字
調用函數則產生一個函數的局部名稱空間,該函數調用結束則當即銷燬
名稱空間示例 x = 10 # 全局名稱空間 def f1(): # f1自己是全局名稱空間 y = 2 # 局部名稱空間 if 1 > 0: z = 3 # 全局名稱空間 if 3 > 1: m = 333 # 全局名稱空間
局部名稱空間-->全局名稱空間-->內置名稱空間
Tips:在全局沒法查看局部的,在局部能夠看全局的
優先級示例 x = 111 def f1(): print(x) x = 222 f1() # 報錯 x = 111 def f1(): x = 222 print(x) f1() # 222
名稱空間的嵌套關係是在函數定義階段,即檢測語法時肯定的
與調用函數的位置無關,與函數定義位置有關
global 局部對全局變量修改
x = 111 def f1(): global x x = 222 f1() print(x) # 222
x = 111 def f1(): x = 222 def f2(): nonlocal x x = 333 f2() print(x) f1() # 333
做用域即範圍
全局範圍(內置、全局名稱空間屬該範圍):全局存活,全局有效
局部範圍(局部名稱空間屬該範圍):臨時存活,局部有效
做用域關係是在函數定義階段固定的,與函數調用位置無關
查看做用域
LEGB表明名字查找順序:locals -> enclosing function -> globals -> _builtings_
locals 是函數內的名字空間,包括局部變量和形參
enclosing 外部嵌套函數的名字空間(閉包中常見)
globals 全局變量,函數定義所在模塊的名字空間
builtings 內置模塊的名字空間
閉函數
該函數就是定義在一個函數內部的函數
def outter(): def wrapper(): pass
包函數
閉函數引用了一個來源於外層函數的變量
def outter(): x = 111 def wrapper(): print(x) wrapper() x = 222 # 不妨礙 outter() # 111
意義:
返回的函數對象外部還包了一層做用域
該函數不管在何處調用都優先使用本身外層包裹的做用域
應用:
延遲計算
from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu=index('http://www.baidu.com') print(baidu().decode('utf-8'))
什麼是裝飾器
器---->工具
裝飾-->添加新功能
裝飾器就是定義個函數,用該函數去爲其餘函數添加新功能
爲何用裝飾器
開放封閉原則:針對上線的功能對拓展是開放的,可是對修改源代碼以及調用方式是封閉的
需求:爲index加上新功能-->統計其運算時間
import time
def index():
time.sleep(1)
print('from index')
index()
# 一、首先考慮直接在運行的代碼體上下方加入時間模塊 import time def index(): start = time.time() time.sleep(1) print('from index') stop = time.time() print('run time is %s' % (stop - start)) index() # 可是這樣改修改了源代碼
# 二、不修改源代碼 import time def index(): time.sleep(1) print('from index') start = time.time() index() stop = time.time() print('run time is %s' % (stop - start)) # 這樣修改每次調用函數都要輸重複代碼,不方便
# 三、把調用放進函數 import time def index(): time.sleep(1) print('from index') def wrapper(): start = time.time() index() stop = time.time() print('run time is %s' % (stop - start)) wrapper() # 調用方便,可是改變了調用方式
# 3.1改進一 import time def index(): time.sleep(1) print('from index') def wrapper(f): start = time.time() f() stop = time.time() print('run time is %s' % (stop -start)) wrapper(index)
# 3.2改進二 import time def index(): time.sleep(1) print('from index') def outter(f): def wrapper(): start = time.time() f() stop = time.time() print('run time is %s' % (stop - start)) return wrapper index = outter(index) index()
# 添加新功能home import time def index(): time.sleep(1) print('from index') def home(name): time.sleep(1) print('homepage welcome %s' % name) def outter(f): def wrapper(*args, **kwargs): start = time.time() f(*args, **kwargs) stop = time.time() print('run time is %s' % (stop - start)) return wrapper index = outter(index) index() home = outter(home) home('ccc')
# 最終版 import time def index(): time.sleep(1) print('from index') def home(name): time.sleep(1) print('homepage welcome %s' % name) return 123 def outter(f): def wrapper(*args, **kwargs): start = time.time() res = f(*args, **kwargs) stop = time.time() print('run time is %s' % (stop - start)) return res return wrapper index = outter(index) home = outter(home) res = index() print(res) # None res = home('ccc') print(res) # 123
在被裝飾對象的正上方單獨一行添加@timer,當解釋器解釋到@timer時就會調用timer函數,且把它正下方的函數名當作實參傳入,而後將返回的結果從新賦值給原函數名
原函數
import time def index(): time.sleep(1) print('from index') def home(name): time.sleep(1) print('homepage welcome %s' % name) return 123 def outter(f): def wrapper(*args, **kwargs): start = time.time() res = f(*args, **kwargs) stop = time.time() print('run time is %s' % (stop - start)) return res return wrapper index = outter(index) home = outter(home) res = index() print(res) # None res = home('ccc') print(res) # 123
import time def timmer(f): def wrapper(*args, **kwargs): start = time.time() res = f(*args, **kwargs) stop = time.time() print('run time is %s' % (stop - start)) return res return wrapper @timmer # index = timmer(index) def index(): time.sleep(1) print('from index') @timmer # home = time(home) def home(name): time.sleep(2) print('welcome to %s' % name) return 123 index() res = home("ccc") print(res) # from index # run time is 1.0003390312194824 # welcome to ccc # run time is 2.0008108615875244 # 123
def auth(driver): def func(x): ... return func @auth(driver='file') def index(): pass @auth(driver='mysql') def home(): pass
import time def login(x, engine='file'): def auth(func): def wrapper(*args, **kwargs): print("========>", x) inp_user = input("username>>>>:").strip() inp_pwd = input("password>>>:").strip() if engine == "file": print("基於file認證") if inp_user == "egon" and inp_pwd == "123": print('login successful') res = func(*args, **kwargs) return res else: print('username or password error') elif engine == 'mysql': print("基於mysql認證") elif engine == "ldap": print("基於ldap認證") else: print("未知認證來源") return wrapper return auth @login(11, engine='file') # @auth # index = auth(index) # index=wrapper def index(): time.sleep(1) print('from index') @login(22, engine='file') # @auth # home=auth(home) # home=wrapper def home(name): time.sleep(2) print('home page,welcome %s' % name) return 123 index() home('egon') # ========> 11 # username>>>>:egon # password>>>:123 # 基於file認證 # login successful # from index # ========> 22 # username>>>>:egon3 # password>>>:123 # 基於file認證 # login successful # home page,welcome egon
加載順序(outter函數的調用順序):自下而上
執行順序(wrapper函數的執行順序):自上而下
@deco1
@deco2
@deco3
def foo():
pass
至關於
foo=deco1(deco2(deco3(foo)))
def outter1(func1): # func1 = wrapper2的內存地址 print('============>outter1') def wrapper1(*args, **kwargs): print('=============wrapper1') res1 = func1(*args, **kwargs) return res1 return wrapper1 def outter2(func2): # func2 = wrapper3的內存地址 print('============>outter2') def wrapper2(*args, **kwargs): print('=============wrapper2') res2 = func2(*args, **kwargs) return res2 return wrapper2 def outter3(func3): # func3 = index的內存地址 print('============>outter3') def wrapper3(*args, **kwargs): print('=============wrapper3') res3 = func3(*args, **kwargs) return res3 return wrapper3 # index = wrapper1的內存地址 @outter1 # outter1(wrapper2的內存地址)-->wrapper1的內存地址 @outter2 # outter2(wrapper3的內存地址)-->wrapper2的內存地址 @outter3 # outter3(index的內存地址)-->wrapper3的內存地址 def index(): print('from index') print('*'*25) # print(index) index() # ============>outter3 # ============>outter2 # ============>outter1 # ************************* # =============wrapper1 # =============wrapper2 # =============wrapper3 # from index
import time def timmer(func): def wrapper1(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print('run time is:%s' % (stop - start)) return res return wrapper1 def login(x, engine='file'): def auth(func): def wrapper2(*args, **kwargs): print("========>", x) inp_user = input("username>>>>:").strip() inp_pwd = input("password>>>:").strip() if engine == "file": print("基於file認證") if inp_user == "egon" and inp_pwd == "123": print('login successful') res = func(*args, **kwargs) return res else: print('username or password error') elif engine == 'mysql': print("基於mysql認證") elif engine == "ldap": print("基於ldap認證") else: print("未知認證來源") return wrapper2 return auth # 場景一 @timmer @login(11, engine='file') def index(): time.sleep(1) print('from index') index() # ========> 11 # username>>>>:egon # password>>>:123 # 基於file認證 # login successful # from index # run time is:9.147817134857178 # 場景二 @login(11, engine='file') @timmer def index(): time.sleep(1) print('from index') index() # ========> 11 # username>>>>:egon # password>>>:123 # 基於file認證 # login successful # from index # run time is:1.0001623630523682
import time from functools import wraps def timmer(func): @wraps(func) def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print('run time is:%s' % (stop - start)) return res return wrapper @ timmer def index(): """index函數""" time.sleep(1) print('from index') help(index)
def func(x, y): # func=函數的內存地址 return x+y 匿名函數:沒有名字的函數 應用場景:臨時用一次,一般用於與其餘函數配合使用
# 無用調用方式 f = lambda x, y: x+y print(f) res = f(1, 2) print(res) # 調用方式1 res = (lambda x, y: x+y)(1, 2) print(res) # 調用方式2 salaries = { "egon": 1000, "alex": 2000, "jack": 3000, "rose": 4000 } # 求薪資最高的那我的的名字 def get_salary(name): return salaries[name] print(max(salaries, key = get_salary)) # rose print(max(salaries, key=lambda name: salaries[name])) # rose print(min(salaries, key=lambda name: salaries[name])) # egon print(sorted(salaries)) # ['alex', 'egon', 'jack', 'rose'] print(sorted(salaries, key=lambda name: salaries[name])) # ['egon', 'alex', 'jack', 'rose'] print(sorted(salaries, key=lambda name: salaries[name], reverse=True)) # ['rose', 'jack', 'alex', 'egon']
# abs 返回絕對值 print(abs(-11)) # 11 print(abs(0)) # 0 print(abs(11)) # 11 # all 若是是空或布爾值爲真則返回True print(all('')) # True print(all([])) # True print(all([11, 22, 333, 0])) # False # any 只要有一個值的布爾值爲真就返回True print(any('')) # False print(any([])) # False print(any([0, None, '', 1])) # True print(any([0, None, ''])) # False # chr 對比ASCⅡ表:65-90 A-Z print(chr(65)) # 數字->字母A print(ord('A')) # 字母->數字65 print(chr(90)) # Z # bin/oct/hex 進制轉換 print(bin(11)) # 十進制->二進制 0b1011 print(oct(11)) # 十進制->八進制 0o13 print(hex(11)) # 十進制->十六進制 0xb # 工廠函數 int float str list tuple dict set bool bytes # callable查看對象是否可調用 print(callable(len)) # True # 面向對象重點 classmethod staticmethod setattr getattr delattr hasattr dir exec # eval 讀取內容代碼時執行 l = eval("[1, 2, 3]") print(l[0]) # 1 with open('user1.txt', mode='wt', encoding='utf-8') as f: dic = {"ccc": "123", "zzz": "456", "yyy": "789"} f.write(str(dic)) with open('user1.txt', mode='rt', encoding='utf-8') as f: data = f.read() print(data, type(data)) # {'ccc': '123', 'zzz': '456', 'yyy': '789'} <class 'str'> dic = eval(data) print(dic["ccc"]) # 123
# 一、map 映射 names = ["egon", "lxx", "hxx"] res = (name if name == "egon" else name+"_sb" for name in names) print(list(res)) # ['egon', 'lxx_sb', 'hxx_sb'] 用map實現 names = ["egon", "lxx", "hxx"] res = map(lambda name:name if name == "egon" else name+"_sb", names) print(res) # <map object at 0x0000020E897D5B50> print(list(res)) # ['egon', 'lxx_sb', 'hxx_sb'] # 二、filter 過濾 names = ['egon', 'lxx_sb', 'hxx_sb'] res = (name for name in names if name.endswith("sb")) print(list(res)) # ['lxx_sb', 'hxx_sb'] 用filter實現 names = ['egon', 'lxx_sb', 'hxx_sb'] res = filter(lambda name:name.endswith("sb"), names) print(list(res)) # ['lxx_sb', 'hxx_sb'] # 三、reduce from functools import reduce res = reduce(lambda x,y:x+y, "hello", "xxx") print(res) # xxxhello from functools import reduce res = reduce(lambda x,y:x+y, [1, 2, 3], 100) print(res) # 106 # 四、set可變集合/frozenset不可變集合 s = frozenset({1, 2, 3}) # 不可變 s1 = set({1, 2, 3}) # 可變 s1.add(4) print(s1) # {1, 2, 3, 4} # 五、locals局部變量/globals全局變量 x = 3333 def func(): x = 1 y = 2 print(locals()) print(globals()) func() # {'x': 1, 'y': 2} # {'__name__': '__main__', ...} a = 1111 print(locals()) # {'__name__': '__main__', ...} print(globals()) # {'__name__': '__main__', ...} print(locals() is globals()) # True # 六、hash返回散列值 print(hash("asaasdf")) # -9196404338305892359 # 七、pow(base ** exp % mod) res = pow(10, 3, 3) # 10 ** 3 % 3 print(res) # 1 # 八、reversed 反序 res = reversed([11, 333, 222, 77]) print(list(res)) # [77, 222, 333, 11]沒有排序,直接反序 # 九、round 四捨五入 print(round(3.5)) # 4 # 十、slice 切片 l = [11, 22, 33, 44, 55, 66, 77, 88, 99] res = l[0: 7: 2] print(res) # [11, 33, 55, 77] 用slice實現 l = [11, 22, 33, 44, 55, 66, 77, 88, 99] s = slice(0, 7, 2) res = l[s] print(res) # [11, 33, 55, 77] # 十一、zip 拉鍊 s1 = "hello" l = [11, 22, 33, 44, 55, 66] res1 = zip(s1, l) print(list(res1)) # [('h', 11), ('e', 22), ('l', 33), ('l', 44), ('o', 55)] res2 = zip(l, s1) print(list(res2)) # [(11, 'h'), (22, 'e'), (33, 'l'), (44, 'l'), (55, 'o')] zip多的元素會直接丟掉
迭代器指的是迭代取值的工具
迭代是一個重複的過程(不是單純重複),每次重複都是基於上一次的結果進行的
count = 1
while count < 5:
print(count)
count += 1
使用迭代器的目的
Ⅰ 爲了找到一種通用的迭代取值的方案
Ⅱ 節省內存
可迭代對象
內置有__iter__方法的類型都稱之爲可迭代對象
但凡調用了__iter__方法,就會將該類型轉換成迭代對象
res = 值.__iter__() 或 res = iter(值)
迭代器對象
Ⅰ 內置有__next__方法
Ⅱ 內置有__iter__方法(爲了方便for循環)
迭代器對象必定是可迭代對象
可迭代對象不必定是迭代器對象
優勢:
Ⅰ 提供了一種不依賴索引的迭代取值方案
Ⅱ 惰性計算,節省內存
缺點:
Ⅰ 取值麻煩
Ⅱ 沒法預測值的長度
Ⅲ 是一次性的
"hello".__iter__() # 字符串 [].__iter__() # 列表 (11,).__iter__() # 元組 {"k1": 12, }.__iter__() # 字典 {11, 22}.__iter__() # 集合 f = open("a.txt", mode="wt") # 文件 f.__iter__()
l = [11, 22, 33] iter_l = l.__iter__() print(iter_l.__next__()) # 11 print(iter_l.__next__()) # 22 print(iter_l.__next__()) # 33 info = {'name': "ccc", "age": 18, "gender": 'male'} iter_info = info.__iter__() print(iter_info.__next__()) # name print(iter_info.__next__()) # age print(iter_info.__next__()) # gender print(iter_info.__next__()) # 拋出異常StopIteration
迭代器的iter與自己 print(iter_info.__iter__().__iter__().__iter__() is iter_info) # True
l = [11, 222, 333, 444, 555] iter_l = iter(l) # l.__iter__ while True: try: print(next(iter_l)) except StopIteration: break # 11 # 222 # 333 # 444 # 555 l = {'name': "ccc", "age": 18, "gender": 'male'} iter_l = iter(l) while True: try: print(next(iter_l)) except StopIteration: break print('--------------------') while True: try: print(next(iter_l)) except StopIteration: break # name # age # gender # -------------------- l = {'name': "ccc", "age": 18, "gender": 'male'} iter_l = iter(l) while True: try: print(next(iter_l)) except StopIteration: break print('--------------------') iter_l = iter(l) while True: try: print(next(iter_l)) except StopIteration: break # name # age # gender # -------------------- # name # age # gender l = [11, 222, 333, 444, 555] iter_l = iter(l) for item in iter_l: print(item) print('====================') for item in iter_l: print(item) # 11 # 222 # 333 # 444 # 555 # ==================== l = [11, 222, 333, 444, 555] iter_l = iter(l) for item in iter_l: print(item) print('====================') iter_l = iter(l) for item in iter_l: print(item) # 11 # 222 # 333 # 444 # 555 # ==================== # 11 # 222 # 333 # 444 # 555
for循環原理: 一、調用可迭代對象.__iter__(),拿到一個迭代器對象 二、調用next(迭代對象),將返回值賦值變量item 三、循環往復,直到拋出異常Stopiteration,for會檢測異常而後結束循環 f = open('a.txt', mode='rt', encoding='utf-8') for line in f: print(line) print('=======') for line in f: print(line) f.close() # 111 # # 222 # # 333 # # 444 # =======
生成器:生成器就是一種自定義迭代器(生成器內置iter和next方法)
使用生成器是爲了省內存
使用生成器的方式:
函數體內但凡出現yield關鍵字,調用函數不會觸發函數體代碼的運行,而是會返回一個生成器對象
yield與return
相同點:在返回值角度的用法一致
不一樣點:Ⅰ yield能夠返回屢次值,return只能返回一次
Ⅱ yield能夠暫停函數,而後能夠用next方法觸發函數體代碼的運行->協程(或用list)
def func(): print("111") yield 1 print("222") yield 2 print("333") yield 3 print("444") g = func() # 生成器本質就是一個迭代器 print(g) # <generator object func at 0x0000024D38B57900> res = next(g) # 111 print(res) # 1 res = next(g) # 222 print(res) # 2 res = next(g) # 333 print(res) # 3 next(g) # 444 檢測異常StopIteration
g = func() print(g) for i in g: print(i) # <generator object func at 0x0000020C4D217900> # 111 # 1 # 222 # 2 # 333 # 3 # 444
def my_range(start, stop, step=1): while start < stop: yield start start += step for i in my_range(0, 5, 2): print(i) # 0 # 2 # 4
res = "條件成立時返回的值" if "條件" else "條件不成立時返回的值"
def max2(x, y): if x > y: return x else: return y res = max2(1, 2)
# 可用三元表達式一行解決 x = 1 y = 2 res = x if x > y else y
[表達式 for i in 可迭代對象 if 條件] {k:v for i in 可迭代對象 if 條件} {k for i in 可迭代對象 if 條件}
l = [] for i in range(8): l.append(i) print(l) # [0, 1, 2, 3, 4, 5, 6, 7] # 可用列表生成式一行解決 l = [i for i in range(10)] print(l) # [0, 1, 2, 3, 4, 5, 6, 7]
names = ["egon", "lxx_sb", "hxx_sb"] name = [] for item in names: if item.endswith('sb'): name.append(item) print(name) # ['lxx_sb', 'hxx_sb'] # 可用列表生成式一行解決 names = ["egon", "lxx_sb", "hxx_sb"] name = [name for name in names if name.endswith('sb')] print(name) # ['lxx_sb', 'hxx_sb']
res = {i: i for i in range(5) if i > 2} print(res) # {3: 3, 4: 4}
res = {i for i in range(5) if i > 2} print(res, type(res)) # {3, 4} <class 'set'>
調用帶yield的函數
生成器表達式,將列表生成式的[]換成()便可
(expression for item in iterable if condition)
列表生成式返回的是一個列表,生成器表達式返回的是一個生成器對象
生成器表達式更加節省內存(一次只產生一個值在內存中)
若是要讀取一個大文件的字節數應該是基於生成器表達式的方式完成的
res = (i for i in range(5)) print(res) # <generator object <genexpr> at 0x00000274941E7900> print(next(res)) # 0 print(next(res)) # 1 print(next(res)) # 2 print(next(res)) # 3 print(next(res)) # 4 print(next(res)) # 拋出異常StopIteration
with open(r'a.txt', mode='rt', encoding='utf-8') as f: res = 0 for line in f: res += len(line) print(res) # 15 # 生成式表達式 with open(r'a.txt', mode='rt',encoding='uyf-8') as f: res = sum(len(line) for line in f) print(res) # 15 依次執行next(res),而後累加到一塊兒獲得結果
111 222 333 444
核心是過程
二字
過程指的是解決問題的步驟,即先幹什麼後幹什麼再幹什麼
基於面向過程開發程序比如是在設計一條條流水線,是一種機械式的思惟方式,正好契合計算機的運行原理
計算機運行原理:任何程序的執行最終都要轉換成cpu的指令流水按過程調度執行
即不管採用什麼語言、何種編程範式設計出的程序,最終的執行都是過程式的
優勢:將複雜的問題流程化,進而簡單化
缺點:程序的可擴展性差
面向過程的程序設計通常用於那些功能一旦實現以後就不多須要改變的場景, 若是你只是寫一些簡單的腳本,去作一些一次性任務,用面向過程去實現是極好的, 但若是你要處理的任務是複雜的,且須要不斷迭代和維護,那仍是用面向對象最爲方便。
函數遞歸調用:在調用一個函數的過程當中又調用了本身
本質:循環的過程-->用函數來實現的循環
遞歸調用必須在知足某種條件下結束,不能無限遞歸調用下去
python不是函數式編程語言,沒法對遞歸進行尾遞歸優化
遞歸的兩個階段:
Ⅰ 回溯-->一層層往下爬
Ⅱ 遞推-->一層層往上爬
def f1(): print("from f1") f1() f1() # 先遞歸執行,超過最大限制後報錯RecursionError
# 可用getrecursionlimit修改限制 import sys print(sys.getrecursionlimit()) # 默認限制是1000 sys.setrecursionlimit(2000) # 可修改,但通常不修改(受主機操做系統棧大小限制) print(sys.getrecursionlimit(2000)) # 此時修改成2000
# 問題 某公司四個員工坐在一塊兒,問第四我的薪水,他說比第三我的多1000,問第三我的薪水,第他說比第二我的多1000,問第二我的薪水,他說比第一我的多1000,最後第一人說本身每個月5000,請問第四我的的薪水是多少? # 思路解析 要知道第四我的的月薪,就必須知道第三我的的,第三我的的又取決於第二我的的,第二我的的又取決於第一我的的,並且每個員工都比前一個多一千,數學表達式即 salary(4)=salary(3)+1000 salary(3)=salary(2)+1000 salary(2)=salary(1)+1000 salary(1)=5000 總結爲: salary(n)=salary(n-1)+1000 (n>1) salary(1)=5000 (n=1) # 回溯階段 要求第n個員工的薪水,須要回溯獲得(n-1)個員工的薪水,以此類推,直到獲得第一個員工的薪水,此時,salary(1)已知,於是沒必要再向前回溯了。而後進入遞推階段:從第一個員工的薪水能夠推算出第二個員工的薪水(6000),從第二個員工的薪水能夠推算出第三個員工的薪水(7000),以此類推,一直推算出第第四個員工的薪水(8000)爲止,遞歸結束。須要注意的一點是,遞歸必定要有一個結束條件,這裏n=1就是結束條件。 # 代碼實現 def salary(n): if n == 1: return 5000 return salary(n-1)+1000 s=salary(4) print(s) # 8000 # 程序分析 在未知足n==1的條件時,一直進行遞歸調用,即一直回溯。而在知足n==1的條件時,終止遞歸調用,即結束回溯,從而進入遞推階段,依次推導直到獲得最終的結果。
items=[[1, 2], 3, [4, [5, [6, 7]]]] def foo(items): for i in items: if isinstance(i, list): #知足未遍歷完items以及if判斷成立的條件時,一直進行遞歸調用 foo(i) else: print(i, end=' ') foo(items) #打印結果1 2 3 4 5 6 7
使用遞歸,咱們只須要分析出要重複執行的代碼邏輯,而後提取進入下一次遞歸調用的條件或者說遞歸結束的條件便可,代碼實現起來簡潔清晰