1. set類型
set 和 dict 類似,也是一組 key 的集合,但是不存儲 value. 由於 key 不重復,所以,在 set 中, 沒有重復的 key 集合是可變類型
(1)集合的創建
# 第一種方式創建 set 類型
>>> print(type(set1), set1)
<class 'set'> {1, 3, 6, 'z', 'a', 'b'}
# 第二種方式創建 set 類型
>>> set2 = set(['z', 'a', 'b', 3, 6, 1])
>>> print(type(set2), set2)
<class 'set'> {1, 3, 6, 'z', 'a', 'b'}
# 第三種方式創建 set 類型
>>> set3 = set('hello')
>>> print(type(set3), set3)
<class 'set'> {'o', 'e', 'l', 'h'}
2. set 工廠函數
(1)add(self, *args, **kwargs)
新增一個元素到集合
set1 = {'a', 'z', 'b', 4, 6, 1}
set1.add(8)
set1.add('hello')
print(set1)
# 執行結果:
# {'b', 1, 'a', 4, 6, 8, 'hello', 'z'}
(2) clear()
清空所有集合元素
set1 = {'a', 'z', 'b', 4, 6, 1}
set1.clear()
print(set1)
# 執行結果:
# set()
(3)copy()
拷貝整個集合並賦值給變量
set1 = {'a', 'z', 'b', 4, 6, 1}
set2 =set1.copy()
print(set2)
# 執行結果:
# {1, 'a', 4, 6, 'b', 'z'}
(4)pop()
隨機刪除集合中一個元素,可以通過變量來獲取刪除的元素
set1 = {'a', 'z', 'b', 4, 6, 1}
ys = set1.pop()
print('set1集合:', set1)
print('刪除的元素:', ys)
# 執行結果:
# set1集合: {4, 6, 'z', 'a', 'b'}
# 刪除的元素: 1
(5)remove(self, *args, **kwargs)
刪除集合中指定的元素,如果該集合內沒有該元素就報錯
set1 = {'a', 'z', 'b', 4, 6, 1}
set1.remove('a')
print(set1)
set1.remove('x')
print(set1)
# 執行結果:
# {1, 4, 6, 'b', 'z'}
# Traceback (most recent call last):
# File "D:/learn_python/learn_python/day13/s1.py", line 43, in <module>
# set1.remove('x')
# KeyError: 'x'
(6)discard(self, *args, **kwargs)
刪除集合中指定的元素,如果該集合內沒有該元素也不會報錯
set1 = {'a', 'z', 'b', 4, 6, 1}
set1.discard('a')
print(set1)
set1.discard('y')
print(set1)
# 執行結果:
# {1, 4, 6, 'b', 'z'}
# {1, 4, 6, 'b', 'z'}
pop() 、remove() 、 discard() 三個集合刪除函數比較:
pop() 隨機刪除集合中一個元素remove() 刪除集合中指定的元素,如果集合中沒有指定的元素,程序報錯!
discard() 刪除集合中指定的元素,如果集合中沒有指定的元素,程序正常運行。
(7) intersection & :交集; union | :並集合; difference - : 差集
set1 = {'a', 'b', 'x', 'y'}
set2 = {'i', 'j', 'b', 'a'}
# 交集
print(set1 & set2)
print(set1.intersection(set2))
# 執行結果:
# {'a', 'b'}
# {'a', 'b'}
# 並集
print(set1 | set2)
print(set1.union(set2))
# 執行結果:
# {'y', 'j', 'a', 'b', 'x', 'i'}
# {'y', 'j', 'a', 'b', 'x', 'i'}
# 差集
print(set1 - set2)
print(set1.difference(set2))
print(set2 - set1)
print(set2.difference(set1))
# 執行結果:
# {'y', 'x'}
# {'y', 'x'}
# {'j', 'i'}
# {'j', 'i'}
(8)difference_update ()
求差集,並賦值給源集合
set1 = {'a', 'b', 'x', 'y'}
set2 = {'i', 'j', 'b', 'a'}
set1.difference_update(set2)
print(set1)
# 執行結果:
# {'y', 'x'}
(9)intersection_update()
求交集,並賦值給源集合
set1 = {'a', 'b', 'x', 'y'}
set2 = {'i', 'j', 'b', 'a'}
set1.intersection_update(set2)
print(set1)
# 執行結果:
# {'b', 'a'}
(10)symmetric_difference() 和 ^ 符號效果一樣
求交叉補集
set1 = {'a', 'b', 'x', 'y'}
set2 = {'i', 'j', 'b', 'a'}
print('symmetric_difference:', set1.symmetric_difference(set2))
print('^:', set1 ^ set2)
# 執行結果:
# symmetric_difference: {'x', 'i', 'y', 'j'}
# ^: {'x', 'i', 'y', 'j'}
(11)symmetric_difference_update()
求交叉補集並賦值給源集合
set1 = {'a', 'b', 'x', 'y'}
set2 = {'i', 'j', 'b', 'a'}
set1.symmetric_difference_update(set2)
print(set1)
# 執行結果:
# {'y', 'i', 'j', 'x'}
(12)update()
更新集合,參數為可迭代對象
set1 = {'a', 'b', 'x', 'y'}
set1.update(('hello', 'world'))
print(set1)
# 執行結果:
# {'hello', 'world', 'b', 'a', 'y', 'x'}
add() 和 update() 比較:
add(): 只能添加一個元素到集合
update(): 可以添加多個元素到集合,參數為 iterable
使用 frozenset 定義不可變集合
s = frozenset('hello')
print(s)
# 執行結果:
# frozenset({'h', 'e', 'o', 'l'})
使用 frozenset 定義的集合,沒有 add 或者 pop 等方法
3. 函數
(1)函數表現形式
python中函數的定義方法:
def test(x): "The function definitions" x += 1 return x
def: 定義函數關鍵字
test: 函數名(): 內可定義參數"": 文檔描述(非必要,強烈建議添加函數信息描述)
x+=1 : 泛指代碼塊或程序處理邏輯
return: 定義返回值
調用運行:可以帶參數也可以不帶函數名()
使用函數的好處:
代碼重用
保持一致性,易維護
可擴展
函數返回值:
返回值 = 0 : 返回 None
返回值 = 1 : 返回 object
返回值數 > 1: 返回 tuple
(2)函數的參數
建議參考:廖老師python3函數的參數
4. 全局變量和局部變量
如果函數的內容無 global 關鍵字,優先讀取局部變量,能讀取全局變量,無法對全局變量重新賦值 NAME='FFF',但是對於可變類型,可以對內部元素進行操作;
如果函數中有 global 關鍵字,變量本質上就是全局變量,可讀取可賦值 NAME='fff'
name = 'hkey'
def test1():
name = 'xiaofei'
print(name)
def test2():
global name
name = 'xxxx'
test1()
test2()
print('name:', name)
# 執行結果:
# xiaofei
# name: xxxx

