Python根据缩进来判断代码行与前一个代码行的关系。Python要求你使用缩进让代码整洁而结构清晰。
1.变量和常用数据类型
变量名只能包含字母、数字和下划线。变量名能以字母或下划线打头,但不能以数字打头。Python中应使用小写的表示变量,全大写的表示常量。
在Python中,注释用井号(#)标识。
1.1 字符串
在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。这种灵活性让你能够在字符串中包含引号和撇号。
修改字符串的方法: title() upper() lower()
msg = "Hello Python World!"
print(msg)
1.1.1 在字符串中使用变量
要在字符串中插入变量的值,可在前引号前加上字母f,再将要插入的变量放在花括号内。
f字符串是Python3.6引入的。如果你使用的是Python 3.5或更早的版本,需要使用 format() 方法,而非这种f语法。使用方法format(),可在圆括号内列出要在字符串中使用的变量。对于每个变量,都通过一对花括号来引用。
msg = "Hello World!"
la = 'python'
words = f"{la} {msg}"
print(words)
#f字符串拼接
print(f"Hello, {la.title()} World.")
old = 'old format'
#format()方法拼接
print("{} by {}".format(msg, old.title()))
1.1.2 删除空白
Python能够找出字符串开头和末尾多余的空白,并删除它:
rstrip() #删除字符串末尾的空白
lstrip() #删除字符串开头的空白
strip() #删除字符串两边的空白
但这种删除只是暂时的,要永久删除需要将删除的结果关联到变量。
message = " Hello World "
message = message.strip()
1.2 数
1.2.1 整数
在Python中,可对整数执行加(+)减(-)乘(*)除(/)运算。
使用两个乘号 ** 表示乘方运算。
1.2.2 浮点数
Python将所有带小数点的数称为浮点数。
将任意两个数相除时,结果总是浮点数,即便这两个数都是整数且能整除。
无论是哪种运算,只要有操作数是浮点数,Python默认得到的总是浮点数,即便结果原本为整数也是如此。
1.2.3 数中的下划线
书写很大的数时,可使用下划线将其中的数字分组,使其更清晰易读。这种表示法适用于整数和浮点数,但只有Python 3.6和更高的版本支持。
num = 14_000_100
x, y, z = 23, 37, 73
可在一行代码中给多个变量赋值,Python将按顺序将每个值赋给对应的变量。这有助于缩短程序并提高其可读性。
1.2.4 常量
Python没有内置的常量类型,但可使用全大写来指出应将某个变量视为常量。
1.3 列表
列表由一系列按特定顺序排列的元素组成。可以将任何东西加入列表中,其中的元素之间可以没有任何关系。列表通常包含多个元素,因此列表变量一般使用复数名称。
在Python中,用方括号 [] 表示列表,并用逗号分隔其中的元素。如果让Python将列表打印出来,Python将打印列表的内部表示,包括方括号。
len() #获取列表的长度
1.3.1 访问列表
列表是有序集合,因此可以使用下标(索引)访问。在Python中,列表元素的索引也是从0开始的。
Python为访问最后一个列表元素提供了一种特殊语法。通过将索引指定为-1,可让Python返回最后一个列表元素。这种访问方式也适用于其他负数索引。
1.3.2 修改元素
直接使用下标访问,然后指定新值即可。
1.3.3 添加元素
append() #在列表末尾添加元素
insert() #在列表任意位置添加元素,需要指定索引和值
1.3.4 删除元素
如果知道要删除的元素在列表中的位置,可使用del语句删除元素。
pop() #删除末尾的元素,pop会返回被删除的元素,可以继续使用。实际上可以使用pop()来删除列表中任意位置的元素,只需在圆括号中指定要删除元素的索引即可。
remove() #按值删除元素。注意:方法remove()只删除第一个指定的值,如果要删除的值可能在列表中出现多次,就需要使用循环来确保将每个值都删除。
countries = ["China", "America", "Russia", "England", "france"]
num = len(countries)
print(f'There are {num} countries:{countries}')
print(f"I Love {countries[0]}!")
#访问并修改元素
countries[-1] = countries[-1].title()
#新增元素
countries.append('Japan')
countries.insert(-1, "Korean")
#删除元素
del countries[-1]
gl = countries.pop()
print(f'Good Luck, {gl}')
countries.remove('America')
print(countries)
1.3.5 排序列表
sort() #永久的修改列表排列顺序,按字母顺序排序。向sort()方法传递参数reverse=True即可实现字母的反向排序。
sorted() #对列表临时排序,并不影响列表的原始排序。也可向函数sorted()传递参数reverse=True。
reverse() #反转列表元素的排列顺序。
cars = ['BYD', 'TESLA', 'AION', 'ZEEKR', 'Li', 'AITO', 'Geely']
cars.reverse()
print(cars)
cars.sort()
cars.sort(reverse=True)
print(cars)
print(sorted(cars))
cars.sort()
print(sorted(cars, reverse=True))
print(cars)
1.3.6 遍历列表
for语句末尾的冒号告诉Python,下一行是循环的第一行。
cars = ['BYD', 'TESLA', 'AION', 'ZEEKR', 'Li', 'AITO', 'Geely']
for car in cars:
print(car)
1.3.7 数值列表
使用 range() 函数可以轻松生成一系列数值。
调用函数 range() 时,也可只指定一个参数,这样它将从0开始。
使用函数 list() 可将 range() 的结果直接转换为列表。
使用函数range()时,还可指定步长,Python将根据这个步长来生成数。
min() max() sum()
for v in range(1, 6):
print(v) # 1 2 3 4 5
nums = []
for v in range(3):
nums.append(v)
print(nums) # [0, 1, 2]
nums = list(range(6))
print(nums) # [0, 1, 2, 3, 4, 5]
nums = list(range(3, 13, 3))
print(nums) # [3, 6, 9, 12]
print(min(nums)) # 3
print(max(nums)) # 12
print(sum(nums)) # 30
1.3.8 列表解析
列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素。
squares = [v**2 for v in range(7)]
print(squares) # [0, 1, 4, 9, ,16, 25, 36]
1.3.9 切片
列表的一部分称之为切片。
要创建切片,可指定要使用的第一个元素和最后一个元素的索引。
在表示切片的方括号内可指定第三个值,告诉Python在指定范围内每隔多少元素提取一个。
cars = ['BYD', 'TESLA', 'Geely', 'AION', 'Li', 'AITO']
print(cars[:3]) # ['BYD', 'TESLA', 'Geely']
print(cars[-3:]) # ['AION', 'Li', 'AITO']
print(cars[::2]) # ['BYD', 'Geely', 'Li']
#复制列表
newCars = cars[:]
newCars.sort()
print(newCars) # ['AION', 'AITO', 'BYD', 'Geely', 'Li', 'TESLA']
注意:将一个列表赋值给另一个列表,并不能得到两个列表,它们指向的其实是同一个列表。要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:])。这让Python创建一个始于第一个元素、终止于最后一个元素的切片,即整个列表的副本。
1.3.10 元组
Python将不可变的列表被称为元组。元组用圆括号 () 表示。
严格地说,元组是由逗号标识的,圆括号只是让元组看起来更整洁、更清晰。
如果要定义只包含一个元素的元组,必须在这个元素后面加上逗号。
1.4 字典
在Python中,字典是一系列键值对。每个键都与一个值相关联,可使用键来访问相关联的值。与键相关联的值可以是数、字符串、列表乃至字典。事实上,可将任何Python对象用作字典中的值。
Python使用花括号 {} 来定义字典。键和值之间用冒号分隔,而键值对之间用逗号分隔。
在Python 3.7中,字典中元素的排列顺序与定义时相同。如果将字典打印出来或遍历其元素,将发现元素的排列顺序与添加顺序相同。
一种不错的做法是,在最后一个键值对后面也加上逗号,为以后在下一行添加键值对做好准备。
1.4.1 访问元素
在python中访问字典的和C++中的map一样,可以使用键作下标访问。
当访问的键不存在时,使用键作下标的访问方式将会出错。这种情况可以使用 get() 方法访问,当键不存在时,返回一个默认值。
方法get()的第一个参数用于指定键,是必不可少的;第二个参数为指定的键不存在时要返回的值,是可选的。如果get()方法没有指定第二个参数,则返回值None。
1.4.2 删除元素
使用 del 语句删除字典中的元素。但必须指定字典名和要删除的键。
countries = {
'China': '中国',
'America': '美国',
'Russia': '俄罗斯',
}
print(countries) #{'China': '中国', 'America': '美国', 'Russia': '俄罗斯'}
countries['England'] = '英国'
countries['Japan'] = '日本'
del countries['Japan']
print(countries) #{'China': '中国', 'America': '美国', 'Russia': '俄罗斯', 'England': '英国'}
japan = countries.get('Japan')
print(japan) #None
japan = countries.get('Japan', "There is no japan!")
print(japan) #There is no japan!
1.4.3 遍历字典
Python对字典有多种遍历方式:可遍历字典的所有键值对,也可仅遍历键或值。
items() 返回一个所有键值对的列表。
keys() 返回一个所有键的列表。
values() 返回一个所有值的列表。
遍历字典时,会默认遍历所有的键。
countries = {
'China': '中国',
'America': '美国',
'Russia': '俄罗斯',
}
print(countries)
for k, v in countries.items():
print(f"English: {k}, 中文:{v}")
for k in countries.keys():
print(f"English: {k}")
for v in countries.values():
print(f"中文:{v}")
1.5 集合
Python集合中的每个元素都是独一无二的。
Python集合可以用一对花括号 {} 直接创建。集合不会以特定的顺序存储元素。
通过对包含重复元素的列表调用set(),可让Python找出列表中独一无二的元素,并使用这些元素来创建一个集合。
cars = {'BYD', 'TESLA', 'Geely', 'AION', 'Li', 'AITO'}
print(cars) #{'AION', 'Geely', 'AITO', 'Li', 'BYD', 'TESLA'} 打印顺序随机
1.6 嵌套
Python可以在列表中嵌套字典,在字典中嵌套列表甚至在字典中嵌套字典。
1.7 用户输入
Python的 input() 函数将用户输入解释为字符串。
函数input()接受一个参数,要向用户显示的提示(prompt)或说明,让用户知道该如何做。
使用 int() 函数可以将数的字符串转换为数值。
msg = "Tell me something, and I'll repeat it.\n"
msg = input(msg)
print(msg)
age = input('how old are you?')
age = int(age)
print(f'your age {age}')
2. if语句
Python中布尔表达式的值为 True 或 False。
Pyhon使用关键字 and 表示逻辑与,用关键字 or 表示逻辑或。
使用关键字 in 判断特定的值是否已包含在列表中,使用关键字 not in 来判断特定是不是否没有被包含在列表中。
if语句的结构:
if-else if-elif-else 多elif代码块结构
Python并不要求if语句后面必须有else代码块。和for循环一样,在每个分支后面都需要冒号 : 标识后面是该分支的代码块。
if语句可以用来判断列表是否为空:在if语句中将列表名用作条件表达式时,Python将在列表至少包含一个元素时返回True,并在列表为空时返回False。
3. 循环语句
for循环用于针对集合中的每个元素都执行一个代码块,而while循环则不断运行,直到指定的条件不满足为止。
for循环是一种遍历列表的有效方式,但不应在for循环中修改列表,否则将导致Python难以跟踪其中的元素。要在遍历列表的同时对其进行修改,可使用while循环。
for循环和while循环都使用冒号 : 来标识循环体开始。
Python的循环中的 break语句 和 continue语句 的作用与C++等其他语言中的作用是一致的。
4. 函数
Python中使用关键字 def 来定义函数。最后,定义以冒号结尾。
文档字符串用三引号括起来,Python使用它们来生成有关程序中函数的文档。
定义函数时,也可以给每个形参指定默认值。规则和其他语言一样,有默认值的参数定义在没有默认值的参数的后面。可将默认值设置为None,将其视为占位值。在条件测试中,None相当于False。给形参指定默认值时,等号两边不要有空格。
编写函数时,应给函数指定描述性名称,且只在其中使用小写字母和下划线。
4.1 参数传递
向函数传递实参的方式很多:可使用位置实参,这要求实参的顺序与形参的顺序相同;也可使用关键字实参,其中每个实参都由变量名和值组成;还可使用列表和字典。
def add(numa, numb=0):
"""两个数相加"""
return numa + numb
#位置实参
print(add(1, 1))
#关键字实参
print(add(numa = 1, numb = 2))
#使用默认参数
print(add(4))
4.1.1 传列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都是永久性的。如果不想修改列表里的元素,可以在调用函数时传入列表的副本,即使用切片方式传参。
def listAdd1(nums):
for i in range(len(nums)):
nums[i] += 1
nums = [v for v in range(1, 10, 2)]
print(nums) #[1, 3, 5, 7, 9]
#传列表
listAdd1(nums)
print(nums) #[2, 4, 6, 8, 10]
#传列表的副本
listAdd1(nums[:])
print(nums) #[2, 4, 6, 8, 10]
4.1.2 传任意数量的实参
定义形参时参数名前加星号 * ,Python将为其创建一个空元组,并将收到的所有值都封装到这个元组中。
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
注意:经常会看到通用形参名*args,它也收集任意数量的位置实参。
def printCars(*cars):
print(cars) #('BYD', 'GEELY', 'AITO', 'Li')
for car in cars:
print(car) #BYD GEELY AITO LI
printCars("BYD", "GEELY", "AITO", "Li")
4.1.3 传递任意数量的关键字实参
定义形参时参数名前加两个星号 ** ,Python将为其创建一个空字典,并将收到的所有名称值对都放到到这个字典中。
注意:经常会看到形参名**kwargs,它用于收集任意数量的关键字实参。
4.2 返回值
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
4.3 模块导入
还可以将函数存储在称为模块的独立文件中,再将模块导入到主程序中。import语句允许在当前运行的程序文件中使用模块中的代码。
模块是扩展名为.py的文件,包含要导入到程序中的代码。常见导入方法如下:
#导入整个re模块,函数调用方式:模块名.函数名 re.search
import re
#导入特定函数,函数调用方式:不需要模块名,直接调用 findall
from re import search, match, split, findall
#使用as给函数指定别名
from re import findall as regexpFA
#使用as给模块指定别名
import re as regexp
#导入模块中所有函数 最好不要采用这种导入方法!
from re import *
最佳的做法是,要么只导入需要使用的函数,要么导入整个模块并使用句点表示法。
5. 类
在Python中,首字母大写的名称指的是类。类也用class定义。
5.1 类的定义及使用
类中的函数称为方法。
__init__()方法是一个特殊的方法,每当你根据类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。定义 __init__()方法时,形参self必不可少,而且必须位于其他形参的前面。
创建实例时,有些属性无须通过形参来定义,可在方法__init__()中为其指定默认值。
每个与实例相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
要访问实例的属性,可使用句点表示法。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def sit(self):
print(f'{self.name} is now sitting.')
def roll_over(self):
print(f'{self.name} rolled over.')
my_dog = Dog("大黄", 2)
print(f'this my dog {my_dog.name}, {my_dog.age} years old.')
my_dog.roll_over()
my_dog.sit()
5.2 继承
在既有类的基础上编写新类时,通常要调用父类的方法__init__()。这将初始化在父类__init__()方法中定义的所有属性,从而让子类包含这些属性。
定义子类时,父类必须包含在当前文件中,且位于子类前面。定义子类时,必须在圆括号内指定父类的名称。方法__init__()接受创建父类实例所需的信息。
super()是一个特殊函数,让你能够调用父类的方法。
class Car:
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
def print_car(self):
print(f'{self.brand} {self.model} {self.year}')
class ElectricCar(Car):
def __init__(self, brand, model, year):
super().__init__(brand, model, year)
self.battery_size = 400
def describe_battery(self):
print(f"The battery of {self.brand} {self.model} is {self.battery_size} kWh.")
car = Car('Audi', 'A6L', 2023)
elecCar = ElectricCar('Tesla', 'Model3', 2023)
car.print_car()
elecCar.print_car()
elecCar.describe_battery()
父类方法也可以被重写。
类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
6. 文件和异常
6.1 从文件中读取数据
关键字with在不再需要访问文件后将其关闭。
open()函数可传入多个参数:
第一个参数是要打开的文件名称;
第二个是打开的模式,可指定读取模式('r')、写入模式('w')、附加模式('a')或读写模式('r+')。如果省略了模式实参,Python将以默认的只读模式打开文件。
还可传入编码格式,使用关键字传参:encoding='utf-8'
注意:显示文件路径时,Windows系统使用反斜杠(\)而不是斜杠(/),但在代码中依然可以使用斜杠。如果在文件路径中直接使用反斜杠,将引发错误,因为反斜杠用于对字符串中的字符进行转义。
若想每次一行的方式检查文件,可对文件对象使用for循环。
使用关键字with时,open()返回的文件对象只在with代码块内可用。如果要在with代码块外访问文件的内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表:可以立即处理文件的各个部分,也可以推迟到程序后面再处理。
方法readlines()从文件中读取每一行,并将其存储在一个列表中。
注意:读取文本文件时,Python将其中的所有文本都解读为字符串。如果读取的是数,并要将其作为数值使用,就必须使用函数int()将其转换为整数或使用函数float()将其转换为浮点数。
with open("test.py") as file_obj:
contens = file_obj.read()
print(contens.rstrip())
with open("helloWorld.py") as hell_file:
for line in hell_file:
print(line)
with open("test.py") as file_obj:
lines = file_obj.readlines()
longstring = ""
for line in lines:
print(line)
longstring += line.rstrip()
print(longstring)
key = input("find what you want\n")
if key in longstring:
print(True)
else:
print(False)
6.2 写文件
Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
如果要写入的文件不存在,函数open()将自动创建它。
函数write()不会在写入的文本末尾添加换行符。要让每个字符串都单独占一行,需要在方法调用write()中包含换行符(\n)。
with open("test.txt", 'w') as file_obj:
file_obj.write('Hello World!')
方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
6.3 异常
Python使用称为异常的特殊对象来管理程序执行期间发生的错误。
异常是使用try-except代码块处理的。try-except代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用try-except代码块时,即便出现异常,程序也将继续运行:显示你编写的友好的错误消息,而不是令用户迷惑的traceback。
还有一种try-except-else代码块,依赖try代码块成功执行的代码都应放到else代码块中。
try:
print(2/0)
except ZeroDivisionError:
print("can't divide by zero")
print("After try-except.")
Python有一个pass语句,可用于让Python在代码块中什么都不要做。pass语句可以充当占位符,在except中执行pass语句,可达到静默失败的目的。
6.4存储数据 -- json模块
json.dump() json.load()
函数json.dump()接受两个实参:要存储的数据,以及可用于存储数据的文件对象。
import json
nums = [v for v in range(1, 10, 2)]
with open("test.json", 'r+', encoding='utf-8') as tf:
json.dump(nums, tf)
with open("test.json") as f:
lists = json.load(f)
print(lists) #[1, 3, 5, 7, 9]
7. 测试代码
单元测试用于核实函数的某个方面没有问题。
测试用例是一组单元测试,它们一道核实函数在各种情形下的行为都符合要求。
7.1 测试函数
要为函数编写测试用例,可先导入模块unittest和要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。
unittest模块中的常用断言方法:
方法 | 用途 |
assertEqual(a, b) | a == b |
assertNotEqual(a, b) | a != b |
assertTrue(a) | a == True |
assertFalse(a) | a == False |
assertIn(ele, list) | ele in list |
assertNotIn(ele, list) | ele not in list |
所有以test_打头的方法都将自动运行。
import unittest
#导入要测试的函数
#from model_name import function_name
def format_name(first, last):
fullName = f'{first} {last}'
return fullName.title()
#创建继承自 unittest.TestCase 的测试类
class NameTestCase(unittest.TestCase):
#所有 test_ 打头的函数都将自动运行
def test_format_name(self):
name = format_name('janis', 'joplin')
#断言方法核实得到的结果是否与期望的结果一致
self.assertEqual(name, 'Janis Joplin')
# __name__ 变量是在程序执行时设置的
if __name__ == '__main__':
unittest.main()
#直接运行该文件的结果:
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.000s
# OK
运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过时打印一个句点,测试引发错误时打印一个E,而测试导致断言失败时则打印一个F。这就是你运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。
7.2 测试类
类的测试与函数的测试相似,你所做的大部分工作是测试类中方法的行为。
在unittest.TestCase类的 setUp() 方法中创建一系列实例并设置其属性,就可在每个测试方法中直接使用这些实例。如果在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法。