大資料學習記錄,Python基礎(4)

灵敏的迅捷蟹發表於2024-12-02

函式

引言:比如植物大戰殭屍,這個遊戲本身也是由程式碼編寫,現在假設有一種豌豆射手,每發射一次炮彈會執行100行邏輯程式碼

如果我在程式,每當需要發射炮彈的時候,都要編寫100行邏輯程式碼,就會覺得該程式過於冗餘,程式碼重複度較高。

解決方案:

如果我將這100行程式碼放到一個區域中,然後給這個區域起一個名字,今後在需要發射炮彈的程式碼邏輯中,透過這個名字就可以呼叫起這100行程式碼。這個區域【程式碼段】在python中稱之為函式,先將函式定義出來,並對該函式起一個名字,將來在合適的地方透過函式名呼叫該函式,執行該函式的內部邏輯。

函式的定義

  • 語句定義格式:
# 使用python中的關鍵字 def
def 函式名(...):
函式程式碼邏輯

函式使用特點

  • 函式不呼叫不執行
  • 定義函式必須在呼叫之前出現

函式的引數

  • 引數種類

    • 形式引數:指的是函式定義時,小括號中定義的引數
    • 實際引數:指的是將來呼叫函式時,實際傳入進去的具體的值
    def fun1(hhs, zcy): # hhs zcy是形式引數,名字自定義
    	print(hhs + zcy)
    a1 = int(input("請輸入第一個數值:"))
    b1 = int(input("請輸入第二個數值:"))
    fun1(a1,b1) # a1 b1 是實際引數,可以是變數,也可以是具體的值本身
    
  • 引數的傳值方式

    • 位置傳參
    def show1(a, b, c):
    	print(f"a:{a},b:{b},c:{c}") # a:11,b:22,c:33
    show1(11, 22, 33)
    
    • 關鍵字傳參 【透過形參的名字傳參】
    def show1(a, b, c):
    	print(f"a:{a},b:{b},c:{c}")
    show1(b=100, c=200, a=300)
    
    • 混合傳參
    def show1(a, b, c):
    	print(f"a:{a},b:{b},c:{c}")
    show1(100, c=200, b=300)
    

    注意: 混合傳參的時候,前面沒有關鍵字的實參是會按照形參的位置來的,後面關鍵字傳參可以順序不一樣。

    函式傳參的場景【擴充套件知識】

    # 未使用函式
    '''
    編寫登入時的邏輯程式碼
    '''
    編寫傳送郵件的程式碼 50行
    '''
    編寫註冊時的邏輯程式碼
    '''
    編寫傳送郵件的程式碼 50行
    
    # 使用函式
    def send_email(xxx,xxx):
    編寫傳送郵件的程式碼
    '''
    編寫登入時的邏輯程式碼
    '''
    send_email(xxx,xxx)
    '''
    編寫註冊時的邏輯程式碼
    '''
    send_email(xxx,xxx)
    
    def send_email(msg_to, send_info):
     import smtplib
     from email.mime.text import MIMEText
     from email.header import Header
     msg_from = '1165872335@qq.com' # 傳送方郵箱
     passwd = 'owbciardnivafija' # 填入傳送方郵箱的授權碼(填入自己的授權碼,相當於郵箱密碼)
     # msg_to = ['','','']
     subject = "郵件資訊" # 主題
     # 生成一個MIMEText物件(還有一些其它引數)
     msg = MIMEText(send_info)
     # 放入郵件主題
     msg['Subject'] = subject
     # 也可以這樣傳參
     # msg['Subject'] = Header(subject, 'utf-8')
     # 放入發件人
     msg['From'] = msg_from
     # 放入收件人
     # 透過ssl方式傳送,伺服器地址,埠
     s = smtplib.SMTP_SSL("smtp.qq.com", 465)
     # 登入到郵箱
     s.login(msg_from, passwd)
     # 傳送郵件:傳送方,收件方,要傳送的訊息
     s.sendmail(msg_from, msg_to, msg.as_string())
     print('成功')
    p = input("請輸入要接收郵件的qq郵箱地址:")
    info = input("請輸入要傳送的內容:")
    send_email(p, info)
    
    • 預設值傳參

    需求:呼叫一個函式,傳入一個大字串和一個小字串,查詢小字串在大字串中出現的次數,呼叫函式的時候,可以不傳小字串,預設查詢字元'a'在大字串中的出現次數。

    def str_number(big_str, small_str='a'): # 定義函式時,可以設定形式引數的值,作為預設值
        # input輸入dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja
        list1 = list(big_str)
        counts = list1.count(small_str)
        print(f"{small_str}在大字串中總共出現了{counts}次。。。")
    str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja') # 呼叫時若不傳入第二個引數,使用的就是定義時的預設值
    str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja','f') # 若傳入第二個引數,使用的就是實際傳入的值	
    
    • 動態傳參

    未使用動態引數時,解決需求,比較麻煩,引數需要另外定義一個函式

