溫故而知新--day1
變數型別
變數是計算機存盤資料的記憶體空間,由于計算機可以處理不同的資料,不同的資料就要定義不同的資料型別,python的資料型別很多,還可以自定義資料型別,常用的一般資料型別有以下幾種:
- 整型:
- 在python2版本中有long和int之分,但到了python3中就只有int了,
- 除此之外,整型還有進制的概念:二進制:
0b10表示十進制2,八進制:0o10表示十進制8,十進制:10,十六進制:0x10表示十進制16
- 浮點型:
- 即float,也就是小數,稱之為浮點型是因為按照科學記數法表示時,一個浮點數的小數點位置是可變的,
- 字串
- 以
"或'括起來的字符,比如:"hello, world", - 在表示多行字串時,可以使用三個單引號(
''')/雙引號(""")括起來
- 以
- 布爾型
- 表示的是真或假,通常使用True或False表示,
- 一些運算式的結果也可以表示真偽,如:
1 != 2 - 空的資料型別(
""、[]、{})和None和0表示False,反之為True
- 復數
- 如3+5j,跟數學上的復數表示一樣,唯一不同的是虛部的i換成了j,了解即可,
函式
基本概念
計算機的函式實質上就是一段有特定功能的代碼,使用函式可以有效的減少代碼的耦合度,同時提高代碼的可讀性和易維護性,
函式的寫法
計算機的函式和數學的函式有一定的相似性:
- 有引數,相當于數學函式的自變數
- 有回傳值,相當于數學函式的因變數
python 的函式使用def關鍵詞定義,需要寫上函式名稱,而引數值和回傳值需要根據需求考慮是否填寫,
如:
def foo(num):
return num + 1
引數
前面說過,引數就相當于數學函式的自變數,主要是一些在函式體中用到的值,python的引數可以指定默認的引數,
def pow(num, count=2):
"""計算多少次方"""
return num ** count
if __name__ == "__main__":
print(pow(2)) # 4
print(pow(2, 3)) # 8
上面的函式的count引數即指定了默認引數count=2,對于某些對于引數不確定的函式還可以使用不定長引數,其方式一般為*args或**kwargs,這兩個引數接收的值的型別分別為list和dict,
def foo(*args, **kwargs):
for a in args:
print(a)
for k, v in kwargs.items():
print(k, v)
if __name__ == "__main__":
foo(1, 2, 3, **{"a": 4, "b": 5, "c": 6}, d=7)
需要注意的是:在傳入引數時,可以根據函式引數的位置傳參,也可以根據根據引數的關鍵字傳參,二者可以結合使用,但位置引數一定要在關鍵字引數之前,
比如對于def foo(a, b, c)來說,既可以foo(1, 2, 3)也可以foo(b=2, a=1, c=3)還可以foo(1, c=3, b=2)但不能foo(c=3, 1, 2),
回傳值
使用回傳值需要用到一個關鍵詞return,一個函式的回傳值可以是一個或多個值,也可以是一個函式,
匯入模塊
由于python沒有函式多載的概念,所以假如定義了相同函式名的函式時,前一個函式會被后一個函式所覆寫:
def foo():
print("foo1")
def foo():
print("foo2")
在日常的開發程序中,假如是一個人開發的話可以為不同的函式取不同的名字,但假如是多人開發的話就有可能使用相同的函式名,多人開發時通常使用模塊(module)開發,在使用時可以使用import關鍵字匯入某個指定的模塊,
m1.py:
def foo():
print("foo1")
m2.py:
def foo():
print("foo2")
在使用時:
import m1
import m2
# 使用
m1.foo()
m2.foo()
需要注意的是:匯入模塊時會將模塊的內容執行一遍,假如不想這樣的話,可以使用一個判斷陳述句,使代碼主動執行時運行,而不是匯入時也運行,
def foo():
print("foo")
if __name__ == "___main__":
foo()
__name__是Python中一個隱含的變數它代表了模塊的名字,只有被Python解釋器直接執行的模塊的名字才是__main__,
作用域
作用域就相當于一個變數可以使用的范圍,該作用域的變數只能本作用域和子作用域可用,有了作用域這個概念就有了全域變數和區域變數這兩者變數,全域變數即宣告在全域作用域中的變數,而區域變數則不是宣告在全域的變數,一般來說是一些函式內部宣告的變數,
n = 2 # 全域變數
def foo():
m = 3 # 區域變數
根據python的規則,變數會優先找本作用域的,假如找不到會依次往外找,直至找到,當找不到時就會報錯,
age = 19
def main():
print(age)
main()
但假如要修改外部作用域的變數時,必須使用global和nonlocal這兩個關鍵字宣告一下,否則報錯,因為python會認為修改的這個動作其實是宣告,也就是說python沒有朝外找變數,假如使用變數在宣告變數之前的話,就會報錯:UnboundLocalError: local variable 'xxx' referenced before assignment,
# 這是錯誤的示范
age = 18
def main():
print(age)
age = 20
main()
print(age)
正確的方法:
- global
age = 18
def main():
global age
print(age)
age = 20
main()
print(age)
如果我們希望函式內部的函式能夠修改嵌套作用域中的變數,可以使用nonlocal關鍵字來指示變數來自于嵌套作用域,
2. nonlocal
def test1():
count = 0
def test2():
nonlocal count
count += 1
return count
return test2()
print(test1())
練習
-
實作計算求最大公約數和最小公倍數的函式,
幾個整數中公有的約數,叫做這幾個數的公約數;其中最大的一個,叫做這幾個數的最大公約數,例如:12、16的公約數有1、2、4,其中最大的一個是4,4是12與16的最大公約數,
-
實作判斷一個數是不是素數的函式
# 第一題 求最大公約數和最小公倍數
def gcd(x, y):
"""最大公約數"""
(x, y) = (y, x) if x > y else (x, y)
for i in range(x, 0, -1):
if x % i == 0 and y % i == 0:
return i
def lcm(x, y):
"""最小公倍數"""
return x * y // gcd(x, y)
# 第二題
def is_prime(num):
"""判斷一個數是不是素數"""
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True if num != 1 else False
常用資料結構
字串 str
字串實質上就是由字符組成的有序序列,前面說過字串是以引號括起來的,引號里面的內容可以使用\進行轉義,使一般的字符特殊化,如:"\n"表示換行,"\\"表示反斜杠\,除此之外轉義符還可以跟八進制(\141)、十六進制(\x61)和Unicode編碼,
一些常用的轉義符
| 字符 | 含義 |
|---|---|
\ |
在行尾時是續行符 |
\\ |
反斜杠符號 |
\' |
單引號 |
\" |
雙引號 |
\a |
響鈴 |
\b |
退格 |
\e |
轉義 |
\000 |
空 |
\n |
換行 |
\v |
縱向制表符 |
\t |
橫向制表符 |
\r |
回車 |
\f |
換頁 |
除了轉義以外,字串還有很多使用方法,
- 切片
s = "hello, world"
print(s[1:4])
如上所述,切片實質上就是拿中括號寫成[開頭:結尾:步長]的形式(步長可以省略,且默認為一),把需要截取的一部分內容取出來,不過需要注意的是:切片里面的數不能超過要切片的范圍,python的索引以0開始,假如要取開頭([:n])或結尾([n:])的話,可以空著,
- 其他方法
python的字串還有很多的其他方法,這些方法本質上就是一些函式,使用時以"".xxx()的形式呼叫,
s = "hello world"
# 大寫
print(s.upper()) # HELLO WORLD
# 首字母大寫
print(s.title()) # Hello World
# 小寫
print(s.lower()) # hello world
# 替換
print(s.replace("world", "world!")) # hello world!
# 分割
print(s.split(" ")) # ['hello', 'world']
# join
print(" ".join(["hello", "world"])) # hello world
# 兩邊去空
print(" hello world ".strip()) # hello world
# 查找
# 找的是第一個的位置,用rfind可以找最后一個
print(s.find("l")) # 2
# print(s.index("t")) # 找不著時會報錯
# 判斷開頭、結尾
print(s.startswith("hello")) # True
print(s.endswith("ld")) # True
串列 list
串列也是python的一種常用的資料結構,上面例子中split方法的結果就是一個串列,串列由一個個元素組成,各個元素的型別可以各不相同,與字符一樣,串列可以切片、也有一些特定的方法,不一樣的是,串列可以直接通過索引對元素進行修改,而字串則不可以,
fruits_list = ["apple", "pear", "peach", "banana"]
print(fruits_list[1:]) # ['pear', 'peach', 'banana']
# 修改值
fruits_list[2] = "orange" # ['apple', 'pear', 'orange', 'banana']
# 追加
fruits_list.append("pear") # ['apple', 'pear', 'orange', 'banana', 'pear']
# 插入
# 第一個引數是位置,第二個引數是要插入的元素
fruits_list.insert(0, "cherry")
# ['cherry', 'apple', 'pear', 'orange', 'banana', 'pear']
# 迭代添加一個串列
fruits_list.extend(["watermelon", "lemon"])
# ['cherry', 'apple', 'pear', 'orange', 'banana', 'pear', 'watermelon', 'lemon']
# 洗掉
# 按索引位置洗掉
fruits_list.pop(0)
# ['apple', 'pear', 'orange', 'banana', 'pear', 'watermelon', 'lemon']
# 刪串列中的第一個指定值
fruits_list.remove("pear")
# ['apple', 'orange', 'banana', 'pear', 'watermelon', 'lemon']
# 排序
# 可以跟匿名函式lambda:fruits_list.sort(key=lambda x: len(x))
fruits_list.sort()
# ['apple', 'banana', 'lemon', 'orange', 'pear', 'watermelon']
# 查找
# 第一個指定值的位置
print(fruits_list.index("pear")) # 4
# 清空
fruits_list.clear() # []
元組 tuple
元組是一種類似于串列的資料結構,它以小括號()括起來為一個元組,元組的元素同樣可以是任意的,但是需要注意的是,元組的元素并不能被改變,這一種特性這某些場合中適用,如某些重要的資料、不允許改變的類屬性(__slots__)和函式的多回傳值,由于元組不能被修改,所以我們只需要關注其定義和使用即可,
# 定義元組
fruits_tuple = ("apple", "pear", "peach", "banana")
# 也可以使用tuple從其他可迭代資料轉換過來
fruits_tuple = tuple(["apple", "pear", "banana", "peach", "banana"])
print(fruits_tuple)
# 遍歷
for f in fruits_tuple:
print(f)
# 計數
print(fruits_tuple.count("banana")) # 2
# 查找
print(fruits_tuple.index("banana")) # 2
元組在記憶體上比串列更小,換句話說使用元組可以節省記憶體,使用sys.getziseof函式可以回傳該物件的位元組數,
import sys
print(sys.getsizeof(("apple", "pear", "peach", "banana"))) # 72
print(sys.getsizeof(["apple", "pear", "peach", "banana"])) # 88
字典 dict
字典是由一個個鍵值對組成的資料結構,它以大括號({})括起來為一個資料,一般的形式為:{"key": "value},需要注意的是,字典的鍵不能重復,也就是說,假如再次給已經存在的鍵賦值時,原來的值會被替換;而且鍵是可以被哈希的資料,一般來說,python不可變的內置型別都可以被哈希,而串列和字典是可變的,不可被哈希,所以不能作為集合的元素,,
data = https://www.cnblogs.com/lczmx/archive/2021/01/09/{
"name": "lczmx",
"age": 18,
"address": "xxx",
}
# 獲取
# 1. 使用中括號,類似于索引的方法,假如沒有該鍵的話會報錯
print(data["name"]) # lczmx
# 2. 使用get方法,沒有該鍵時,回傳另一個引數
print(data.get("name", "none")) # lczmx
# 3. 獲取鍵值對
for k, v in data.items():
print(f"key: {k} value: {v}")
# 4. 獲取鍵或值
for k in data.keys():
print(f"key: {k}")
for v in data.values():
print("value: %s" % v)
# 更新
# 1. update
data.update({"score": 99, "student": True}) # 寫法一
data.update(score=99, student=True) # 寫法二
# {'name': 'lczmx', 'age': 18, 'address': 'xxx', 'score': 99, 'student': True}
# 2. fromkeys
# 將一個可迭代的資料的元素作為鍵,為多個鍵創建統一的值
# 注意,這是dict的方法
d2 = dict.fromkeys(["a", "b", "c"], "123")
print(d2) # {'a': '123', 'b': '123', 'c': '123'}
# 3. setdefault
# 存在取對應的值,不存在則新增鍵值對
print(data.setdefault("name", "lczmx")) # lczmx
# 洗掉
# 1. 隨機洗掉,回傳被洗掉的鍵值對
print(data.popitem()) # ('student', True)
# 2. 洗掉鍵對應的值,不存在時回傳的二個引數
print(data.pop("name", "already delete")) # lczmx
# 3. 清空
data.clear()
print(data) # {}
集合 set
python的集合與數學上的集合是一樣的,有交集、差集、并集、補集等操作,而且元素是唯一無序的,注意:元素的型別不可變的,準確的說:可以被哈希的資料型別可成為元素,根據集合的這些特性,一般來說其用途一般有兩個方面:1. 關系測驗(相交等)、2. 去重,
fruits1 = {'cherry', 'pear', 'banana', 'watermelon', 'lemon'}
fruits2 = set(['apple', 'pear', 'banana', 'orange'])
# 添加
fruits2.add("lemon")
# 交差并集可以用方法實作,也可以用符號實作
# 交集
print(fruits1.intersection(fruits2))
print(fruits1 & fruits2)
# {'banana', 'lemon', 'pear'}
# 差集
print(fruits1.difference(fruits2))
print(fruits1 - fruits2)
# {'watermelon', 'cherry'}
# 并集
print(fruits1.union(fruits2))
print(fruits1 | fruits2)
# {'banana', 'orange', 'pear', 'cherry', 'watermelon', 'lemon', 'apple'}
# 洗掉
# 1. remove
# 洗掉指定元素,不存在則報錯
fruits1.remove("banana")
# 2. discard
# 洗掉指定元素,不存在不報錯
fruits1.discard("apple")
假如定義的時候用forzenset定義的話,則該集合不可變,
推導式
推導式是一種構建資料的快捷方式,假如用得好可以簡化代碼,提高可讀性,但假如濫用推導式,就有可能降低代碼可讀性,一般來說,超過兩個for回圈的代碼,就不適合用推導式了,而直接用多個回圈寫了,
串列推導式
顧名思義,即生成串列的推導式,和定義串列一樣,串列推導式用中括號包裹著運算式,
假如有這樣一個需求:
把num = [18, 22, 23, 50]里面的數加一,我們固然可以,使用一個for回圈把每個元素加一,然后放回原來的串列中,但使用串列推到式只需要一行代碼即可:num = [n + 1 for n in num],
上面的例子只有一個回圈,但假如多個回圈該怎么做,如果現在有num和code兩個串列:
num = [1, 2, 3, 4, 5]
code = ["A", "B", "C", "D"]
要求他們相互組合成['A1', 'A2', 'A3', 'A4', 'A5', 'B1', 'B2', 'B3', 'B4', 'B5', 'C1', 'C2', 'C3', 'C4', 'C5', 'D1', 'D2', 'D3', 'D4', 'D5'],
很簡單:
num = [1, 2, 3, 4, 5]
code = ["A", "B", "C", "D"]
result = [c + str(n) for c in code for n in num]
print(result)
python2.7的版本中使用串列推導式有可能有變數泄露的風險,但在python3中則沒有該顧慮,可以放心使用,
生成器運算式
雖然可以使用串列推導式初始化元組等其它序列型別,但是生成器運算式是更好的選擇,由于生成器遵循迭代器協議,可以在用到時才生成元素,可以減少記憶體開銷,生成器運算式在書寫上與串列推導式僅僅是把中括號換成了小括號,
比如同樣是上面的那個例子:
import sys
num = [1, 2, 3, 4, 5]
code = ["A", "B", "C", "D"]
result_list = [c + str(n) for c in code for n in num]
result_tuple = tuple([c + str(n) for c in code for n in num])
result_gen = (c + str(n) for c in code for n in num)
print(sys.getsizeof(result_list), sys.getsizeof(
result_tuple), sys.getsizeof(result_gen))
# 256 200 112
使用生成器除了可以用生成器運算式,也可以用yeild關鍵字:
def gen_result():
num = [1, 2, 3, 4, 5]
code = ["A", "B", "C", "D"]
for c in code:
for n in num:
yield c + str(n)
for i in gen_result():
print(i)
字典推導式
自python2.7以來,串列推導式和生成器運算式的概念就移植到了字典上(集合也一樣),因此就有了字典推導式,使用字典推導式可以將可迭代的資料作為鍵值對構建出字典,
例子:
temp = ["A1", "B2", "C3", "D4"]
result_dict = {c: n for c, n in temp}
print(result_dict) # {'A': '1', 'B': '2', 'C': '3', 'D': '4'}
假如是由兩個可迭代資料組成字典的話,可以使用zip函式:
num = ["1", "2", "3", "4"]
code = ["A", "B", "C", "D"]
result_dict = dict(zip(code, num))
print(result_dict) # {'A': '1', 'B': '2', 'C': '3', 'D': '4'}
集合推導式
集合推導式跟串列推導式用起來差不多,下面舉個簡單的例子即可:
num = ["1", "2", "3", "4"]
code = ["A", "B", "C", "D"]
result_set = {c + str(n) for c in code for n in num}
print(result_set)
# {'D3', 'C3', 'A2', 'D1', 'C1', 'C2', 'B4', 'B2', 'B3', 'C4', 'A1', 'D2', 'D4', 'A3', 'B1', 'A4'}
練習
- 在螢屏上顯示跑馬燈文字,
import time
def main():
string = "放飛你的青春,奔灑你的熱情, "
while True:
print("\r%s" % string, end="")
string = string[1:] + string[0] # 把第一個字符放到最后一個,以達到運動的效果
time.sleep(0.2)
if __name__ == '__main__':
main()
- 設計一個函式產生指定長度的驗證碼,驗證碼由大小寫字母和數字構成,
import random
def veri_code(count=4):
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
temp = ""
for _ in range(count):
temp += random.sample(chars, 1)[0]
return temp
def main():
print(veri_code())
if __name__ == '__main__':
main()
- 設計一個函式回傳給定檔案名的后綴名,
def get_suffix(filename):
if "." in filename:
return filename.split(".")[-1]
else:
return ""
- 設計一個函式回傳傳入的串列中最大和第二大的元素的值,
def get_max(data: list):
max1 = 0 # 最大
max2 = 0 # 第二大
for d in data:
if d > max1:
max2 = max1
max1 = d
else:
if d > max2:
max2 = d
return max1, max2
- 列印楊輝三角,
def triangles():
L = [1]
while True:
yield L
L = [sum(i) for i in zip([0] + L, L + [0])] # zip和sum結合,不過要在兩邊加0
我的github
我的博客
我的筆記
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/246753.html
標籤:其他
