溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

發(fā)布時(shí)間:2020-08-11 15:47:03 來源:ITPUB博客 閱讀:186 作者:千鋒Python唐小強(qiáng) 欄目:編程語言

字符串和常用數(shù)據(jù)結(jié)構(gòu)

使用字符串

第二次世界大戰(zhàn)促使了現(xiàn)代電子計(jì)算機(jī)的誕生,當(dāng)初的想法很簡單,就是用計(jì)算機(jī)來計(jì)算的彈道,因此在計(jì)算機(jī)剛剛誕生的那個(gè)年代,計(jì)算機(jī)處理的信息主要是數(shù)值,而世界上的第一臺(tái)電子計(jì)算機(jī)ENIAC每秒鐘能夠完成約5000次浮點(diǎn)運(yùn)算。隨著時(shí)間的推移,雖然對(duì)數(shù)值運(yùn)算仍然是計(jì)算機(jī)日常工作中最為重要的事情之一,但是今天的計(jì)算機(jī)處理得更多的數(shù)據(jù)都是以文本信息的方式存在的,而Python表示文本信息的方式我們?cè)诤茉缫郧熬驼f過了,那就是字符串類型。所謂 字符串 ,就是由零個(gè)或多個(gè)字符組成的有限序列,一般記為 Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

我們可以通過下面的代碼來了解字符串的使用。

def main():
    str1 = 'hello, world!'
    # 通過len函數(shù)計(jì)算字符串的長度
    print(len(str1))  # 13
    # 獲得字符串首字母大寫的拷貝
    print(str1.capitalize())  # Hello, world!
    # 獲得字符串變大寫后的拷貝
    print(str1.upper())  # HELLO, WORLD!
    # 從字符串中查找子串所在位置
    print(str1.find('or'))  # 8
    print(str1.find('shit'))  # -1
    # 與find類似但找不到子串時(shí)會(huì)引發(fā)異常
    # print(str1.index('or'))
    # print(str1.index('shit'))
    # 檢查字符串是否以指定的字符串開頭
    print(str1.startswith('He'))  # False
    print(str1.startswith('hel'))  # True
    # 檢查字符串是否以指定的字符串結(jié)尾
    print(str1.endswith('!'))  # True
    # 將字符串以指定的寬度居中并在兩側(cè)填充指定的字符
    print(str1.center(50, '*'))    # 將字符串以指定的寬度靠右放置左側(cè)填充指定的字符
    print(str1.rjust(50, ' '))
    str2 = 'abc123456'
    # 從字符串中取出指定位置的字符(下標(biāo)運(yùn)算)
    print(str2[2])  # c
    # 字符串切片(從指定的開始索引到指定的結(jié)束索引)
    print(str2[2:5])  # c12
    print(str2[2:])  # c123456
    print(str2[2::2])  # c246
    print(str2[::2])  # ac246
    print(str2[::-1])  # 654321cba
    print(str2[-3:-1])  # 45
    # 檢查字符串是否由數(shù)字構(gòu)成
    print(str2.isdigit())  # False
    # 檢查字符串是否以字母構(gòu)成
    print(str2.isalpha())  # False
    # 檢查字符串是否以數(shù)字和字母構(gòu)成
    print(str2.isalnum())  # True
    str3 = '  jackfrued@126.com '
    print(str3)    # 獲得字符串修剪左右兩側(cè)空格的拷貝
    print(str3.strip())if __name__ == '__main__':
    main()

除了字符串,Python還內(nèi)置了多種類型的數(shù)據(jù)結(jié)構(gòu),如果要在程序中保存和操作數(shù)據(jù),絕大多數(shù)時(shí)候可以利用現(xiàn)有的數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn),最常用的包括列表、元組、集合和字典。

使用列表

下面的代碼演示了如何定義列表、使用下標(biāo)訪問列表元素以及添加和刪除元素的操作。

def main():
    list1 = [1, 3, 5, 7, 100]    print(list1)
    list2 = ['hello'] * 5
    print(list2)    # 計(jì)算列表長度(元素個(gè)數(shù))
    print(len(list1))    # 下標(biāo)(索引)運(yùn)算
    print(list1[0])    print(list1[4])    # print(list1[5])  # IndexError: list index out of range
    print(list1[-1])    print(list1[-3])
    list1[2] = 300
    print(list1)    # 添加元素
    list1.append(200)
    list1.insert(1, 400)
    list1 += [1000, 2000]    print(list1)    print(len(list1))    # 刪除元素
    list1.remove(3)    if 1234 in list1:
        list1.remove(1234)    del list1[0]    print(list1)    # 清空列表元素
    list1.clear()    print(list1)if __name__ == '__main__':
    main()