# 需求1:定義一個函式,將來傳入兩個int型別的值求和
def sum1(a, b):
	print(a + b)
sum1(10, 20)
def sum2(a, b, c):
	print(a + b + c)
# 需求2:定義一個函式,將來傳入三個int型別的值求和
sum2(10, 20, 30)

使用動態引數,只需要定義一個函式就可以了

def sum1(*num):
	# 這裡的num 是一個元組,接收若干個將來呼叫時傳入的實參
	n = 0
	for i in num:
		n = n + i
	print(f"總和為:{n}")
sum1(10, 20) # (10, 20)
sum1(10, 20, 30) # (10, 20, 30)
sum1(10, 20, 30, 40) # (10, 20, 30, 40)

使用動態引數時的注意事項:

傳參的內容,多個引數的型別可以是不一樣的

def sum1(*num):
 # 這裡的num 是一個元組,接收若干個將來呼叫時傳入的實參
 # n = 0
 # for i in num:
 # n = n + i
 # print(f"總和為:{n}")
 print(num, type(num))
# sum1(10, 20) # (10, 20)
# sum1(10, 20, 30) # (10, 20, 30)
# sum1(10, 20, 30, 40) # (10, 20, 30, 40)
# sum1(11) # (11,)
# sum1(11, '小虎', [11, 22, 33]) # (11, '小虎', [11, 22, 33])
sum1((11,22,33)) # ((11, 22, 33),)

傳入兩個**的動態引數

def sum1(**num):
	print(num, type(num))
sum1(name='小虎', age=18)

結論:

* : 表示傳入的每一個單獨的元素都被封裝成一個元組
** : 表示傳入的是一個一個的鍵值對,所有的鍵值對會被封裝成一個字典
我們今後開發的時候,定義動態引數時,起名字是固定的,若一個*的動態引數,名字起為*args, 若**的動態引數,名字起為**kwargs
def show1(a, b, *args, **kwargs):
    print(args, type(args))
    print(kwargs, type(kwargs))
# show1(11,22,33,44,name='小虎',address='合肥')
show1(11, 22, 33, 44, name='小虎', address='合肥')

函式的返回值

有些函式,我們呼叫完之後,是能夠得到結果的,理論上來說,python中所有的函式都有返回值

python中提供了一個關鍵字給我們在函式中使用,表示呼叫完後返回的值,這個關鍵字叫做return

  • 例子
def sum1(a, b):
    c = a + b
    return c
res1 = sum1(10, 20)
print(res1)
print(res1+20)
  • 函式返回值的特點

    • 一個函式中如果沒有寫return, 預設情況下,這個函式最後一句話會有一個return None
    • return 和print的區別?
      • return是呼叫完函式時,可以返回一個值給呼叫者
      • print就直接輸出了,沒有返回值
    • 一個函式中,如果遇到了return,那麼這個函式就結束了,函式中的後續程式碼不執行
    def fun1(a, b):
        print("今天是星期二")
        c = a + b
        return c
        print("明天自習") # 不執行
    res1 = fun1(10, 20)
    print(res1)
    
    • 一個函式中只能有一個return
    def fun1(a, b):
        print("今天是星期二")
        c = a + b
        return c
        print("明天自習") # 不執行
        return 100 # 無效程式碼
    res1 = fun1(10, 20)
    print(res1)
    def fun1():
    	for i in range(1,11):
    		return i
    res1 = fun1()
    print(res1) # 1
    
    • 函式返回值return後面,要返回的型別可以是任意的型別
  • 函式引數和返回值的練習

    • 定義 兩個函式,第一個函式使用者迴圈輸入要累加的數值,函式內部將使用者輸入的值封裝成一個列表返回;第二個函式將第一個函式返回的列表當作引數傳入,返回列表中所有資料之和的結果。
    def get_list():
        list1 = []
        while True:
        	n = int(input("請輸入一個數值:"))
        	if n == -1:
        		break
        	list1.append(n)
        return list1
    
    def sum_list(l2):
    	n = 0
    	for i in l2:
    		n += i
    	return n
    
    
    l1 = get_list()
    print(l1)
    res2 = sum_list(l1)
    print(res2)
    
  • 函式返回值的的一些進階用法

    • 直接返回多個值,多個值之間使用英文逗號分隔,實際返回的內容是一個元組
    def show1():
    	return 11, 22, 33
    res1 = show1()
    print(res1, type(res1))
    
    • 分別接收每個返回元素的值
    def show1():
    	return 11, 22, 33
    
    a1, a2, a3 = show1()
    print(f"a1:{a1}")
    print(f"a2:{a2}")
    print(f"a3:{a3}")
    def show1():
    	return 11, ['hello','world','python'], 33
    
    a1, a2, a3 = show1()
    print(f"a1:{a1}") # a1:11
    print(f"a2:{a2}") # a2:['hello', 'world', 'python']
    print(f"a3:{a3}") # a3:33
    

