3.3.python_列表/字典基礎

環境: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
-+-+-

嘿, 是一把平局!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值