和字符串一樣,列表也可以做切片操作,通過切片操作我們可以實(shí)現(xiàn)對(duì)列表的復(fù)制或者將列表中的一部分取出來創(chuàng)建出新的列表,代碼如下所示。

def main():
    fruits = ['grape', 'apple', 'strawberry', 'waxberry']
	fruits += ['pitaya', 'pear', 'mango']	# 循環(huán)遍歷列表元素
    for fruit in fruits:        print(fruit.title(), end=' ')    print()    # 列表切片
    fruits2 = fruits[1:4]    print(fruits2)    # fruit3 = fruits  # 沒有復(fù)制列表只創(chuàng)建了新的引用
    # 可以通過完整切片操作來復(fù)制列表
    fruits3 = fruits[:]    print(fruits3)
    fruits4 = fruits[-3:-1]    print(fruits4)    # 可以通過反向切片操作來獲得倒轉(zhuǎn)后的列表的拷貝
    fruits5 = fruits[::-1]    print(fruits5)if __name__ == '__main__':
    main()

下面的代碼實(shí)現(xiàn)了對(duì)列表的排序操作。

def main():
    list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
    list2 = sorted(list1)    # sorted函數(shù)返回列表排序后的拷貝不會(huì)修改傳入的列表
    # 函數(shù)的設(shè)計(jì)就應(yīng)該像sorted函數(shù)一樣盡可能不產(chǎn)生副作用
    list3 = sorted(list1, reverse=True)    # 通過key關(guān)鍵字參數(shù)指定根據(jù)字符串長度進(jìn)行排序而不是默認(rèn)的字母表順序
    list4 = sorted(list1, key=len)    print(list1)    print(list2)    print(list3)    print(list4)    # 給列表對(duì)象發(fā)出排序消息直接在列表對(duì)象上進(jìn)行排序
    list1.sort(reverse=True)    print(list1)if __name__ == '__main__':
    main()

我們還可以使用列表的生成式語法來創(chuàng)建列表,代碼如下所示。

import sysdef main():
    f = [x for x in range(1, 10)]    print(f)
    f = [x + y for x in 'ABCDE' for y in '1234567']    print(f)    # 用列表的生成表達(dá)式語法創(chuàng)建列表容器
    # 用這種語法創(chuàng)建列表之后元素已經(jīng)準(zhǔn)備就緒所以需要耗費(fèi)較多的內(nèi)存空間
    f = [x ** 2 for x in range(1, 1000)]    print(sys.getsizeof(f))  # 查看對(duì)象占用內(nèi)存的字節(jié)數(shù)
    print(f)    # 請(qǐng)注意下面的代碼創(chuàng)建的不是一個(gè)列表而是一個(gè)生成器對(duì)象
    # 通過生成器可以獲取到數(shù)據(jù)但它不占用額外的空間存儲(chǔ)數(shù)據(jù)
    # 每次需要數(shù)據(jù)的時(shí)候就通過內(nèi)部的運(yùn)算得到數(shù)據(jù)(需要花費(fèi)額外的時(shí)間)
    f = (x ** 2 for x in range(1, 1000))    print(sys.getsizeof(f))  # 相比生成式生成器不占用存儲(chǔ)數(shù)據(jù)的空間
    print(f)    for val in f:        print(val)if __name__ == '__main__':
    main()

除了上面提到的生成器語法,Python中還有另外一種定義生成器的方式,就是通過 yield 關(guān)鍵字將一個(gè)普通函數(shù)改造成生成器函數(shù)。下面的代碼演示了如何實(shí)現(xiàn)一個(gè)生成 斐波拉切數(shù)列 的生成器。所謂斐波拉切數(shù)列可以通過下面 遞歸 的方法來進(jìn)行定義:

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b        yield adef main():    for val in fib(20):        print(val)if __name__ == '__main__':
    main()

使用元組

Python 的元組與列表類似,不同之處在于元組的元素不能修改,在前面的代碼中我們已經(jīng)不止一次使用過元組了。顧名思義,我們把多個(gè)元素組合到一起就形成了一個(gè)元組,所以它和列表一樣可以保存多條數(shù)據(jù)。下面的代碼演示了如何定義和使用元組。