函式的分類

  • 無參無返回值
def login():
	# 登入的操作邏輯
login()
  • 無參有返回值
def get_number():
    # 隨機生成一個數
    return num

n = get_number()
print(n)	
  • 有參無返回值
def sum1(a,b):
	print(a+b)
    
sum1(10,20)
  • 有參有返回值
def fun1(s1):
	return "shujia:" + s1
res1 = fun1('hello')

函式可以進行巢狀

  • 巢狀呼叫
def fun1():
	print("hello world 1")
def fun2():
	return 100
def fun3(a1, b1):
    fun1() # 呼叫fun1函式
    res1 = fun2() # 呼叫fun2函式
    return a1 + b1 + res1
res2 = fun3(11,22)
print(res2)
  • 巢狀定義
def fun1():
    a = 10
    def fun2():
    	print("hello world")
    print(a)
    fun2() # 不呼叫 不執行
    
fun1()
fun2() # 報錯,呼叫不了函式內部定義的函式
  • 函式練習2:定義一個函式,傳入一個文字路徑,和一個關鍵詞,將文字中包含關鍵詞的那一句話拿出來放在一個列表中返回該列表
import os
def get_word_list(file_os, word):
    res_list = []
    if os.path.exists(file_os):
        f = open(file_os, 'r', encoding='UTF-8')
        line_list = f.readlines()
        for line in line_list:
   			if word in line:
   				res_list.append(line.strip())
    else:
    	print("該路徑不存在!!")
    return res_list

list1 = get_word_list('data/words.txt', 'shujia')
print(list1)
def get_word_list(file_os, word):
    res_list = []
    if not os.path.exists(file_os):
        print("該路徑不存在!!")
        return res_list
    f = open(file_os, 'r', encoding='UTF-8')
    line_list = f.readlines()
    for line in line_list:
		if word in line:
			res_list.append(line.strip())
	return res_list

list1 = get_word_list('data/words.txt', 'shujia')
print(list1)

函式的傳值問題

在python中,呼叫函式時,傳入的是物件的引用。

  • 不可變物件【str, int, float, bool】
def fun1(x, y):
    print(f"x:{x}, y:{y}") # x:hello, y:world
    x = y
    x = x + x
    print(f"x:{x}, y:{y}") # x:worldworld, y:world
s1 = "hello"
s2 = "world"
print(f"s1:{s1}, s2:{s2}") # s1:hello, s2:world
fun1(s1,s2)
print(f"s1:{s1}, s2:{s2}") # s1:hello, s2:world


不可變物件:指的是函式內的操作不會影響到函式外的變數值

  • 可變物件【list, tuple, dict, set, 類】
def fun1(x, y):
    print(f"x:{x}, y:{y}") # x:['hello'], y:['world']
    x = y
    x.append('java')
    print(f"x:{x}, y:{y}") # x:['world','java'], y:['world','java']

s1 = ['hello']
s2 = ['world']
print(f"s1:{s1}, s2:{s2}") # s1:['hello'] , s2:['world']
fun1(s1,s2)
print(f"s1:{s1}, s2:{s2}") # s1:['hello'], s2:['world', 'java']

