Pref 逢居家懈怠,为缓解焦虑,更好利用空闲时间,启动容易上手的 python3 学习!另,我已有 C 的基础,故一些相同知识点会略过。
注释 #
注释'''
"""
多行注释,文档字符串#coding=utf-8
或 #coding=gbk
中文注释
字符串 字符串连接 'a' + 'b'
字符串复制 'a' * 5
单双引号均可用,包含时区分开,如 “ ‘ “
print() 返回 None 值 str()
title() 首字母大写 upper() 全大写 lower() 全小写
istitle() 返回布尔值,字符串只包含首字母大写 isupper() islower()
isalpha() 字符串只包含字母 isalnum() 字符串只包含字母和数字 isdecimal() 字符串只包含数字 isspace() 字符串只包含空格、制表符和换行
startswith() endswith() 所调用的字符串以该方法传入的字符串开始或结束
join() 参数是一个字符串列表。
1 2 ' ' .join(['My' , 'name' , 'is' , 'Simon' ])'My name is Simon'
split() 默认以空格为分隔符拆分字符串,返回一个列表
ljust() 左对齐 rjust() center() 居中 插入空格来对齐文本;第一个参数是整数长度,第二个可选参数指定一个填充字符。
strip() 删除首尾空白,第二参数可选指定字符删除,字符顺序不重要 lstrip() rstrip()
1 2 3 spam = 'SpamSpamBaconSpamEggsSpamSpam' spam.strip('ampS' ) 'BaconSpamEggs'
u r b f 前缀 u「Unicode」以 Unicode 格式进行编码,常用于中文字符串 r 去掉反斜杠的转义机制,常用于正则表达式,对应 re 模块 b「bytes」bytes 类型字符串 f「format」拼接字符串
1 2 3 4 first_name = "ada" last_name = "lovelace" full_name = f"{first_name} {last_name} " print(full_name)
bytes 和 str 互相转换 1 2 str .encode('utf-8' )bytes .decode('utf-8' )
正则表达式 regex 正则表达式的函数都在 re 模块
创建对象 re.compile() 传入一个字符串值,表示正则表达式,返回一个 Regex 模式对象。
匹配对象 search() group() 方法 Regex 对象的 search(),未找到返回 None;找到返回一个 Match 对象。
Match 对象的 group(),返回被查找字符串中实际匹配的文本。 mo 是一个通用变量名,用于 Match 对象。
1 2 3 phoneNumRegex = re.compile (r'\d{3}-\d{3}-\d{4}' ) mo = phoneNumRegex.search('My number is 415-555-4242.' ) print('Phone number found: ' + mo.group())
括号分组 向 group() 传入整数 1 等,取得匹配文本的不同分组;传入 0 或无参数,返回整个匹配文本。 groups() 获取所有分组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 phoneNumRegex = re.compile (r'(\d\d\d)-(\d\d\d-\d\d\d\d)' ) mo = phoneNumRegex.search('My number is 415-555-4242.' ) mo.group(1 ) '415' mo.groups() ('415' , '555-4242' ) areaCode, mainNumber = mo.groups() print(areaCode) 415 phoneNumRegex = re.compile (r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)' )
管道匹配多个分组 | 返回第一次出现的匹配文本 1 2 3 4 heroRegex = re.compile (r'Batman|Tina Fey' ) mo1 = heroRegex.search('Batman and Tina Fey.' ) mo1.group() 'Batman'
只指定一次前缀 1 2 3 4 5 6 7 batRegex = re.compile (r'Bat(man|mobile|bat)' ) mo = batRegex.search('Batmobile lost a wheel' ) mo.group() 'Batmobile' mo.group(1 ) 'mobile'
问号匹配零次或一次 指代字符之前的分组,下同。
1 2 3 4 5 6 7 8 batRegex = re.compile (r'Bat(wo)?man' ) mo1 = batRegex.search('The Batman' ) mo1.group() 'Batman' mo2 = batRegex.search('The Batwoman' ) mo2.group() 'Batwoman'
星号匹配零次或多次 1 2 3 4 batRegex = re.compile (r'Bat(wo)*man' ) mo3 = batRegex.search('The Batwowowowoman' ) mo3.group() 'Batwowowowoman'
加号匹配一次或多次 1 2 3 4 batRegex = re.compile (r'Bat(wo)+man' ) mo3 = batRegex.search('The Batman' ) mo3 == None True
花括号匹配特定次数 一个数字,或指定一个范围(最小值,最大值)或不限定最值之一。
(Ha){3} 匹配字符串 ‘HaHaHa’。
(Ha){3,5} 匹配 ‘HaHaHa’、’HaHaHaHa’、’HaHaHaHaHa’。
贪心和非贪心匹配 Python 的 Regex 默认是贪心的,表示在有二义的情况下,它们会尽可能匹配最长的字符串。 花括号的非贪心版本匹配尽可能最短的字符串,即在结束的花括号后跟着一个问号。
1 2 3 4 nongreedyHaRegex = re.compile (r'(Ha){3,5}?' ) mo = nongreedyHaRegex.search('HaHaHaHaHa' ) mo.group() 'HaHaHa
findall() 方法 包含被查找字符串中的所有匹配。不是返回一个 Match 对象。 在正则表达式中没有分组,返回一个字符串列表。 有分组,则返回元组列表。
1 2 3 4 5 6 7 phoneNumRegex = re.compile (r'\d\d\d-\d\d\d-\d\d\d\d' ) phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000' ) ['415-555-9999' , '212-555-0000' ] phoneNumRegex = re.compile (r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)' ) phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000' ) [('415' , '555' , '1122' ), ('212' , '555' , '0000' )]
字符分类
缩写字符
表示
\d
任何一位数字
\D
除 0-9 以外的任何字符
\w
任何字母、数字或下划线字符
\W
除字母、数字和下划线以外的任何字符
\s
空格、制表符或换行符「匹配空白」
\S
除空格、制表符和换行符以外的任何字符
自定义字符分类 [] [a-zA-Z0-9] 匹配所有小写、大写字母和数字。
方括号内,普通的正则表达式符号不会被解释,不需要转义。
非字符类 ^ 匹配不在这个字符类中的所有字符。
consonantRegex = re.compile(r'[^aeiouAEIOU]')
开始字符 ^ 结束字符 $ 开始处用插入符号 ^
,表明匹配必须发生在被查找文本开始处。 末尾加上美元符号 $
,表示该字符串必须以这个 Regex 的模式结束。 同时使用,表明整个字符串必须匹配该模式。如 r'^\d+$'
匹配从开始到结束都是数字的字符串。
1 2 3 4 5 6 7 beginsWithHello = re.compile (r'^Hello' ) beginsWithHello.search('Hello world!' ) <re.Match object ; span=(0 , 5 ), match='Hello' > endsWithNumber = re.compile (r'\d$' ) endsWithNumber.search('Your number is 42' ) <re.Match object ; span=(16 , 17 ), match='2' >
通配符 . 匹配除换行外所有字符,只匹配一个字符 1 2 3 atRegex = re.compile (r'.at' ) atRegex.findall('The cat in the hat sat on the flat mat.' ) ['cat' , 'hat' , 'sat' , 'lat' , 'mat' ]
.* 匹配除换行外所有字符 1 2 3 4 nameRegex = re.compile (r'First Name: (.*) Last Name: (.*)' ) mo = nameRegex.search('First Name: Alice Last Name: Sweigart' ) mo.group(1 ) 'Alice'
.*
贪心模式。.*?
非贪心模式。
1 2 3 4 5 6 7 8 9 greedyRegex = re.compile (r'<.*>' ) mo = greedyRegex.search('<To serve man> for dinner.>' ) mo.group() '<To serve man> for dinner.>' nongreedyRegex = re.compile (r'<.*?>' ) mo = nongreedyRegex.search('<To serve man> for dinner.>' ) mo.group() '<To serve man>'
re.DOTALL 匹配换行 1 2 3 NewlineRegex = re.compile ('.*' , re.DOTALL) NewlineRegex.search('First\nSecond\nThird' ).group() 'First\nSecond\nThird'
re.IGNORECASE 不区分大小写匹配 传入 re.IGNORECASE
或 re.I
作为 re.compile()
第二个参数。
sub() 方法替换字符串 Regex 对象的 sub() 传入两个参数。返回替换后的字符串。 第一个是一个字符串,用于取代发现的匹配; 第二个是要搜索的字符串。
1 2 3 namesRegex = re.compile (r'Agent \w+' ) namesRegex.sub('CENSORED' , 'Agent Alice gave the documents to Agent Bob.' ) 'CENSORED gave the documents to CENSORED.'
使用匹配的文本本身,作为替换的一部分。sub() 第一个参数中输入 \1、 \2 表示输入分组 1、2 的文本。
字符串中的 \1 将由分组 1 匹配的文本所替代,即 (\w)
分组。
1 2 3 agentNamesRegex = re.compile (r'Agent (\w)\w*' ) agentNamesRegex.sub(r'\1****' , 'Agent Alice told Agent Carol.' ) A**** told C****.
管理复杂的正则表达式 忽略正则表达式字符串中的空白符和注释。 向 re.compile()
传入变量 re.VERBOSE
,作为第二参数。
难以阅读:
1 phoneRegex = re.compile (r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)' )
多行书写,加上注释:
1 2 3 4 5 6 7 8 phoneRegex = re.compile (r'''( (\d{3}|\(\d{3}\))? # area code (\s|-|\.)? # separator \d{3} # first 3 digits (\s|-|\.) # separator \d{4} # last 4 digits (\s*(ext|x|ext.)\s*\d{2,5})? # extension )''' , re.VERBOSE)
1 someRegexValue = re.compile ('foo' , re.IGNORECASE | re.DOTALL | re.VERBOSE)
数
数学操作符
操作「优先级从高到低」
**
指数
%
取模
//
整除
/
除
*
乘
-
减
+
加
int() float()
类假值 0、0.0 和 ' '
(空字符串)被认为是 False
大数 - 下划线分组 1 2 3 universe_age = 14_000_000_000 print(universe_age) 14000000000
多变量赋值
变量名
只能包含字母、数字和下划线
不能以数字开头
区分大小写,常用小写
常量,全大写 表示(无内置常量类型)
列表 列表名用复数
[['a','b'],'c']
可嵌套
子列表副本 [:]
访问最后一个元素 [-1]
列表连接 +
复制 *
方法 返回值是 None,方法属于单个数据类型,只能在列表上调用。
index() 在列表中查找值
传入一个值,存在于列表中,就返回下标;不在就报 ValueError;有重复只返回第一次出现的下标。
1 2 spam = ['hello' , 'hi' , 'howdy' ] spam.index('hello' )
append() 列表末添加元素,只能一个 insert(0, ‘’) 插入元素
del bicycles[0] 仅删除元素 pop() 删除列表末元素 pop(0) 删除元素,可赋值使用 remove() 根据值删除元素,有重复则只删第一个
sort(reverse=True) 字母顺序排序(逆序) 使用 ASCII 字符顺序; 按照字典顺序排序,spam.sort(key=str.lower)
,sort() 将列表中所有的表项当成小写。
sorted() 临时字母顺序排序,不改变原列表
非所有元素值是小写时,按字母顺序排列列表变复杂。
reverse() 逆序 len() 长度 min() max() sum() 数字列表总和
可变和不可变数据类型 字符串可看作是单个文本字符的列表 ,列表相关操作也用于字符串。
1 2 name = 'Zophie a cat' newName = name[0 :7 ] + 'the' + name[8 :12 ]
遍历 1 2 3 cats = ['alice' , 'david' , 'carolina' ] for cat in cats: print(cat)
迭代 1 2 3 spam = ['a' , 'b' , 'c' ] for i in range (len (spam)): print(str (i) + ' in spam is ' + spam[i])
多重赋值技巧 列表的值为多个变量赋值,变量数目和列表长度必须严格相等。
1 2 cat = ['fat' , 'black' , 'loud' ] size, color, disposition = cat
range(5) 生成数值 0-4 range(1,5) 生成数值 1-4 range(5, -1, -1) 生成数值 5-0
list() 返回传递值的列表版本
tuple() 返回传递值元组版本
1 2 3 4 5 6 numbers = list (range (1 , 6 )) print(numbers) [1 , 2 , 3 , 4 , 5 ] list ('hello' ) ['h' , 'e' , 'l' , 'l' , 'o' ]
列表解析 1 2 3 4 5 6 7 8 9 squares = [] for value in range (1 , 4 ): squares.append(value**2 ) print(squares) squares = [value**2 for value in range (1 , 4 )] print(squares)
切片 1 2 players = ['charles' , 'martina' , 'alice' ] print(players[0 :2 ])
复制列表 1 2 my_foods = ['pizza' , 'falafel' , 'cake' ] friend_foods = my_foods[:]
元组 tuple:值不可变的列表,可优化比列表快
注:元组是由逗号标识的,圆括号只是方便区分;若定义只包含一个元素的元组,必须在这个元素后面加上逗号。
1 2 3 4 dimensions = (200 , 50 ) for dimension in dimensions: print(dimension) dimensions = (400 , 100 )
if 语句 在所有算术、比较操作符求值后,依次求值布尔操作符 not,and,or
1 2 (age_0 >= 21 ) and (age_1 >= 21 )
1 2 3 dogs = ['alice' , 'tom' ] 'tom' in dogs'jam' not in dogs
1 2 3 4 5 6 7 8 9 10 11 age = 12 if age < 4 : price = 0 elif age < 18 : price = 25 else : price = 40 print(f"Price is ${price} ." )
字典 1 2 3 4 5 6 7 8 9 10 11 12 13 14 alien = {} alien = {'color' : 'red' } aline = { 'color' : 'red' , 'point' : '3' , } alien['point' ] = 5 print(alien) alien['point' ] = 3 del alien['color' ] print(speed['fast' ]) speed_value = alien.get('speed' , 'No speed value assigned.' )
遍历所有键值对 items() 1 2 3 for key, value in alien.items(): print(f"\nkey: {key} " ) print(f"value: {value} " )
这些数据类型(dict_keys、dict_values、dict_items)可用于 for 循环,不能被修改。
遍历所有键 keys() 1 2 3 for key in alien: for key in alien.keys(): print(key)
按特定顺序遍历所有键 sorted() 1 for key in sorted (alien.key()):
遍历所有值 values() 1 2 for value in alien.values(): print(value)
无重复遍历所有值 set() 1 for value in set (alien.values()):
不同于列表和字典,集合不会以特定的顺序存储元素
多重赋值技巧 在 for 循环中将键和值赋给不同的变量
1 2 3 spam = {'color' : 'red' , 'age' : 42 } for k, v in spam.items(): print('Key: ' + k + ' Value: ' + str (v))
某键设置默认值 setdefault() 两参数:检查并为字典中某键设置一个默认值; 该键不存在或没有值时使用它;若存在,方法就会返回键的值,不做修改
while 循环 input() 接受一个参数做 prompt,提示输入内容,返回字符串
Ctrl + C
向程序发送 KeyboardInterrupt 错误,退出无限循环
一般循环 1 2 3 4 5 6 7 8 prompt = "\nTell me something: " prompt += "\nEnter 'q' to quit." msg = "" while msg != 'q' : msg = input (prompt) if msg != 'q' : print(msg)
标志循环 1 2 3 4 5 6 7 8 active = True while active: msg = input (prompt) if msg == 'q' : active = False else : print(msg)
break 1 2 3 4 5 6 while True : msg = input (prompt) if msg == 'q' : break else : print(msg)
continue 1 2 3 4 5 6 7 n = 0 while n < 10 : n += 1 if n % 2 == 0 : continue print(n)
在列表间移动元素 1 2 3 4 5 6 7 8 names = ['alice' , 'brian' ] new_names = [] while names: temp = names.pop() new_names.append(temp) for new_name in new_names: print(new_name)
删除为特定值的所有列表元素 1 2 3 4 5 pets = ['dog' , 'cat' , 'dog' , 'cat' , 'rabbit' , 'cat' ] while 'cat' in pets: pets.remove('cat' ) print(pets)
使用用户输入来填充字典 1 2 3 4 5 6 7 8 9 10 11 responses = {} while True : name = input ("\nname: " ) response = input ("response: " ) responses[name] = response repeat = input ("Enter anything to continue or 'n' to quit." ) if repeat == 'n' : break for name, response in responses.items(): print(f"{name} : {response} " )
函数 形参 parameter 实参 argument
实参 1 2 3 4 5 6 7 8 9 10 11 12 13 def user_age (name, age ): print(f"{name} : {age} " ) user_age('Tom' , '18' ) user_age(name='Tom' , age='18' ) def user_age (name, age='18' ): def user_age (name, age, gender='' ): if gender: user = f"{name} {age} {gender} " else : user = f"{name} {age} " return user
print() 有可选变元 end 和 sep,分别指定在参数末尾打印什么,在参数之间用什么隔开print('Hello', end='')
禁用换行
返回字典 1 2 3 4 5 6 7 8 9 def build_person (first_name, last_name, age=None ): person = {'first' : first_name, 'last' : last_name} if age: person['age' ] = age return person user = build_person('tom' , 'antonio' , age=18 ) print(user)
传递列表 1 2 3 4 5 6 7 def users (names ): for name in names: msg = f"Hello, {name.title()} !" print(msg) usernames = ['hannah' , 'ty' , 'margot' ] users(usernames)
在函数中修改列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def change (usernames, new_usernames ): while usernames: temp = usernames.pop() new_usernames.append(temp) def show (new_usernames ): for new_username in new_usernames: print(new_username) usernames = ['hannah' , 'ty' , 'margot' ] new_usernames = [] change(usernames, new_usernames) show(new_usernames)
禁止函数修改列表,[:] 创建列表副本 1 change(usernames[:], new_usernames)
传递任意数量的实参 1 2 3 4 5 6 7 8 def make_pizza (size, *toppings ): print(f"size: {size} " ) for topping in toppings: print(f"{topping} " ) make_pizza(6 , 'pepperoni' ) make_pizza(8 , 'mushrooms' , 'green peppers' )
使用任意数量的关键字实参 1 2 3 4 5 6 7 8 def build_profile (first, last, **info ): info['first_name' ] = first info['last_name' ] = last return info profile = build_profile('albert' , 'einstein' , location='princeton' , field='physics' ) print(profile)
函数模块化及别名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 '''pizza.py''' def make_pizza (size, *toppings ): print(f"size: {size} " ) for topping in toppings: print(f"{topping} " ) def show (): print("..." ) '''main.py''' import pizzapizza.make_pizza(6 , 'pepperoni' ) pizza.make_pizza(8 , 'mushrooms' , 'green peppers' ) from pizza import make_pizza, show make_pizza(6 , 'pepperoni' ) from pizza import * import pizza as p from pizza import make_pizza as mp
作用域
类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 ''' 类中函数称为方法,规定双下划线; 调用 __init__ 方法创建 Car 实例,自动传入实参 self, 必须有一个参数位于最前面, 方法是一个指向实例本身的引用,让实例能够访问类中的属性和方法; Car 类创建实例时,只需给其他形参提供值; 前缀为 self 的变量可供类中所有方法使用,可通过任何实例访问; 类看作是如何创建实例的说明。 ''' class Car : def __init__ (self, make, model, year ): self.make = make self.model = model self.year = year self.odometer = 0 def info (self ): name = f"{self.year} {self.make} {self.model} " return name.title() def read_odometer (self ): print(f"{self.odometer} " ) def update_odometer (self, mileage ): if mileage >= self.odometer: self.odometer = mileage else : print("Don't roll back an odometer." ) def increment_odometer (self, miles ): self.odometer += miles car = Car('audi' , 'a4' , 2019 ) print(f"{car.make} " ) print(car.info()) car.read_odometer() car.odometer = 20 car.update_odometer(35 ) car.increment_odometer(10 )
继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ''' 创建子类时,父类必须包含在当前文件中,且位于子类前; 父类也称超类(superclass) ''' class Car : --snip-- class EletricCar (Car ): def __init__ (self, make, model, year ): super ().__init__(make, model, year) self.battery = 100 def info_battery (self ): print(f"{self.battery} " ) el_car = EletricCar('tesla' , 'model s' , 2019 ) print(el_car.info())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Car : --snip-- class Battery : def __init__ (self, battery=100 ): self.battery = battery def info_battery (self ): print(f"{self.battery} " ) def get_range (self ): if self.battery == 100 : range = 315 elif self.battery == 75 : range = 260 print(f"{range } " ) class EletricCar (Car ): def __init__ (self, make, model, year ): super ().__init__(make, model, year) self.battery = Battery() el_car = EletricCar('tesla' , 'model s' , 2019 ) print(el_car.info()) el_car.battery.info_battery()
导入类 1 2 3 4 5 6 7 8 9 '''car.py''' class Car : --snip-- class Battery : --snip-- class EletricCar (Car ): --snip--
1 2 3 4 5 6 7 8 '''my_car.py''' from car import Car, EletricCar my_car = Car('audi' , 'a4' , 2019 ) print(my_car.info()) my_car.odometer = 23 my_car.read_odometer()
文件 读取整个文件 - read() 1 2 3 4 5 6 7 8 9 10 11 ''' 函数 open() 返回一个表示文件的对象, 赋给 file_object(只在 with 内可用),用方法 read() 读取; 关键字 with 在不再需要访问文件后将其关闭; close() 关闭文件可能存在各种问题; read() 到达文件尾时返回一个空字符串,表现为空行; 文本文件内容都被解读为字符串。 ''' with open ('demo.txt' ) as file_object: contents = file_object.read() print(contents.rstrip())
逐行读取 - for 循环 1 2 3 4 5 6 7 8 9 ''' 输出可能每行中间有一个空行, print() 调用有一个换行符,文件本身有一个换行符。 ''' filename = 'demo.txt' with open (filename) as file_object: for line in file_object: print(line.rstrip())
创建包含文件各行内容的列表 - readlines() 1 2 3 4 5 6 filename = 'demo.txt' with open (filename) as file_object: lines = file_object.readlines() for line in lines: print(line.rstrip())
使用文件内容 - 空字符串 1 2 3 4 5 6 7 8 9 10 filename = 'demo.txt' with open (filename) as file_object: lines = file_object.readlines() use = '' for line in lines: use += line.rstrip() print(use)
写入文件 - write() - rwar+w 1 2 3 4 5 6 7 8 9 10 11 12 13 ''' 读取模式:r 读、w 写、a 附加、r+w 读写; 省略模式实参,默认只读模式打开文件; 写入文件不存在则自动创建,存在则覆盖重写; 只能将字符串写入文本文件。 ''' filename = 'demo.txt' with open (filename, 'w' ) as file_object: file_object.write('anything' ) with open (filename, 'a' ) as file_object: file_object.write('\naddition' )
注:Windows 使用 \ 显示文件路径,但在代码中用 / 绝对路径较长,赋给一个变量使用; python 可处理的数据量没有限制,只要系统内存足够。
异常处理 ZeroDivisionError 异常 1 2 3 4 5 6 7 8 9 10 11 ''' python 用特殊对象「异常」来管理程序执行期间发生的错误; 避免用户看到 traceback ''' def spam (divideBy ): try : return 42 / divideBy except ZeroDivisionError: print("You can't divide by zero!" ) print(spam(0 ))
FileNotFoundError 异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 def count_words (filename ): try : with open (filename, encoding='utf-8' ) as f: contents = f.read() except FileNotFoundError: print(f"Sorry, the file {filename} does not exist." ) ''' except FileNotFoundError: pass # 静默失败 ''' else : words = contents.split() num_words = len (words) print(f"{filename} has about {num_words} words." ) filename = 'alice.txt' count_words(filename) filenames = ['alice.txt' , 'siddhartha.txt' ] for filename in filenames: count_words(filename)
存储数据 - json JSON(JavaScript Object Notation)
dump() load() 1 2 3 4 5 6 7 8 9 10 11 12 13 import jsonnumbers = [2 , 3 , 5 , 7 , 11 , 13 ] filename = 'numbers.json' with open (filename, 'w' ) as f: json.dump(numbers, f) with open (filename) as f: numbers = json.load(f) print(numbers)
保存和读取用户生成的数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import jsonfilename = 'username.json' try : with open (filename) as f: username = json.load(f) except FileNotFoundError: username = input ("What is your name? " ) with open (filename, 'w' ) as f: json.dump(username, f) print(f"We'll remember you when you come back, {username} !" ) else : print(f"Welcome back, {username} !" )
重构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ''' 代码能正确运行,但将其划分为便于改进的一系列完成具体工作的函数,该过程称为重构。 ''' import jsondef greet_user (): """问候用户,并指出其名字。""" filename = 'username.json' try : with open (filename) as f: username = json.load(f) except FileNotFoundError: username = input ("What is your name? " ) with open (filename, 'w' ) as f: json.dump(username, f) print(f"We'll remember you when you come back, {username} !" ) else : print(f"Welcome back, {username} !" ) greet_user()
重构 greet_user() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import jsondef get_stored_username (): filename = 'username.json' try : with open (filename) as f: username = json.load(f) except FileNotFoundError: return None else : return username def get_new_username (): username = input ("What is your name? " ) filename = 'username.json' with open (filename, 'w' ) as f: json.dump(username, f) return username def greet_user (): username = get_stored_username() if username: print(f"Welcome back, {username} !" ) else : username = get_new_username() print(f"We'll remember you when you come back, {username} !" ) greet_user()
测试 模块函数的定义和调用 1 2 3 4 '''name_function.py''' def get_formatted_name (first, last ): full_name = f"{first} {last} " return full_name.title()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 '''names.py''' import name_functionprint("Enter 'q' at any time to quit." ) while True : first = input ("\nfirst name: " ) if first == 'q' : break last = input ("last name: " ) if last == 'q' : break formatted_name = get_formatted_name(first, last) print(f"\tNeatly formatted name: {formatted_name} ." )
单元测试和测试用例 - unittest 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ''' 运行 test_name_function.py 时, 所有以 test_ 打头的方法都将自动运行。 ''' '''test_name_function.py''' import unittestfrom name_function import get_formatted_nameclass NamesTestCase (unittest.TestCase ): def test_first_last_name (self ): """能够正确地处理像 Janis Joplin 这样的姓名吗?""" formatted_name = get_formatted_name('janis' , 'joplin' ) self.assertEqual(formatted_name, 'Janis Joplin' ) if __name__ == '__main__' : unittest.main() ''' 运行测试文件,输出如下: 第一行句点表明有一个测试通过了; OK 表明该测试用例中的所有单元测试都通过了。 ''' . ---------------------- Ran 1 test in 0.001 s OK
未通过的测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ''' 使函数能处理中间名,但无法正确处理只有名和姓的情况 ''' '''name_function.py''' def get_formatted_name (first, middle, last ): full_name = f"{first} {middle} {last} " return full_name.title() ''' 运行测试文件,输出如下: 第一行字母 E,指出有一个单元测试导致了错误; 第三行指出 NamesTestCase 中的 test_first_last_name() 导致了错误; Traceback 指出函数调用 get_formatted_name(...) 有问题; 最后指出整个测试用例未通过,因为发生了一个错误。 ''' E ================================ ERROR: test_first_last_name (__main__.NamesTestCase) -------------------------------- Traceback (most recent call last): File "test_name_function.py" , line 8 , in test_first_last_name formatted_name = get_formatted_name('janis' , 'joplin' ) TypeError: get_formatted_name() missing 1 required positional argument: 'last' -------------------------------- Ran 1 test in 0.001 s FAILED (errors=1 )
处理未通过的测试 1 2 3 4 5 6 7 '''name_function.py''' def get_formatted_name (first, last, middle='' ): if middle: full_name = f"{first} {middle} {last} " else : full_name = f"{first} {last} " return full_name.title()
添加新测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ''' 用于测试包含中间名的姓名 ''' '''test_name_function.py''' --snip-- class NamesTestCase (unittest.TestCase ): def test_first_last_name (self ): --snip-- def test_first_last_middle_name (self ): formatted_name = get_formatted_name('wolf' , 'mozart' , 'amadeus' ) self.assertEqual(formatted_name, 'Wolf Amadeus Mozart' ) if __name__ == '__main__' : unittest.main() ''' 第一行句点表明有两个测试通过了…… ''' .. ---------------------- Ran 2 test in 0.001 s OK
断言方法 unittest 模块中的断言方法,只能在继承 unittest.TestCase 的类中使用这些方法
方法
用途
assertEqual(a, b)
核实 a == b
assertNotEqual(a, b)
核实 a != b
assertTrue(x)
核实 x 为 True
assertFalse(x)
核实 x 为 False
assertIn(item, list)
核实 item 在 list 中
assertNotIn(item, list)
核实 item 不在 list
模块类定义与调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 '''survey.py''' class AnonymousSurvey : """收集匿名调查问卷的答案。""" def __init__ (self, question ): self.question = question self.responses = [] def show_question (self ): print(self.question) def store_response (self, new_response ): self.responses.append(new_response) def show_results (self ): print("Survey results:" ) for response in self.responses: print(f"- {response} " )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 '''language_survey.py''' from survey import AnonymousSurveyquestion = "What language did you first learn to speak?" my_survey = AnonymousSurvey(question) my_survey.show_question() print("Enter 'q' at any time to quit." ) while True : response = input ("Language: " ) if response == 'q' : break my_survey.store_response(response) my_survey.show_results()
测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 '''test_survey.py''' import unittestfrom survey import AnonymousSurveyclass TestAnonymousSurvey (unittest.TestCase ): def test_store_single_response (self ): """测试单个答案会被妥善存储。""" question = "What language did you first learn to speak?" my_survey = AnonymousSurvey(question) my_survey.store_response('English' ) self.assertIn('English' , my_survey.responses) def test_store_three_responses (self ): question = "What language did you first learn to speak?" my_survey = AnonymousSurvey(question) responses = ['English' , 'Spanish' , 'Mandarin' ] for response in responses: my_survey.store_response(response) for response in responses: self.assertIn(response, my_survey.responses) if __name__ == '__main__' : unittest_main()
方法 setUp() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 '''test_survey.py''' import unittestfrom survey import AnonymousSurveyclass TestAnonymousSurvey (unittest.TestCase ): def setUp (self ): """创建一个调查对象和一组答案,供使用的测试方法使用。""" question = "What language did you first learn to speak?" self.my_survey = AnonymousSurvey(question) self.responses = ['English' , 'Spanish' , 'Mandarin' ] def test_store_single_response (self ): self.my_survey.store_response(self.responses[0 ]) self.assertIn(self.responses[0 ], self.my_survey.responses) def test_store_three_responses (self ): for response in self.responses: self.my_survey.store_response(response) for response in self.responses: self.assertIn(response, self.my_survey.responses) if __name__ == '__main__' : unittest_main()
注:运行测试用例时,每完成一个单元测试,都打印一个字符: 通过时打印一个句点,报错时打印一个 E, 而测试导致断言失败时则打印一个 F。
关键字
False
await
else
import
pass
None
break
except
in
raise
True
class
finally
is
return
and
continue
for
lambda
try
as
def
from
nonlocal
while
assert
del
global
not
with
async
elif
if
or
yield
内置函数
abs()
delattr()
hash()
memoryview()
set()
all()
dict()
help()
min()
setattr()
any()
dir()
hex()
next()
slice()
ascii()
divmod()
id()
object()
sorted()
bin()
enumerate()
input()
oct()
staticme
bool()
eval()
int()
open()
str()
breakpoint()
exec()
isinstance()
ord()
sum()
bytearray()
filter()
issubclass()
pow()
super()
bytes()
float()
iter()
print()
tuple()
callable()
format()
len()
property()
type()
chr()
frozenset()
list()
range()
vars()
classmethod()
getattr()
locals()
repr()
zip()
compile()
globals()
map()
reversed()
__import
complex()
hasattr()
max()
round()
Git 版本控制 1. 创建文件夹 git_practice 2. 创建程序 hello_git.py
3. 忽略文件 .gitignore
git bash: touch .gitignore
dos: ren n.txt .gitignore
4. 初始化仓库 git init
Initialized empty Git repository in git_practice/.git/
Git 用来管理仓库的文件都存储在 .git 中,不用管它但不能删除。
5. 检查状态 git status
1 2 3 4 5 6 7 8 On branch main No commits yet Untracked files: # 指出未被跟踪的文件 (use "git add <file>..." to include in what will be committed) .gitignore hello_git.py # 当前无提交,但指出了可能需要加入仓库的未跟踪文件 nothing added to commit but untracked files present (use "git add" to track)
6. 加入仓库 git add .
项目中未被跟踪的文件都加入仓库中,但未提交
1 2 3 4 5 6 On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: .gitignore new file: hello_git.py
7. 执行提交 git commit -m "Started project"
标志 -m 让后面信息记录到项目的历史记录中。
1 2 3 4 5 6 7 8 [main (root-commit) a3f6a37] Started project 2 files changed, 2 insertion(+) create mode 100644 .gitignore create mode 100644 hello_git.py On branch master nothing to commit, working tree clean # 工作树是干净的,若非如此,可能提交前忘记了添加文件。
8. 查看提交历史 git log
1 2 3 4 commit b4a4af78247b33c27de89b57d4dde2369f712ab4 (HEAD -> main) Author: xxx <xxx@gmail.com> Date: Mon Apr 24 16:34:50 2023 +0800 Started project
每次提交 Git 都会生成唯一的引用 ID,长 40 字符。 记录提交人,提交时间,及提交时的指定信息。
精简版:git log --pretty=oneline
1 b4a4af78247b33c27de89b57d4dde2369f712ab4 (HEAD -> main) Started project
9. 第二次提交 git commit -am "Extended greeting"
标志 -a 让仓库中所有修改了的文件都加入当前提交中
1 2 3 '''hello_git.py''' print("Hello Git!" ) print("Hello everyone." )
1 2 3 4 5 6 7 8 9 10 11 12 # 检查状态,指出所做修改未提交 On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: hello_git.py no changes added to commit (use "git add" and/or "git commit -a") [main 35530cb] Entended greeting 1 file changed, 1 insertion(+) # 查看状态和记录,同上
10. 撤销修改 git checkout .
1 2 3 Updated 1 path from the index # 查看状态,输出工作树干净,文件中最后一行代码被删除。
git checkout 能恢复到以前的任意提交。 git checkout . 放弃最后一次提交后 所做的修改,恢复到最后一次提交 的状态。
11. 检出以前的提交 git checkout b4a4af
末尾指定该提交的引用 ID 前 6 字符。
1 2 3 4 5 6 7 Note: switching to 'b4a4af'... HEAD is now at b4a4af7 Started project git checkout main Previous HEAD position was b4a4af7 Started project Switched to branch 'main'
检出以前的提交后,将离开分支 main,进入分离头指针(detached HEAD)状态。 HEAD 指针表示当前提交的项目状态。
12. 重置到以前的提交 git reset --hard b4a4af
13. 删除仓库 rm -rf .git
当仓库的历史记录弄乱了,无法恢复时,个人可删除历史记录,再重建仓库,不影响文件当前状态。
可直接删除 .git 或 cmd 下:
缩进规则的例外
在源码文件中,列表可以跨越几行,直到结束方括号。 行末使用续行字符 \
,将一条指令写成多行。
标准库 random 1 2 3 4 5 6 7 8 9 from random import randint, choicerandint(1 , 6 ) players = ['charles' , 'michael' , 'florence' , 'eli' ] choice(players)
第三方模块 自动排版
Refer 《Python编程快速上手——让繁琐工作自动化第一版》 《python编程从入门到实践第二版》git - Windows下创建 .gitignore 文件 Python 字符串前面加u,r,b,f的含义 python格式化代码【自动排版】 yapf、black风格选择
PS 啃过 C/C++ 的选手,再学 python 进展之快着实超乎我的意料,晃荡大学四年,编程语言这方面总算开始有真正的基础了,汗颜啊!