def main():    # 定義元組
    t = ('駱昊', 38, True, '四川成都')    print(t)    # 獲取元組中的元素
    print(t[0])    print(t[3])    # 遍歷元組中的值
    for member in t:        print(member)    # 重新給元組賦值
    # t[0] = '王大錘'  # TypeError
    # 變量t重新引用了新的元組原來的元組將被垃圾回收
    t = ('王大錘', 20, True, '云南昆明')    print(t)    # 將元組轉(zhuǎn)換成列表
    person = list(t)    print(person)    # 列表是可以修改它的元素的
    person[0] = '李小龍'
    person[1] = 25
    print(person)    # 將列表轉(zhuǎn)換成元組
    fruits_list = ['apple', 'banana', 'orange']
    fruits_tuple = tuple(fruits_list)    print(fruits_tuple)if __name__ == '__main__':
    main()

這里有一個(gè)非常值得探討的問題,我們已經(jīng)有了列表這種數(shù)據(jù)結(jié)構(gòu),為什么還需要元組這樣的類型呢?

  1. 元組中的元素是無法修改的,事實(shí)上我們?cè)陧?xiàng)目中尤其是 多線程 環(huán)境(后面會(huì)講到)中可能更喜歡使用的是那些不變對(duì)象(一方面因?yàn)閷?duì)象狀態(tài)不能修改,所以可以避免由此引起的不必要的程序錯(cuò)誤,簡單的說就是一個(gè)不變的對(duì)象要比可變的對(duì)象更加容易維護(hù);另一方面因?yàn)闆]有任何一個(gè)線程能夠修改不變對(duì)象的內(nèi)部狀態(tài),一個(gè)不變對(duì)象自動(dòng)就是線程安全的,這樣就可以省掉處理同步化的開銷。一個(gè)不變對(duì)象可以方便的被共享訪問)。所以結(jié)論就是:如果不需要對(duì)元素進(jìn)行添加、刪除、修改的時(shí)候,可以考慮使用元組,當(dāng)然如果一個(gè)方法要返回多個(gè)值,使用元組也是不錯(cuò)的選擇。
  2. 元組在創(chuàng)建時(shí)間和占用的空間上面都優(yōu)于列表。我們可以使用sys模塊的getsizeof函數(shù)來檢查存儲(chǔ)同樣的元素的元組和列表各自占用了多少內(nèi)存空間,這個(gè)很容易做到。我們也可以在ipython中使用魔法指令%timeit來分析創(chuàng)建同樣內(nèi)容的元組和列表所花費(fèi)的時(shí)間,下圖是我的macOS系統(tǒng)上測試的結(jié)果。

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

使用集合

Python中的集合跟數(shù)學(xué)上的集合是一致的,不允許有重復(fù)元素,而且可以進(jìn)行交集、并集、差集等運(yùn)算。

Python學(xué)習(xí)教程100天(Python學(xué)習(xí)路線):Day07字符串和常用數(shù)據(jù)結(jié)構(gòu)

def main():
    set1 = {1, 2, 3, 3, 3, 2}    print(set1)    print('Length =', len(set1))
    set2 = set(range(1, 10))    print(set2)
    set1.add(4)
    set1.add(5)
    set2.update([11, 12])    print(set1)    print(set2)
    set2.discard(5)    # remove的元素如果不存在會(huì)引發(fā)KeyError
    if 4 in set2:
        set2.remove(4)    print(set2)    # 遍歷集合容器
    for elem in set2:        print(elem ** 2, end=' ')    print()    # 將元組轉(zhuǎn)換成集合
    set3 = set((1, 2, 3, 3, 2, 1))    print(set3.pop())    print(set3)    # 集合的交集、并集、差集、對(duì)稱差運(yùn)算
    print(set1 & set2)    # print(set1.intersection(set2))
    print(set1 | set2)    # print(set1.union(set2))
    print(set1 - set2)    # print(set1.difference(set2))
    print(set1 ^ set2)    # print(set1.symmetric_difference(set2))
    # 判斷子集和超集
    print(set2 <= set1)    # print(set2.issubset(set1))
    print(set3 <= set1)    # print(set3.issubset(set1))
    print(set1 >= set2)    # print(set1.issuperset(set2))
    print(set1 >= set3)    # print(set1.issuperset(set3))if __name__ == '__main__':
    main()