可變物件函式內部可以進行操作,改變可變物件中儲存的值,間接影響到函式外變數的引用

作用域和變數

  • 在python中,作用域分為兩個區域

    • 函式外是一個作用域
    • 函式內部是一個作用域
  • 全域性變數:將變數定義在函式外

  • 區域性變數:將變數定義在函式內部

  • 全域性變數和區域性變數使用特點

    • 區域性作用域中可以使用到全域性變數【可以使用函式外部定義的變數】
    • 函式與函式內部的作用域是相互獨立的,不能互相呼叫函式內部建立的區域性變數
    if 1==1:
    	a=10
    print(f"a:{a}")
    for i in range(11):
    	pass
    print(f"i:{i}")
    
  • python中提供了一個關鍵字 global, 在函式內部定義一個全域性變數,出了函式也是可以被訪問到的。

def fun1():
    global a
    a = 100
fun1()
print(a)

注意:如果函式內部有變數被global修飾,需要先呼叫該函式,讓記憶體中出現這個變數,後續才能去使用。

函式名也可以當作一個變數使用

  • 用法場景1:
def fun1():
	print("好好學習,天天向上!")
fun2 = fun1

fun2()

賦值的時候,注意有沒有小括號,方法名直接賦值,相當於給函式另起了一個名字;如果加了小括號,相當於呼叫函式的結果賦值。

  • 用法場景2:變數可以儲存在容易中,比如列表
def fun1():
	print("鵝鵝鵝")
def fun2():
	print("曲項向天歌")
def fun3():
	print("白毛浮綠水")
def fun4():
	print("紅掌撥清波")
fun_list = [fun1, fun2, fun3, fun4]
flag = input("請輸入開始:")
for i in fun_list:
	i()
  • 用法場景:將函式作為返回值使用
def fun1():
	print("鵝鵝鵝")
def fun2():
	print("曲項向天歌")
def fun3():
	print("白毛浮綠水")
def fun4():
	print("紅掌撥清波")
fun_list = [fun1, fun2, fun3, fun4]
def show1():
	for i in fun_list:
		i()
def function1():
	return show1
res1 = function1()
res1()    
  • 用法場景4:將函式作為引數傳遞
def fun1():
	print("鵝鵝鵝")
def fun2():
	print("曲項向天歌")
def fun3():
	print("白毛浮綠水")
def fun4():
	print("紅掌撥清波")
fun_list = [fun1, fun2, fun3, fun4]
def show1():
	for i in fun_list:
		i()
def function1(s):
	s()
function1(show1)

作業:登入註冊的案例

  • main函式要有,使用者自己選擇要做的功能,根據選擇呼叫不同的函式
  • 使用者註冊的資訊需要使用一個檔案儲存,登入需要判斷使用者是否存在,密碼是否正確
  • 註冊的時候,需要傳送郵件

函式和模組

在python開發中,我們需要利用python語言完成現實生活中的場景,python提供了許多內建的函式和模組給我們使用,完善我們的程式,比如time,random等等模組,如果我們還想要學習其他的模組,就需要使用第三方模組了。所以在python開發行業中,我們將python開發程式設計師稱之為調包俠。

內建函式