如果函數內無 global 關鍵字:
(1)有聲明局部變量
NAME = ['xiaofei', 'hkey']
def test():
NAME = 'sky'
print('name:', NAME)
test()
# 執行結果:
# name: sky
(2)無聲明局部變量
對於可變類型,可以對內部元素進行操作;
NAME = ['xiaofei', 'hkey']
def test():
NAME.append('sky')
print('name:', NAME)
test()
# 執行結果:
# name: ['xiaofei', 'hkey', 'sky']
如果函數內有 global 關鍵字
(1)有聲明局部變量
NAME = ['xiaofei', 'hkey']
def test():
# 獲取全局變量 NAME
global NAME
# 打印全局變量 NAME
print('global NAME:', NAME)
# 將全局變量 NAME 修改為 'test_func'
NAME = 'test_func'
# 打印修改后的全局變量
print('name:', NAME)
test()
# 執行結果:
# global NAME: ['xiaofei', 'hkey']
(2)無聲明局部變量
NAME = ['xiaofei', 'hkey']
def test():
# 獲取全局變量 NAME
global NAME
# 打印全局變量 NAME
print(NAME)
# 修改全局變量為 ['sky']
NAME = ['sky']
# 追加全局變量
NAME.append('blue')
# 打印修改后的全局變量
print(NAME)
test()
# 執行結果:
##['sky','blue']
在代碼中我們規定,全局變量名全部使用大寫,而局部變量用小寫,這邊就避免變量名的混淆;
(3)nonlocal 關鍵字用來在函數或者其他作用域中使用外層變量
def outer(): num = 10 def inner(): nonlocal num # nonlocal 關鍵字聲明 num = 100 # 修改作用域 num 使用方法和 global 一致 print(num) inner() print(num) # 該 num 已經在 inner() 中修改過的 outer() # 執行結果: # 100 # 100
5. 遞歸函數
(1)函數即變量
def test(): pass t = test # 把函數當作值 賦值給變量 t print(t) # 執行結果: # <function test at 0x00000245A2FBA048>
(2)遞歸函數
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
遞歸函數的優點是定義簡單,邏輯清晰。理論上,所有的遞歸函數都寫成循環的方式,但循環的邏輯不如遞歸清晰。
def fact(n): if n == 1: return 1 return n * fact(n - 1) print(fact(5)) # 執行過程如下: # # ===> fact(5) # ===> 5 * fact(4) # ===> 5 * (4 * fact(3)) # ===> 5 * (4 * (3 * fact(2))) # ===> 5 * (4 * (3 * (2 * fact(1)))) # ===> 5 * (4 * (3 * (2 * 1))) # ===> 5 * (4 * (3 * 2)) # ===> 5 * (4 * 6) # ===> 5 * 24 # ===> 120
遞歸函數就像問路一樣,有去有回。A問B,B在問C,C知道答案返回給B,B在返回給A
必須有一個明確的結束條件
每次進入更深一層的遞歸時,問題規模相比上次遞歸應有所減少
遞歸效率不高
(3)尾遞歸優化
尾遞歸是指,在函數返回的時候,調用自身本身,並且,return 語句不能包含表達式。
def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product # return 語句不能包含表達式。遞歸本身無論調用多少次,都只占用一個棧幀 return fact_iter(num - 1, num * product) # 運行過程: # fact(5) # ===> fact_iter(5, 1) # ===> fact_iter(4, 5) # ===> fact_iter(3, 20) # ===> fact_iter(2, 60) # ===> fact_iter(1, 120) # ===>120
