第五篇 匿名函式、內建函式、import的使用、包的使用
一、函式的遞迴呼叫
#函式遞迴呼叫:在呼叫一個函式的過程中直接或間接地呼叫該函式本身,稱之為函式的遞迴呼叫,也就是函式的巢狀呼叫時呼叫自己本身
import sys
print(sys.getrecursionlimit()) #列印發現預設遞迴的層級是1000
sys.setrecursionlimit(2000) #可以修改遞迴的層級到2000
n=1
def func1():
global n
print('from func1',n)
n+=1
func1()
func1()
#間接地呼叫自身也叫遞迴呼叫
def func():
print('from func')
bar()
def bar():
func()
func()
#遞迴分為兩個重要的階段:遞推+回溯
# age(5)=age(4)+2
# age(4)=age(3)+2
# age(3)=age(2)+2
# age(2)=age(1)+2
# age(1)=18
# n!=1 #age(n)=age(n-1)+2
# n=1 #age(n)=18
上面的例子可以用函式的遞迴呼叫表示
def age(n):
if n == 1:
res=18
return res
res=age(n-1)+2 #res=age(4)+2
return res
print(age(5))
#總結遞迴呼叫:
#1:進入下一次遞迴時,問題的規模必須降低
#2:遞迴呼叫必須要有一個明確的結束條件
#3:在python中沒有尾遞迴優化,遞迴呼叫的效率就是不高
#練習,取出列表中的每一元素
l=[1,2,[3,[4,[5,[6,7,[8,9,[10,[11,[12,]]]]]]]]]
def get(l):
for item in l:
if isinstance(item,list): #等於if type(item) is list,判斷item是否是列表型別
get(item) #如果是列表就遞迴呼叫
else:
print(item)
get(l)
二、二分法
判斷一個數字是否在這個列表內,如果在就列印find it
l=[1,2,10,30,33,99,101,200,301,402] #從小到大排列的數字列表,如果不是按照順序排列的不能用二分法
def get(num,l):
print(l)
if len(l) > 0: #列表不為空,則證明還有值是可以執行二分法邏輯的
mid=len(l)//2 #地板除只取整數部分
if num > l[mid]:
#in the right
l=l[mid+1:] #對列表進行切分,取列表的右半部分
elif num < l[mid]:
#in the left
l=l[:mid]
else: #如果正好是中間的值
print('find it')
return
get(num,l) #使用函式的遞迴呼叫
else: #列表為空,則證明根本不存在要查詢的值
print('not exists')
return
get(403,l)
三、匿名函式
#匿名函式即沒有繫結名字的函式,沒有繫結名字,意味著只能用一次就會被回收
#所以說匿名函式的應用場景就是:某個功能只用一次就結束了
def f1(n):
return n**2
print(f1(3)) #列印函式的返回值
上面的程式碼可以寫成匿名函式
f2=lambda n:n**2 #n:n**2第一個n是上面函式中的引數,匿名函式只能寫到一行,並且把冒號後面的當做匿名函式的返回值,不用加return
print(f2(3))
取出最大的工資
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
}
print(max(salaries)) #預設比較的是key
print(max(salaries.values())) #要取value需這樣寫
執行結果:
Yuanhao
100000000
#拉鍊函式
l1=[1,2,3]
s1='hello'
res=zip(l1,s1)
print(list(res)) #把res的值放到列表中
執行結果:
[(1, 'h'), (2, 'e'), (3, 'l')]
發現拉鍊函式是把l1和s1中的元素按照順序合起來放在元組中
#補充:序列型別的比較,先比較第一個,如果第一個一樣大才比較第二個,有索引的叫做序列型別
兩個元組比較大小
t1=(3333,'a')
t2=(2,'a','b','c')
print(t1 < t2)
執行結果為False
把工資最大的人名取出來
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
}
res=zip(salaries.values(),salaries.keys())
#print(max(res)) #發現把工資最大的和人名放到一個元組中
print(max(res)[1]) #要取出人名就取元組中索引為1的元素
#max與lambda的結合
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
}
def f1(k):
return salaries[k]
print(max(salaries,key=f1)) #表示取最大值,不是鍵而是值,key=什麼表示要取的什麼,因為key=f1函式的返回值,表示要取value的最大值
執行結果為:alex
上面程式碼可以用匿名函式簡寫為
print(max(salaries,key=lambda k:salaries[k])) #表示取的是lambda匿名函式的最大值,此匿名函式的返回值為salaries[k],如果k=alex,就是比較alex的value是不是最大的,不是就繼續比較
print(min(salaries,key=lambda k:salaries[k]))
print(sorted(salaries,key=lambda k:salaries[k])) #表示排序,按照lambda函式的返回值排序,也就是按照工資排序
print(sorted(salaries,key=lambda k:salaries[k],reverse=True))
執行結果為:
Alex
Yuanhao
['yuanhao', 'egon', 'wupeiqi', 'alex']
['alex', 'wupeiqi', 'egon', 'yuanhao']
匿名函式其他常用的其他用途
#map,reduce,filter
map表示對映,在列表中所有的人名後面加_SB結尾
l=['alex','wupeiqi','yuanhao','huanghongwei']
print(list(map(lambda x:x+'_SB',l)))
執行結果:
['alex_SB', 'wupeiqi_SB', 'yuanhao_SB', 'huanghongwei_SB']
reduce表示合併:計算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(1,101))) #,匿名函式有x,y兩個引數,預設初始值是0,首先取初始值0,然後在range中取第一個元素1,進行運算,運算的結果再取一個元素進行加運算,
print(reduce(lambda x,y:x+y,range(1,101),100)) #如果初始值是100,就會100+1,然後101+2,103+3這樣運算
執行結果:
5050
5150
filter:過濾,把SB結尾的過濾出來
l=['alex_SB','wupeiqi_SB','yuuanhao_SB','hhw','egon']
res=filter(lambda name:name.endswith('SB'),l)
print(list(res))
四、內建函式
#其他內建函式
print(abs(-1)) #求-1絕對值為+1
print(all([1,'a',[]])) #all的引數為可迭代物件,並且可迭代物件中的每一個元素都為真,結果才為真,否則為假
print(all([])) #如果引數為空,則結果為真,空不是沒有引數,而是空列表或者空元組、字典等
執行結果:
False
True
print(any([0,None,'',1])) #any表示引數為可迭代物件中的元素有一個為真,結果為真
print(any([])) #False
print(bin(10)) #十進位制轉化為二進位制
print(oct(10)) #十進位制轉化為八進位制
print(hex(10)) #十進位制轉化為十六進位制
# bool()
#布林值為假:0,None,空
把字串轉化為bytes型別
print('hello'.encode('utf-8'))
print(bytes('hello',encoding='utf-8'))
print(callable(max)) #判斷物件是否是可呼叫的,max是個內建函式,可以被呼叫,結果為True
print(chr(65)) #把數字根據ASIC錶轉化為對應的字母
print(chr(90))
print(ord('A')) #反過來,轉化為數字
#complex複數
x=1-2j #x=complex(1-2j)
print(type(x)) #檢視型別
print(x.real) #檢視複數的實部為1
print(x.imag) #檢視虛部為-2
#dict,int,list,tuple,str,float,set,frozenset
s=set({1,2,3}) #可變集合,造的集合是可變型別的,set是內建函式,用來造可變集合
s=frozenset({1,2,3}) #不可變集合,造的集合是不可變型別的
dict是內建函式,用來造字典
import time
print(dir(time))#檢視一個模組都有哪些屬性,比如time.time屬性等
print(divmod(1001,25)) #40是商,1是餘數
執行結果:(40, 1)
l=['a','b','c','d']
for x in enumerate(l):
print(x)
執行結果:取出列表裡的元素的同時,還取出索引
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')
print(hash('asdfasdfasdfasdfasdf')) #取雜湊值
檢視函式的註釋資訊
def func():
'''
xxxxxx
:return:
'''
pass
print(help(func))
print(isinstance(1,int)) #判斷一個資料是不是什麼型別
print(type(1) is int) #也可以用這種方式,但推薦用上面那種
print(pow(10,2,3)) #10**2%3
print(str({'a':1})) #把一個資料型別轉化為字串
l=[1,4,2,9]
print(list(reversed(l)))#對列表倒著排
print(round(10.55545,3)) #表示保留三位小數,四捨五入
l1=['a','b','c','d','e']
l2=['a','b','c','d','e']
print(l1[1:5:2]) #'b','d'
print(l2[1:5:2]) #'b','d'
下面這種方式和上面是一樣的
l1=['a','b','c','d','e']
l2=['a','b','c','d','e']
obj=slice(1,5,2)#可以取切片物件
print(l1[obj])
print(l2[obj])
print(sum([1,2,3,4])) #傳進來的值可以是列表、元組、集合等數字
print(sum(range(10)))#sum函式可以把傳進來的引數變成迭代器,next一次取一次值
print(vars() is locals())#不加引數vars函式是看區域性作用域的名字,等於locals函式
vars(obj) 等同於obj.__dict__
# import "time" #import 不能匯入字串,但可以通過如下方式匯入字串
m=input('>>: ')
print(type(m))
obj=__import__(m) #實現與使用者互動的方式匯入模組,比如輸入的是time字串,就相當於匯入time模組
print(obj.time())
#瞭解:compile,exec,eval
#eval:提取字串內的表示式執行,然後返回執行結果
s1="1+2+3"
print(eval(s1))
s2="['a','b','c']"
l=eval(s2)
print(type(l))
print(l)
執行結果:
6
<class 'list'>
['a', 'b', 'c']
s2="for i in range(10):print(i)"
eval(s2) #執行會報錯,因為沒有執行結果
#exec:僅僅只是執行字串內的表示式或語句,沒有返回值
s1="1+2+3"
print(exec(s1))
s2="for i in range(10):print(i)"
exec(s2)#可以執行
#優先掌握
max min sorted map from functools import reduce filter sum bool chr
divmod enumerate id input print isinstance iter len open pow type
zip
五、import的使用
#常見的場景:一個模組就是一個包含了一組功能的python檔案,比如spam.py,模組名為spam,可以通過import spam使用。
#在python中,模組的使用方式都是一樣的,但其實細說的話,模組可以分為四個通用類別:
1 使用python編寫的.py檔案
2 已被編譯為共享庫或DLL的C或C++擴充套件
3 把一系列模組組織到一起的資料夾(注:資料夾下有一個__init__.py檔案,該資料夾稱之為包)
4 使用C編寫並連結到python直譯器的內建模組
#匯入模組,只會在第一次匯入時執行原始檔的程式碼
#如果模組已經載入到記憶體了,下一次匯入直接引用記憶體中匯入的結果
import spam #m1=111111
import spam #m2=m1
import sys
print(sys.modules) #檢視記憶體中已經載入的模組
print('spam' in sys.modules) #檢視spam模組是否在記憶體中
#import 匯入檔案都做了哪些事?
#1 以原始檔為準產生一個名稱空間,在spam.py檔案裡
#2 以剛剛產生的名稱空間為準,執行原始檔的程式碼
#3 會在當前檔案中定義一個名字,這個名字就是模組名,用來引用模組中的名字
#spam.py
print('from the spam.py')
money=1000
def read1():
print('spam模組:',money)
def read2():
print('spam模組')
read1()
def change():
global money
money=0
import spam #匯入模組就會執行原始檔的程式碼
money=0
def read1():
print('from ------>')
read1()#呼叫的是當前檔案的read1
spam.read1() #呼叫的是spam.py檔案中的read1
spam.read2()
money=1000000000
spam.change()
print(money) #打列印的是當前檔案定義的money
spam.read1()
總結:import匯入spam模組後,可以使用spam.呼叫spam.py檔案的內容
六、from...import的使用
#spam.py
print('from the spam.py')
money=1000
def read1():
print('spam模組:',money)
def read2():
print('spam模組')
read1()
def change():
global money
money=0
#為模組起別名
import spam as sm
print(sm.money)
舉例
#mysql.py
def parse():
print('mysql sql parse')
#oracle.py
def parse():
print('oracle sql parse')
engine_type='mysql'
if engine_type == 'mysql':
import mysql as engine
elif engine_type == 'oracle':
import oracle as engine
engine.parse()
#在一行匯入多個模組
import spam,time
#匯入模組的另外一種方式:from...import...
from spam import money,read1,read2,change #從哪個模組匯入什麼屬性
money=1
print(money) #列印的是當前檔案的
read1() #好處是呼叫的時候不用加字首spam.read1(),壞處會和當前檔案的衝突
def read1():
print('===>?')
read1()#呼叫當前的
read2()
change()
print(money) #列印當前檔案的
from spam import * #可以匯入模組的所有屬性,但不知道都匯入了什麼,儘量不要用,不然衝突的可能性更大
print(money)
print(read1) #列印函式的記憶體地址
print(read2)
print(change)
#spam.py
print('from the spam.py')
__all__=['money','read1'] #from ... import *
money=1000
def read1():
print('spam模組:',money)
def read2():
print('spam模組')
read1()
def change():
global money
money=0
from spam import * #* 對應模組spam內的__all__屬性
print(money)
print(read1)
print(read2) #此時會報錯,因為沒有匯入此屬性
七、python檔案的兩種用途
#模組的過載 (瞭解)
考慮到效能的原因,每個模組只被匯入一次,放入字典sys.module中,如果你改變了模組的內容,你必須重啟程式,python不支援重新載入或解除安裝之前匯入的模組,
有的同學可能會想到直接從sys.module中刪除一個模組不就可以解除安裝了嗎,注意了,你刪了sys.module中的模組物件仍然可能被其他程式的元件所引用,因而不會被清楚。
特別的對於我們引用了這個模組中的一個類,用這個類產生了很多物件,因而這些物件都有關於這個模組的引用。
如果只是你想互動測試的一個模組,使用 importlib.reload()可以重新載入模組, 比如
import importlib
importlib.reload(modulename)#這隻能用於測試環境。
#py檔案區分兩種用途:模組與指令碼
#編寫好的一個python檔案可以有兩種用途:
一:指令碼,一個檔案就是整個程式,用來被執行
二:模組,檔案中存放著一堆功能,用來被匯入使用
#python為我們內建了全域性變數__name__,
當檔案被當做指令碼執行時:__name__ 等於'__main__'
當檔案被當做模組匯入時:__name__等於模組名,也就是說如果被匯入的模組中含有__name__程式碼,那麼__name__等於模組名
#作用:用來控制.py檔案在不同的應用場景下執行不同的邏輯
if __name__ == '__main__':
總結一下:
如果我們是直接執行某個.py檔案的時候,該檔案中”__name__ == '__main__'“是True,但是我們如果從另外一個.py檔案通過import匯入該檔案的時候,這時__name__的值就是我們這個py檔案的名字而不是__main__。
這個功能還有一個用處:除錯程式碼的時候,在”if __name__ == '__main__'“下面加入一些我們的除錯程式碼,我們可以讓外部模組呼叫的時候不執行我們的除錯程式碼
八、模組的搜尋路徑
#模組的查詢順序是:記憶體中已經載入的模組->內建模組->sys.path路徑中包含的模組
import sys
sys.path.append(r'D:\張大志邁遠\pythontest\day5\day5\a') #如果模組的py檔案與執行檔案不在同一目錄下,要將模組的py檔案加到sys.path環境變數中才能匯入模組sys.path.append或者sys.path.insert
import m
或者
from a import m
九、包的使用
1、什麼是包?
#官網解釋Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一種通過使用‘.模組名’來組織python模組名稱空間的方式。
#具體的:包就是一個包含有__init__.py檔案的資料夾,所以其實我們建立包的目的就是為了用資料夾將檔案/模組組織起來
#需要強調的是:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 建立包的目的不是為了執行,而是被匯入使用,記住,包只是模組的一種形式而已,包的本質就是一種模組
#匯入包實際上就是在匯入包下面的__init__.py檔案,如果想呼叫包下的其他模組檔案,需要先在__init__.py檔案中匯入此模組檔案才能使用包下的其他模組,__init__.py檔案的path環境變數路徑和執行檔案環境變數相同,也就是執行檔案在哪個目錄下,_init__.py檔案的環境變數也在哪個目錄下
在__init__.py中匯入模組的方法
from aaa import m1 #匯入aaa目錄下的m1模組,這樣在執行檔案中就可以使用這個模組
在執行檔案中的操作
import aaa #在執行檔案中先匯入aaa這個包,就是匯入__init__.py檔案,因為此檔案中已經匯入m1模組
aaa.m1.f1()#就可以在執行檔案中呼叫m1模組下的f1屬性
如果想在執行檔案中直接調m1模組的f1屬性
#點的左邊必須是包,from...import後必須是一個明確的名字,不能帶點
from aaa.m1 import f1 #在__init__.py中匯入的方式
在執行檔案中呼叫的方式
import aaa #先匯入包,因為__init__.py中已經匯入f1屬性
aaa.f1() #就可以在執行檔案中直接呼叫f1屬性
以上匯入包的方式都是絕對路徑的匯入,都是從包的頂級目錄開始找
也可以用相對路徑的方式匯入包
from .. ccc import f4 #..表示上一級目錄,加一個點就表示上一級
from . bbb.m3 import f3 #. 表示當前目錄,和linux裡面的一樣
如果執行檔案和匯入的包不在同一目錄下,需要在執行檔案中先將包所在的目錄加入環境變數,才能匯入包
import sys
sys.path.append(r'C:\Users\Administrator\PycharmProjects\python19期\day5\7 包的使用\xxx\yyy')
import aaa
也可以不依賴於__init__.py檔案,直接在執行檔案中把包檔案匯入
import aaa.ccc.m4 #匯入aaa包下的ccc包下的m4.py檔案
aaa.ccc.m4.f4() #呼叫的時候就要把包名都寫上,可以把整個包起別名,呼叫的時候簡單
十、軟體開發規範
import os
print(os.path.abspath(__file__)) #列印當前檔案的絕對路徑
print(os.path.dirname(os.path.abspath(__file__))) #當前檔案所在的目錄
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #當前檔案的上一級目錄
#start.py
#目錄結構ATM/bin/start.py ATM/core/src.py ATM/conf/setting.py
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #將ATM目錄加入到path變數裡,因為已經新增到環境變數裡了,在任意檔案中都可以用這個環境變數
from core import src
if __name__ == '__main__':
src.run()
#src.py
from conf import settings
def shop():
print('shopping',settings.DB_PATH)
def run():
while True:
print('''
1 購物
2 付款
3 還款
4 轉賬
''')
choice=input('>>: ').strip()
if not choice:continue
if choice == '1':
shop()
#setting.py
DB_PATH=r'C:\Users\Administrator\PycharmProjects\python19期\day5\8 軟體開發規範\ATM\db'
相關文章
- 閉包函式(匿名函式)的理解函式
- GO 的匿名函式使用注意Go函式
- lambda匿名函式使用中的坑函式
- 關於oracle內建函式的使用Oracle函式
- JavaScript 匿名函式 閉包JavaScript函式
- Day 14 匿名函式 內建函式 物件導向程式設計函式物件程式設計
- 使用bind()函式的產生的函式用作建構函式this的指向函式
- 深入理解 函式、匿名函式、自執行匿名函式函式
- javascript匿名函式的使用簡單介紹JavaScript函式
- 不使用 JS 匿名函式的三個理由JS函式
- webgl內建函式--指數函式Web函式
- webgl內建函式--通用函式Web函式
- ORACLE 內建函式和connect by使用Oracle函式
- 內建函式函式
- python內建函式-eval()函式與exec()函式的區別Python函式
- 3. 匿名函式與閉包函式
- 淺談匿名函式和閉包函式
- js中匿名函式的使用簡單介紹JS函式
- js中的匿名函式JS函式
- 第 8 節:函式-匿名函式、遞迴函式函式遞迴
- python-內建函式(搭配lambda使用)Python函式
- webgl內建函式--幾何函式與矩陣函式Web函式矩陣
- webgl內建函式--向量函式與紋理查詢函式Web函式
- Hive函式(內建函式+自定義標準函式UDF)Hive函式
- 函式: 函式是怎麼使用的?函式
- PHP匿名函式PHP函式
- Ruby 匿名函式函式
- Golang匿名函式Golang函式
- JavaScript 匿名函式JavaScript函式
- Go 匿名函式Go函式
- JavaScript匿名函式JavaScript函式
- MySQL 內建函式MySql函式
- hive內建函式Hive函式
- php 內建函式PHP函式
- Mysql內建函式MySql函式
- 14、內建函式函式
- awk內建函式函式
- js內建函式JS函式