python的內建函式分為很多種

  • 1.數學類函式

    • abs() 求絕對值
    n = -12
    print(abs(n))  #12
    
    • sum() 求和 (字串型別的元素不行)
    list1 = [11,22,33,44,55]
    res1 = sum(list1)
    print(res1) #165
    
    • divmod() 傳入兩個數值,前一個除以後一個,得到兩個值:一個商,一個是餘數
    s, y = divmod(16, 5)
    print(s) #3
    print(y) #1
    
    • round() 四捨五入
    n = 12.765
    print(round(n)) # 13
    print(round(n,2)) # 四捨五入並保留兩位小數(12.77)
    
    • pow 求冪次方
    print(pow(2,3)) #輸出2的三次冪
    
  • 聚合類函式

    • max() 求最大值
    list1 = [123,53,225,1123,52,5,3,14]
    res1 = max(list1)
    print(res1) #1123
    
    • min 求最小值
    list1 = [123,53,225,1123,52,5,3,14]
    res1 = min(list1)
    print(res1) #3
    
    • all 判斷一個列表中是否出現一個False
    # 只要存在一個元素轉bool型別結果是False,all()的結果就是False
    list1 = [12,45,124,'','hello',12.34]
    print(all(list1)) #由於列表中有一個元素為空,輸出False
    
    • any 判斷一個列表中是否出現一個True
    # 只要存在一個元素轉bool型別結果是True,all()的結果就是True
    list1 = [12,45,124,'','hello',12.34]
    print(any(list1)) #True
    
  • 和進位制相關的函式

    • 二進位制

    bin() 將十進位制的值轉二進位制

    print(bin(136)) # 0b10001000
    

    int() 將某一種進位制轉10進位制

    print(int('0b10001000',2))
    
    • 八進位制

    oct() 將十進位制轉八進位制

    print(oct(136)) # 0o210
    
    • 十進位制

    整數預設都是十進位制

    • 十六進位制

    hex() 將十進位制轉16進位制

    print(hex(136)) # 0x88
    
  • 字元類函式

    • ord() 將一個字元轉成ASCII碼數值
      • 0' - 48
      • 'A' - 65
      • 'a' - 97
    print(ord('0')) #48
    print(ord('A')) #65
    print(ord('a')) #97
    
    • chr() 將數值轉成對應的ASCII碼字元
    print(chr(97))
    
  • 型別轉換相關函式

    • int()
    • str()
    • bool()
    • list()
    • dict()
    • tuple()
    • set()
    • bytes()
    s1 = '中國'
    b1 = s1.encode('UTF-8')
    print(b1, type(b1)) #\xe4\xb8\xad\xe5\x9b\xbd' <class 'bytes'>
    
    b2 = bytes('中國','UTF-8')
    print(b2) #\xe4\xb8\xad\xe5\x9b\xbd'
    
  • 獲取輸出類函式

    • input()
    • print()
    • len()
    • open()

    獲取列表的索引和元素

    list1 = [1,2,3,4]
    for i,j in enumerate(list1):
    	print(i,j)
    
    • id() 獲取物件的地址值
    • callable() 判斷一個變數是否是一個函式
    list1 = [1,2,3,4]
    def fun1():
    	pass
    print(callable(fun1)) #變數是函式,因此結果為True
    
    • sorted() 排序 #預設為從小到大排序
    list1 = [34,12,5,12,344,53]
    print(f"list1:{list1}")
    list2 = sorted(list1)
    print(f"list1:{list2}") # list1:[5, 12, 12, 34, 53, 344]
    

    自定義排序依據:

    list1 = ['小虎:1007', '小黃:1009', '小查:1001', '小濤:1004', '小方:1002']
    def fun1(e):
    	return int(e.split(':')[1]) #以“:”為分隔符,並取“:”後的字元
    
    list2 = sorted(list1, key=fun1) #調取fun1函式並根據“:“後的數字進行排序
    print(f"list2:{list2}")#list1:['小查:1001', '小方:1002', '小濤:1004', '小虎:1007', '小黃:1009']
    
    • zip() 將兩個序列中的元素一一對應
    list1 = [1001, 1002, 1003, 1004, 1005]
    list2 = ['小虎', '黃滬生', '查鎔賢', '黃濤', '方直']
    for i,j in zip(list1,list2):
    	print(f"學號:{i}, 姓名:{j}")
    
    #學號: 1002, 姓名: 黃滬生
    #學號: 1003, 姓名: 查鎔賢
    #學號: 1004, 姓名: 黃濤
    #學號: 1005, 姓名: 方直
    
    

函式生成式

python中提供了一個關鍵字可以讓我們在函式中使用 yield

輸入一次 print(res1.next()) 便會執行一次,否則將會暫停

def fun1():
    yield 1
    print("hello world")
    yield 2
    print("hello world")
    yield 3
    print("hello world")
    yield 4
    print("hello world")
    yield 5
res1 = fun1()

print(res1.__next__())
print(res1.__next__())
print(res1.__next__())
print(res1.__next__())

有yield關鍵字的函式,結果是可以使用for迴圈的

def fun1():
    print("hello 1")
	yield 1
	print("hello 2")
	yield 2
	print("hello 3")
	yield 3
	print("hello 4")
	yield 4
	print("hello 5")
	yield 5
res1 = fun1()
for i in res1:
	print(i)
	print("-----------")

def fun1():
	for i in range(1,11):
		yield i
res1 = fun1()

for i2 in res1:
	print(i2)
	print("-----------")

相關文章