說明:  Python中允許通過一些特殊的方法來為某種類型或數(shù)據(jù)結(jié)構(gòu)自定義運(yùn)算符(后面的章節(jié)中會(huì)講到),上面的代碼中我們對(duì)集合進(jìn)行運(yùn)算的時(shí)候可以調(diào)用集合對(duì)象的方法,也可以直接使用對(duì)應(yīng)的運(yùn)算符,例如 & 運(yùn)算符跟intersection方法的作用就是一樣的,但是使用運(yùn)算符讓代碼更加直觀。

使用字典

字典是另一種可變?nèi)萜髂P停愃朴谖覀兩钪惺褂玫淖值?,它可以存?chǔ)任意類型對(duì)象,與列表、集合不同的是,字典的每個(gè)元素都是由一個(gè)鍵和一個(gè)值組成的“鍵值對(duì)”,鍵和值通過冒號(hào)分開。下面的代碼演示了如何定義和使用字典。

def main():
    scores = {'駱昊': 95, '白元芳': 78, '狄仁杰': 82}    # 通過鍵可以獲取字典中對(duì)應(yīng)的值
    print(scores['駱昊'])    print(scores['狄仁杰'])    # 對(duì)字典進(jìn)行遍歷(遍歷的其實(shí)是鍵再通過鍵取對(duì)應(yīng)的值)
    for elem in scores:        print('%s\t--->\t%d' % (elem, scores[elem]))    # 更新字典中的元素
    scores['白元芳'] = 65
    scores['諸葛王朗'] = 71
    scores.update(冷面=67, 方啟鶴=85)    print(scores)    if '武則天' in scores:        print(scores['武則天'])    print(scores.get('武則天'))    # get方法也是通過鍵獲取對(duì)應(yīng)的值但是可以設(shè)置默認(rèn)值
    print(scores.get('武則天', 60))    # 刪除字典中的元素
    print(scores.popitem())    print(scores.popitem())    print(scores.pop('駱昊', 100))    # 清空字典
    scores.clear()    print(scores)if __name__ == '__main__':
    main()

練習(xí)

練習(xí)1:在屏幕上顯示跑馬燈文字
import osimport timedef main():
    content = '北京歡迎你為你開天辟地…………'
    while True:        # 清理屏幕上的輸出
        os.system('cls')  # os.system('clear')
        print(content)        # 休眠200毫秒
        time.sleep(0.2)
        content = content[1:] + content[0]if __name__ == '__main__':
    main()
練習(xí)2:設(shè)計(jì)一個(gè)函數(shù)產(chǎn)生指定長度的驗(yàn)證碼,驗(yàn)證碼由大小寫字母和數(shù)字構(gòu)成。
import randomdef generate_code(code_len=4):    """    生成指定長度的驗(yàn)證碼    :param code_len: 驗(yàn)證碼的長度(默認(rèn)4個(gè)字符)    :return: 由大小寫英文字母和數(shù)字構(gòu)成的隨機(jī)驗(yàn)證碼    """
    all_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    last_pos = len(all_chars) - 1
    code = ''
    for _ in range(code_len):
        index = random.randint(0, last_pos)
        code += all_chars[index]    return code
練習(xí)3:設(shè)計(jì)一個(gè)函數(shù)返回給定文件名的后綴名。
def get_suffix(filename, has_dot=False):    """    獲取文件名的后綴名    :param filename: 文件名    :param has_dot: 返回的后綴名是否需要帶點(diǎn)    :return: 文件的后綴名    """
    pos = filename.rfind('.')    if 0 < pos < len(filename) - 1:
        index = pos if has_dot else pos + 1
        return filename[index:]    else:        return ''
練習(xí)4:設(shè)計(jì)一個(gè)函數(shù)返回傳入的列表中最大和第二大的元素的值。
def max2(x):
    m1, m2 = (x[0], x[1]) if x[0] > x[1] else (x[1], x[0])    for index in range(2, len(x)):        if x[index] > m1:
            m2 = m1
            m1 = x[index]        elif x[index] > m2:
            m2 = x[index]    return m1, m2
