環境:python 3.10 + Win10
列表/元組/字典是python基于int/float/str這三種更低級類型設置的更高級的數據形態.
1.列表, list
python列表是有序的, 動態長度的, 元素類型不限的一種數據結構, 基本格式爲:
list_ = [elem_1, elem_2, ...]
1.1.創建列表
創建空列表,使用方括號[]括起:
guests = []
初始化列表元素時, 各元素之間以逗號間隔, 外圍使用方括號[]括起:
guests = [4, "愛因斯坦", "梵高", "王小波", "江青"]
1.2.訪問列表元素
1.2.1.使用偏移量訪問單个元素
因爲列表是多个元素的有序集合, 所以可以通過各个元素的'所在位置'來區分它們, 也就是使用索引值, 或者叫偏移量更易理解些. 偏移量是指某个元素距離起點元素的距離, 比如:
>>> guests = [4, "愛因斯坦", "梵高", "王小波", "江青"]
>>> guests[0] # 元素4就在起點, 所以偏移量爲0
4
>>> guests[3] # 元素'王小波'的偏移量爲3
'王小波'
>>> guests[-1] # 偏移量爲負數時表示倒序計數, [-1]是倒數第一个, 即元素'江青'
'江青'
使用負數偏移量[-n]的形式便于在不確定列表長度的情況下準確訪問某些元素.
1.2.2.使用切片訪問多个元素
切片是指列表的子集, 訪問時寫明偏移量範圍, [:], 如下:
>>> guests[0:3] # 從偏移量0到(3-1)的元素
[4, '愛因斯坦', '梵高']
>>> guests[:3]
[4, '愛因斯坦', '梵高'] # 冒號左側省略等效于切片起點爲0
>>> guests[:] # 冒號左右兩側皆省略, 表示整个列表的副本
[4, '愛因斯坦', '梵高', '王小波', '江青']
>>> guests[3:] # 從偏移量3到結尾的元素
['王小波', '江青']
>>> guests[::2] # 第三个值2表示步長, 即每2个偏移量返回1个元素, 特殊用法
[4, '梵高', '江青']
>>> guests[::-1] # 倒序返回整个列表, 步長爲負數表示倒序返回, 特殊用法
['江青', '王小波', '梵高', '愛因斯坦', 4]
1.3.列表操作, 基于各種列表方法
1.3.1.修改元素
>>> guests[-1] = '陳圓圓'
>>> guests
[4, '愛因斯坦', '梵高', '王小波', '陳圓圓']
1.3.2.增加元素
在尾部添加元素, 使用append()方法:
>>> guests.append('孫悟空')
>>> guests[0] += 1
>>> guests
[5, '愛因斯坦', '梵高', '王小波', '陳圓圓', '孫悟空']
在列表任意位置插入元素, 使用insert()方法, 第一个參數表示偏移量, 第二个參數表示待插入對象:
>>> guests.insert(3, 'Messi') # 在列表偏移量爲3的位置插入元素, 後續元素依次後移
>>> guests[0] = len(guests) - 1
>>> guests
[6, '愛因斯坦', '梵高', 'Messi', '王小波', '陳圓圓', '孫悟空']
1.3.3.刪除元素
列表元素的刪除有三種操作方式, 可以視情況選用:
在確定偏移量的前提下, 使用del語句, 刪除特定位置的元素:
>>> del guests[4] # 刪除偏移量爲4的元素
>>> guests
[6, '愛因斯坦', '梵高', 'Messi', '陳圓圓', '孫悟空']
在無法確定位置的情況下, 根據值刪除元素, 使用remove()方法:
>>> guests.remove('孫悟空') # 刪除'孫悟空'那一項
>>> guests.remove(6) # 刪除6那一項
>>> guests
['愛因斯坦', '梵高', 'Messi', '陳圓圓']
刪除末位的元素, 並返回該元素, 使用pop()方法:
>>> sorry_guest = guests.pop()
>>> print(f'抱歉, 改天再聚啊{sorry_guest}.')
抱歉, 改天再聚啊陳圓圓.
>>> print(f'現在還剩下{guests}')
現在還剩下['愛因斯坦', '梵高', 'Messi']
pop()方法類似出棧操作, 因爲是有返回值的, 所以可賦值給其它變量, 同時列表中該元素被刪除.
pop()方法可接受一个數值, 彈出特定位置的元素:
>>> sorry_guest = guests.pop(0)
>>> print(f'抱歉, 改天再聚啊{sorry_guest}.')
抱歉, 改天再聚啊愛因斯坦.
>>> print(f'現在還剩下{guests}')
現在還剩下['梵高', 'Messi']
注意, pop()方法移除的元素的值可再次使用, 而del語句就沒這麼靈活.
1.3.4.列表的合並
類似于字符串, 合並兩个列表時, 也可以使用+; 單个列表的元素重復增長時, 使用*:
>>> num = [1, 2, 3, 4]
>>> new_num = num + [5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
>>> new_num*2
[1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]
1.3.5.求列表值的索引
使用index()方法, 當有多个相同值時, 返回第一个匹配值的索引:
>>> list_a = [2,3,43,3,9]
>>> list_a.index(2)
0
>>> list_a.index(3)
1
2.字典
字典是python中作用廣泛的一種數據結構, 字典是動態的, 理論上長度無上限, 基本格式爲:
dictionary_ = {key_1:value_1, key_2:value_2, ...}
字典的本質是一系列鍵值對, 鍵(key)與值(value)一一對應, 通過鍵來訪問與之對應的值. 在特定字典內, 每个鍵都是不同的字符串, 對應的值可以是數值/字符串/列表乃至另一个字典, 即值可爲任意python對象.
2.1.創建字典
創建空字典時, 使用花括號{}
dict_ = {}
字典初始化, 鍵與值用冒號:連接, 鍵值對之間用逗號,隔開, 如:
philosopher = {'姓名':'李聃', '性別':'男', '著作':'道德經', '壽命':89}
訪問字典特定項時, 採用dict_[key]的方式, 如: print(philosopher['姓名'])
注意, 字典不支持通過索引值(下標法)訪問.
2.2.字典操作, 基于各種字典方法
字典的操作包括: 添加/修改/刪除/遍歷/排序和去重.
2.2.1.添加鍵值對
添加新鍵值對時, 使用 dict_[new_key} = value 語句, 如:
philosopher['國別'] = '古中國'
如果是嚴謹的代碼, 得先檢查是否已存在同名鍵, 不然就變成了修改值, 而非添加鍵值對.
setdefault()方法就是比較保守的添加方法, 作用是確保將一个名稱(字符串)作爲鍵添加到字典, 同時指定值, 當鍵名已存在時, 調用不產生副作用. 如下面的例子, 當'name'鍵已存在, 調用該方法試圖添加新鍵值對, 但最終並未修改原字典:
dict = {'name':'契丹'}
dict.setdefault('as', '南俄') # 此時等價于dict['as']='南俄'
dict.setdefault('name', '嘿嘿') # 在字典中已存在鍵名('name')時, 方法調用無副作用
print(dict) # {'name': '契丹', 'as': '南俄'}
----setdefault()代碼案例: 統計字符----
# 字符統計
import pprint # 導入漂亮打印模凷, pprint即pretty-print
# 統計英文字符
message = 'This is a text, and i want to count it!'
count = {} # 創建空的字典
for char in message:
count.setdefault(char, 0) # 使用setdefault()方法確保將字符作爲鍵(key)添加到字典
count[char] += 1 # 在不使用setdefault()方法時, 會報錯: KeyError: 'T'
# 統計漢字
message_ch = '這是一段待測試的中文語句, python也能正確讀取. 不過對于太短的文段, 就中文本身的特性而言, 並無太大的統計意義!'
count_ch = {} # 創建空的字典
for ch in message_ch:
count_ch.setdefault(ch, 0) # 使用setdefault()方法確保將漢字作爲鍵(key)添加到字典
count_ch[ch] += 1
# 使用漂亮打印輸出結果
pprint.pp(count) # .pp()等價于.pprint()
pprint.pp(count_ch)
# {'T': 1,
# 'h': 1,
# 'i': 4,
# ...
# {'這': 1,
# '是': 1,
# '一': 1,
# '段': 2,
# '待': 1,
# '測': 1,
# '試': 1,
# '的': 4,
# ...
2.2.2.修改值
修改值時, 通過鍵名重新賦值即可, 如:
joke = {'蘇聯笑話':'****', '等級':'19+'}
joke['蘇聯笑話'] = '斯大林同志在基輔'
2.2.3.刪除鍵值對
使用del dict_[key]語句刪除原字典中的特定鍵值對, 如:
...
del joke['蘇聯笑話'] # 連同對應的值一併刪除, 剩下{'等級':'19+'}
2.2.4.遍歷字典
遍歷鍵, 在無需值的場合, 使用keys()方法結合for結構:
alpha = {'c':3, 'a':1, 'f':6, 'b':2}
for key in alpha.keys():
print(key, end=' ')
# c a f b
遍歷值, 在無需鍵的場合, 使用values()方法結合for結構:
alpha = {'c':3, 'a':1, 'f':6, 'b':2}
for value in alpha.values():
print(value, end=' ')
# 3 1 6 2
遍歷鍵值對, 使用items()方法結合for結構:
alpha = {'c':3, 'a':1, 'f':6, 'b':2}
for key, value in alpha.items():
print(key, value, sep=':', end=' ')
# c:3 a:1 f:6 b:2
2.2.5.排序鍵和去重值
考慮到值類型的多樣化, 而鍵都是字符串, 所以排序僅對鍵有確切意義, 調用keys()方法獲取鍵名(返回列表), 再使用python內置的sorted()函數排序, 如下:
alpha = {'c':3, 'a':1, 'f':6, 'b':2}
keys_list = sorted(alpha.keys()) # 排序生成的鍵列表: ['a', 'b', 'c', 'f']
print(alpha) # {'c': 3, 'a': 1, 'f': 6, 'b': 2}, 不改變原字典
由于鍵名的不重復, 去重操作僅對值有意義, 調用values()方法獲取值列表, 再調用set()函數去重, 如下:
alpha = {'c':3, 'a':1, 'f':6, 'b':2, 'B':2}
values_list = set(alpha.values()) # 生成去重的值列表: [3, 1, 6, 2]
print(alpha) # {'c': 3, 'a': 1, 'f': 6, 'b': 2}, 不改變原字典
2.2.6.拼接字典, 使用update()方法
>>> dic_1 = {'a':0, 'b':1, 'c':2}
>>> dic_2 = {'d':3, 'e':4, 'f':5}
>>> dic_1.update(dic_2)
>>> dic_1
{'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5} #拼接在原字典之後
3.代碼案例:
----#字棋代碼案例:----
代碼分爲兩个文件:main.py和function.py, 後者是負責檢查落子/更新/打印/檢查勝局的函數的定義所在的文件.
main.py:
# #字棋遊戲, main.py
from function import * # 導入function.py中的所有函數
# 描述規則, 創建棋盤對象(字典)
print('懽迎來玩井字棋遊戲!\n遊戲規則是兩人交替落子, 先將三子達成一條線的玩家獲勝!')
board = {
'1': '1', '2': '2', '3': '3',
'4': '4', '5': '5', '6': '6',
'7': '7', '8': '8', '9': '9'
}
print_board(board)
# 獲取用戶名及創建必要變量
player_1 = input('請輸入一號玩家的名字:')
player_2 = input('請輸入二號玩家的名字:')
winner = '' # 出現贏家時儲存贏家名, 初始化爲空
go = [] # 儲存落點, 使用列表便于檢查是否重復
game_state = 'ongoing' # 默認遊戲狀態爲ongoing, 出現贏家時爲win, 平局時爲draw
# 遊戲主循環
while True:
check_move(player_1, go, board, 'O') # 檢查1號玩家落子並更新棋盤
print_board(board) # 打印棋盤
game_state = check_win(board, len(go)) # 檢查是否獲勝
if game_state == 'win':
winner = player_1
break
elif game_state:
break
check_move(player_2, go, board, 'X') # 檢查2號玩家落子並更新棋盤
print_board(board)
game_state = check_win(board, len(go)) # 檢查是否獲勝
if game_state:
winner = player_2
break
elif game_state:
break
# 輸出結果
if winner:
print('\n恭喜{}, 你贏啦!!!'.format(winner))
else:
print('\n嘿, 是一把平局!!!')
function.py:
def print_board(board):
"""打印棋盤"""
print(board['1'] + '|' + board['2'] + '|' + board['3'])
print('-+-+-')
print(board['4'] + '|' + board['5'] + '|' + board['6'])
print('-+-+-')
print(board['7'] + '|' + board['8'] + '|' + board['9'])
print('-+-+-')
def check_move(player, go, board, chess):
"""
檢查輸入的格子是否有效:
1.不能在同一位置再次落子,
2.輸入需爲數字(即值爲board的鍵之一)
"""
while True:
move = input('請{}落子({}):'.format(player, chess)) # 提示玩家落子
if move in board.keys() and move not in go: # 檢查是否輸入了有效的格子
go.append(move)
board[go[-1]] = chess # 在輸入無誤的情況下, 將1號玩家選擇的格子更改爲O
break
else:
print('請輸入未佔用的棋盤格子的序號!!!') # 落子錯誤提示
continue
def check_win(board, times):
"""檢查獲勝狀態"""
if ((((((((board['1'] == board['2'] and board['2'] == board['3']) or
(board['1'] == board['4'] and board['4'] == board['7'])) or
(board['1'] == board['5'] and board['5'] == board['9'])) or
(board['2'] == board['5'] and board['5'] == board['8'])) or
(board['3'] == board['6'] and board['6'] == board['9'])) or
(board['4'] == board['5'] and board['5'] == board['6'])) or
(board['7'] == board['5'] and board['5'] == board['3'])) or
(board['7'] == board['8'] and board['8'] == board['9'])):
return 'win'
elif times == 9: # 3*3棋盤的步數上限爲9, 達到上限時爲平局
return 'draw'
check_win()中的判定是羅列所有獲勝的情況, 暫時沒想到簡洁的方法, 哈哈哈, 其實, 這麼多括號((((...))))在編輯器安裝有彩虹括號的插件時, 非常漂亮, 嗯.
遊戲過程全程在終端中進行, 大概如下:
懽迎來玩井字棋遊戲!
遊戲規則是兩人交替落子, 先將三子達成一條線的玩家獲勝!
1|2|3
-+-+-
4|5|6
-+-+-
7|8|9
-+-+-
請輸入一號玩家的名字:第一个人
請輸入二號玩家的名字:第二个人
...
請第二个人落子(X):8
O|O|X
-+-+-
X|X|O
-+-+-
O|X|9
-+-+-
請第一个人落子(O):9
O|O|X
-+-+-
X|X|O
-+-+-
O|X|O
-+-+-
嘿, 是一把平局!!!