練習(xí)5:計(jì)算指定的年月日是這一年的第幾天
def is_leap_year(year):    """    判斷指定的年份是不是閏年    :param year: 年份    :return: 閏年返回True平年返回False    """
    return year % 4 == 0 and year % 100 != 0 or year % 400 == 0def which_day(year, month, date):    """    計(jì)算傳入的日期是這一年的第幾天    :param year: 年    :param month: 月    :param date: 日    :return: 第幾天    """
    days_of_month = [
        [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
        [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    ][is_leap_year(year)]
    total = 0
    for index in range(month - 1):
        total += days_of_month[index]    return total + datedef main():    print(which_day(1980, 11, 28))    print(which_day(1981, 12, 31))    print(which_day(2018, 1, 1))    print(which_day(2016, 3, 1))if __name__ == '__main__':
    main()
練習(xí)6:打印 楊輝三角 。
def main():
    num = int(input('Number of rows: '))
    yh = [[]] * num    for row in range(len(yh)):
        yh[row] = [None] * (row + 1)        for col in range(len(yh[row])):            if col == 0 or col == row:
                yh[row][col] = 1
            else:
                yh[row][col] = yh[row - 1][col] + yh[row - 1][col - 1]            print(yh[row][col], end='\t')        print()if __name__ == '__main__':
    main()

綜合案例

案例1:雙色球選號(hào)
from random import randrange, randint, sampledef display(balls):    """    輸出列表中的雙色球號(hào)碼    """
    for index, ball in enumerate(balls):        if index == len(balls) - 1:            print('|', end=' ')        print('%02d' % ball, end=' ')    print()def random_select():    """    隨機(jī)選擇一組號(hào)碼    """
    red_balls = [x for x in range(1, 34)]
    selected_balls = []
    selected_balls = sample(red_balls, 6)
    selected_balls.sort()
    selected_balls.append(randint(1, 16))    return selected_ballsdef main():
    n = int(input('機(jī)選幾注: '))    for _ in range(n):
        display(random_select())if __name__ == '__main__':
    main()

說明:  上面使用random模塊的sample函數(shù)來實(shí)現(xiàn)從列表中選擇不重復(fù)的n個(gè)元素。

綜合案例2: 約瑟夫環(huán)問題
"""《幸運(yùn)的基督徒》有15個(gè)基督徒和15個(gè)非基督徒在海上遇險(xiǎn),為了能讓一部分人活下來不得不將其中15個(gè)人扔到海里面去,有個(gè)人想了個(gè)辦法就是大家圍成一個(gè)圈,由某個(gè)人開始從1報(bào)數(shù),報(bào)到9的人就扔到海里面,他后面的人接著從1開始報(bào)數(shù),報(bào)到9的人繼續(xù)扔到海里面,直到扔掉15個(gè)人。由于上帝的保佑,15個(gè)基督徒都幸免于難,問這些人最開始是怎么站的,哪些位置是基督徒哪些位置是非基督徒。"""def main():
    persons = [True] * 30
    counter, index, number = 0, 0, 0
    while counter < 15:        if persons[index]:
            number += 1
            if number == 9:
                persons[index] = False
                counter += 1
                number = 0
        index += 1
        index %= 30
    for person in persons:        print('基' if person else '非', end='')if __name__ == '__main__':
    main()
綜合案例3: 井字棋 游戲
import osdef print_board(board):    print(board['TL'] + '|' + board['TM'] + '|' + board['TR'])    print('-+-+-')    print(board['ML'] + '|' + board['MM'] + '|' + board['MR'])    print('-+-+-')    print(board['BL'] + '|' + board['BM'] + '|' + board['BR'])def main():
    init_board = {        'TL': ' ', 'TM': ' ', 'TR': ' ',        'ML': ' ', 'MM': ' ', 'MR': ' ',        'BL': ' ', 'BM': ' ', 'BR': ' '
    }
    begin = True
    while begin:
        curr_board = init_board.copy()
        begin = False
        turn = 'x'
        counter = 0
        os.system('clear')
        print_board(curr_board)        while counter < 9:
            move = input('輪到%s走棋, 請(qǐng)輸入位置: ' % turn)            if curr_board[move] == ' ':
                counter += 1
                curr_board[move] = turn                if turn == 'x':
                    turn = 'o'
                else:
                    turn = 'x'
            os.system('clear')
            print_board(curr_board)
        choice = input('再玩一局?(yes|no)')
        begin = choice == 'yes'if __name__ == '__main__':
    main()

說明:  最后這個(gè)案例來自 《Python編程快速上手:讓繁瑣工作自動(dòng)化》 一書(這本書對(duì)有編程基礎(chǔ)想迅速使用Python將日常工作自動(dòng)化的人來說還是不錯(cuò)的選擇),對(duì)代碼做了一點(diǎn)點(diǎn)的調(diào)整。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI