Python基础
开始
导入
- 导入模块:
import module
从模块导入函数:
from module import function
全部导入:
from module import *
注释
- 单行注释:#
- 多行注释:三个单引号或三个双引号包围
格式化输出
占位符:%d
,%s
1
2
3
4
5
6
age = 18;
print("name:%s" % ("Jake"))
print("age:%d" % age)
print("www","baidu", "com" , sep=".") # 默认为换行
print("Hello", end="") # 不换行
print("Hello", end="\t") # 相隔一个换行符
str()
:返回一个用户易读的表达形式repr()
:返回一个解释器易读的表达形式str.format()
:前面的字符串称为格式化字段,被format中的参数替换1 2 3 4 5 6 7 8 9 10 11
"{}.{}.{}".format("www", "baidu", "com") # www.baidu.com # 指定位置 "{0}{1}".format("Hello", "World") # HelloWorld "{1}{0}".format("Hello", "World") # WorldHello # 使用关键字参数 "{first}{second}".format(second="Hello", first="World") # WorldHello # 特定转化,!a:ascii(),!s:str(),!r:repr() "{!s}".format(str) # 在:后接转义字符 "{0:.2f}".format(float) # 保留两位小数 "{0:10}".format(name) # 空出10个单位宽度
输入
1
2
age = input("tip") # input函数返回一个字符串
print(age)
强制类型转换
1
2
a = int("123")
b = int(number_str)
运算符
- 除法
- 传统除法:
/
,向下取整,含有浮点数时进行精确除法 - 整除:
//
,强制向下取整
- 传统除法:
- 逻辑运算符
a and b
:若a为非零(True),则返回b的值,返回类型与b一致a or b
:若a为零(False),则返回b的值,返回类型与b一致not(a)
:当值为非零,返回True- Python指定非零、非None或集合非空表示True,0、None或集合为空表示False
- 成员运算符
x in y
:若x在序列y中,返回Truex not in y
:若x不在序列y中,返回True
- 类型运算符
x is y
:判断两个引用是否引用同一个对象,等价于id(x) == id(y)
,id()
用于获取对象地址x is not y
:判断两个引用是否引用不同的对象
条件语句
1
2
3
4
5
6
if condition:
statements
elif condition:
statements
else:
statements
循环
for
1 2
for iterator in sequnce: statements
sequence为一个序列,数组遍历每个元素,字符串遍历每个字符
- range:返回一个数字序列的迭代器
range(a, b)
:返回一个[a,b)的数字序列,默认步进1range(a)
:返回[0,a)的数字序列range(a, b, c)
:步进为c,a、b为负数时,步进也为负数
len()
:返回字符串大小
- range:返回一个数字序列的迭代器
while
1 2 3
while condition: statements iterator += 1
enumerate(iterator)
将一个可遍历的数据对象(字典,元组等)组合为一个索引序列,同时给出下标和数据,在for循环中可同时使用下标和数据
1 2
for i, item in enumerate(b, start=10): # start参数设置第一个元素的下标 print(i, item)
列表推导式
使用列表推导式可以更方便的创建列表
1 2 3 4 5
list = [] for x in range(10): list.append(x * 2) # x的表达式 # 列表推导式 list = [x * 2 for x in range(10)]
for之后可以继续写子句
1 2 3 4 5 6 7
combs = [] for x in [1, 2, 3]: for y in [3, 1, 4]: if x != y: combs.append((x, y)) # 列表推导式 combs = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
zip()
:该函数可传入多个值或多个序列,将多个序列对应位置的元素组成一个元组(两个序列的元素位置的交集),返回所有这些元组的列表1 2 3 4 5 6
names = ['Alice', 'Bob', 'Charlie'] ages = [25, 30, 35] paired = zip(names, ages) # 返回的是一个zip迭代器 paired_list = list(paired) print(paired_list) # [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
字符串
字符串使用双引号,单引号,三个引号包围
字符串拼接
1 2 3 4
a = "Hello" b = "Python" c = a + b # HelloPython d = a * 3 # HelloPython重复三次
字符串截取
1 2 3 4 5
a = "HelloPython" b = a[0:5] # Hello,左闭右开 c = a[0:5:2] # Hlo,同range(a, b, c) d = a[:5] # [0:5] e = a[5:] # [5:11]
逐字字符串:不对字符串中的特殊字符进行转义
1
a = r"HelloWorld!\n" # HelloWorld!\n
格式字符串:format字符串的简化
1 2
a = 10 s = f"This is a number {a}" # 大括号需要转义,使用{{}}
集合
Python中的基本集合类型有列表list、元组tuple、字典dict、集合set
列表
列表是类似数组的一个数据结构,可以同时存储字符串、数字,支持从尾部遍历
1
list = [obj1, obj2, obj3, ...]
常用操作
- 下标0为开始值,-1为从末尾的开始值(-1,-2,…)
- 使用
+
拼接,使用*
重复 - 切片:
list[0:5:2]
,同字符串切片 append(obj)
:在列表尾部添加元素extend(list)
:在列表尾部添加另一个列表insert(index, value)
:插入元素remove(value)
:删除列表中指定值的第一个匹配del obj
:Python内置关键字,释放指定位置元素的内存pop()
:弹出尾部元素sort()
:同一类型排序,降序设置reverse=True
reverse()
:列表反转index(value, startIndex, endIndex)
:返回指定元素下标,若包含多个,返回第一个匹配下标count(value)
:返回指定元素的数目
元组
元组使用小括号括起来,元素不能修改,可以添加可变对象,对象中的元素可变,如list
只有一个元素时,必须加逗号
1
2
tup = (obj1, obj2, obj3, ...)
tup = (obj1,)
操作类似列表
len()
:获取元组长度max()
:获取元组元素最大值min()
:获取元组元素最小值tuple()
:将其他类型转换为元组
字典
字典是无序的对象集合,使用键值对存储,键必须为不可变类型且唯一
1
dic = {key1: value1, key2: value2, ...}
- 访问
- 直接访问:
dic[key]
,不存在值会报错 - get访问:
dic.get(key, default)
,不存在值返回None或者指定默认值
- 直接访问:
- 添加
update(dic)
:合并字典dict()
:将其他类型转换为字典
- 删除
del dic[key]
:删除整个键值对clear()
:清空字典pop(key)
:弹出键值对
- 查找
keys()
:获取所有的键values()
:获取所有的值items()
:获取所有的键值对
集合
特性与其他语言类似,值唯一且无序,使用大括号包围
1
s = {1, 2, 3, "Hello"}
函数
1
2
def func(parameters) -> None: # -> returnType指定返回值类型,不是强制的
pass # pass关键字为占位语句,没有作用
Python可以返回多个值
1
2
3
def func(a, b):
return a, b
x, y = func(1, 2) # x = 1,y = 2
拆包:对于函数中返回多个返回值,利用拆包可以去掉列表、元组、字典(返回多个值时,在传递过程中被封装成了元组),直接查看里面的数据(字典拆包返回的是key)
忽略不需要的返回值:利用拆包,将接收不需要的返回值的变量命名为_
,或者在调用后用下标获取需要的返回值,同时也可以使用切片
作用域
命名空间
- 内置名称:Python语言内置的名称,比如函数名abs、char和异常名称BaseException、Exception等等
- 全局名称:模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量
- 局部名称:函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量(类中定义的也是)
变量查找顺序为局部命名空间->全局命名空间->内置命名空间
变量作用域
变量查找顺序为L-E-G-B
- 局部变量L
- 闭包函数之外的函数中的变量E
- 全局变量G
- 内置变量B
Python中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
global和nonlocal关键字
- 局部作用域内需要修改全局作用域的变量,在局部作用域中使用global关键字修饰声明该变量
- 局部作用域内需要修改闭包函数之外的函数中的变量,在局部作用域中使用nonlocal修饰声明该变量
闭包
闭包是函数式编程的基本结构,Python中将函数作为一个函数对象,可将函数对象作为参数传递
函数对象的作用域与def所在的层级相同
闭包是将函数对象在函数中传递
1
2
3
4
5
6
7
8
def hello(greet):
def setName(name):
print(greet,name)
return setName
Hello = hello("Good Morning")
Hello('Yang') #Good Morning Yang
闭包的条件
- 函数中必须有内嵌函数
- 内嵌函数必须引用上一级函数的变量
- 函数必须返回该内嵌函数
参数传递
Python中一切皆对象,对象分为可变对象和不可变对象
- 不可变对象:string,tuple,number为不可变对象,传递时按值传递
- 可变对象:list,dict为可变对象,传递时按引用传递
参数列表
关键字参数
Python传递参数时,可以指定参数列表中的某个参数进行传递
1 2 3
def func(a, b): return a + b func(b = 20, a = 10)
默认参数
在声明函数时,可以指定参数的默认值,参数列表中默认参数之后的参数都需要设置默认值
1 2 3
def func(a, b = 10): return a + b func(10) # 20
不定长参数
在参数列表中使用
*
表示一个不定长的元组,表示不定长参数1 2 3 4
def func(arg_normal, *args): print(arg_normal) print(args) func(10, 20, 30) # arg_normal = 10, varstuple = (20, 30)
单独使用
*
占位,表示后面的参数必须使用关键字参数1 2 3 4
def f(a, b, *, c): return a + b + c f(1, 2, 3) # 报错 f(1, 2 , c=3) # 6
使用两个星号
**
表示以字典传入1 2 3 4
def printinfo(arg, **kwargs): print(arg) print(kwargs) printinfo(1, a=2, b=3) # arg = 1, vardict = {"a": 2, "b": 3}
强制位置参数
使用
/
占位,表示前面的参数必须使用位置形参1 2 3 4
def f(a, b, /, c, d, *, e, f): print(a, b, c, d, e, f) f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用关键字参数的形式 f(10, 20, 30, 40, 50, f=60) # e 必须使用关键字参数的形式
lambda函数
使用lambda表达式返回一个函数对象,lambda表达式限定只能包含一行代码
1
2
f = lambda arg1, arg2, ...:expression
f(arg...)
迭代器
迭代器是遍历集合元素的方式,只能前进不能后退
调用iter()
构造一个迭代器对象,可使用for遍历该对象
调用next()
返回下一个元素,循环中通过捕获StopIteration
异常来结束读取
1
2
3
4
5
6
7
8
9
10
import sys
list = [1, 2, 3, 4]
it = iter(list) # 创建迭代器对象
while True:
try:
print(next(it))
except StopIteration:
sys.exit()
自定义迭代器
自定义的迭代器类需要实现__iter__()
和__next__()
1
2
3
4
5
6
7
8
9
10
11
12
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
生成器
使用了yield
关键字的函数称为生成器,生成器是一个函数简化版迭代器
所有的生成器都是迭代器,生成器由函数实现,迭代器由类实现
每次执行next()
时,生成器才执行,在生成器执行过程中,函数遇到yield时,返回yield
之后的值并保存该位置,下一次执行next()
时,函数从该位置执行
1
2
3
4
5
6
7
8
9
10
def fibonacci(n): # 生成斐波那契数列
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f是一个迭代器,由生成器返回生成
next(f)
yield from
:使用其他生成器,简化生成器的嵌套调用
1
2
3
4
5
6
7
8
# 未使用yield from
def generate1(n):
for i in range(n):
yield i
# 使用yield from
def generate2(n):
yield from range(n)
面向对象
成员命名规范
python中使用一些命名规范来表示访问级别
- 类中受保护的实例属性和方法:protected,应该以一个下划线开头,不是强制的
- 类中私有的实例属性和方法:private,应该以两个下划线开头
- 类和异常的命名:应该每个单词首字母大写
- 模块级别的常量:应该采用全大写字母,如果有多个单词就用下划线进行连接
- 类的实例方法:method,应该把第一个参数命名为 self 以表示对象自身
- 类的类方法:class method,应该把第一个参数命名为 cls 以表示该类自身
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
class People:
name = ''
age = 0
__weight = 0 # 私有属性
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self): # 实例方法
print("instance method")
@classmethod
def talk(cls): # 类方法
print("class method")
@staticmethod
def study(): # 静态方法
print("static method")
p = People('runoob', 10, 30)
# 绑定方法调用
p.speak() # 实例方法
p.talk() # 类方法
# 通过类调用实例方法,非绑定方法调用
People.speak(self=p) # 实例方法
People.speak(self=People) # 方法内的self看做类名,可以调用静态方法
People.talk() # 类方法
People.study() # 静态方法
字段
在类中声明的字段分为类字段和实例字段
类变量
类变量在类外通过类名调用,类内方法体同样通过类名调用,由所有对象实例共享,对象实例不可获取到类变量
实例变量
实例变量在类外通过对象实例调用,类内方法体内通过self调用,由对象实例独有,通过类名不可获取到实例变量
在方法内外都可以给类添加动态属性并赋值,通过对象实例定义则为实例变量,通过类名定义则为类变量
方法
Python类内方法分为实例方法,类方法,静态方法
实例方法
参数列表必须包含一个self参数,self表示该类的对象实例,通过对象实例调用
通过类名调用需要传入self参数,若传入的是对象实例,则在方法中可以调用实例方法和类方法,若传入的是类名,则在方法中可以调用类方法和静态方法
类方法
参数列表中包含一个cls参数,使用
@classmethod
修饰,类方法可以通过类名和对象实例调用,传入的cls看做一个类名,可以调用类的构造器或其他方法静态方法
静态方法参数列表中没有self或cls,只能通过类名调用,使用
@staticmethod
修饰通过对象调用静态方法会自动传入一个self参数,而静态方法不需要self参数,所以对象无法调用静态方法
构造函数和析构函数
1
2
3
4
5
6
7
8
class Person:
age = 0
name = ""
def __init__(self, age, name):
self.age = age
self.name = name
def __del__(self):
pass
- 析构函数在Python中不是很需要,Python有垃圾回收机制,在del(obj)时调用__del__
- 当含有多个构造函数时,只有最后一个构造函数生效(局部函数对象覆盖)
运算符重载
Python运算符重载通过一些特殊函数实现
__call__(self)
:重载()
,对象可作为函数对象__str__(self)
:print(obj)
时调用,返回一个字符串__add__(self, rhs)
:重载+
__sub__(self, rhs)
:重载-
__mul__(self, rhs)
:重载*
__truediv__(self, rhs)
:重载/
__setitem__
:按照索引赋值__getitem__
:按照索引获取值__len__
:获得长度__cmp__
:比较运算__mod__
:求余运算__pow__
:乘方__str__
:转换为字符串
继承
单继承
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
#类定义
class people:
name = ''
age = 0
__weight = 0
#定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" % (self.name, self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self, n, a, w, g):
#调用父类的构造函数
#当子类不重写构造器时,会自动调用父类构造,重写后需要显式调用
people.__init__(self, n, a, w)
'''
其他写法
super().__init__(self, n, a, w)
super(people, self).__init__(self, n, a, w)
'''
self.grade = g
#覆盖父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade)
)
s = student('ken',10,60,3)
s.speak()
super(Child, c).myMethod() #用子类对象调用父类已被覆盖的方法
多继承
在子类括号中加入多个父类,当多个父类中有同名方法时,子类调用父类方法根据父类列表顺序来查找,也可指定调用某个父类的方法,当子类重写父类方法时,只会关注子类的方法
内置类属性
__dict__
:类的属性(包含一个字典,由类的数据属性组成)__doc__
:类的文档字符串__name__
:类名__module__
:类定义所在的模块- __bases__ :类的所有父类构成元素(包含了一个由所有父类组成的元组)
__doc__
:类的文档字符串__class__
:获取对象的类对象,获取类名:__class__.__name__
垃圾回收
Python使用引用计数来跟踪和回收垃圾,当一个变量或一个对象被创建时,引用计数器(一个内部跟踪变量)增加该对象的引用,当对象的引用计数为0时,解释器在适当的时机回收该对象的内存
循环引用是指两个对象相互引用,但没有其他对象引用他们,在循环引用的情况下,循环垃圾收集器会留意未被引用计数销毁的对象,试图回收未被清理的循环引用
文件操作
Python中的文件操作通常配合上下文管理器一起使用
打开文件
使用open(filename, mode)
打开文件或创建新文件
使用close()
关闭文件
访问模式
- r:只读,指针在文件开头
- w:只写,会覆盖原文件
- a:追加,指针在文件尾部
- rb,wb,ab:以二进制操作
- r+,w+,a+:;支持读写,特点与对应模式一致
- rb+,wb+,ab+
读写文件
write(str)
:写入文件,返回写入的字符数read(n)
:读取n个字符,同时指针后移readline()
:读取一行,同时;指针移动到下一行readlines()
:读取所有行,返回一个列表,每个元素为一行tell()
:返回文件指针目前位置seek(offset, from_what)
:移动文件指针offset为移动字符数,从尾部开始移动,offset为负数
from_what可选0(文件开头),1(当前位置),2(文件末尾)
上下文管理器
上下文管理器可以简化资源的打开和关闭操作,一个实现了__enter__
和__exit__
方法的类成为上下文管理器
1
2
3
with open(filename, "w") as f
#利用f来操作文件
pass
- 表达式执行完后调用
__enter__
方法,将返回值命名为f - 执行接下来对f的操作
- 最后调用
__exit__
方法
as主要用于起别名,通常有两个使用场景
- 给表达式起别名
- 给捕获的异常对象起别名
- 给导入的模块起别名
异常处理
常见的异常类
Exception | 描述 |
---|---|
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
捕获异常
使用try-except-finally
捕获异常
1
2
3
4
5
6
7
8
try:
statements # 运行别的代码
except exception1:
statements # 如果在try部分抛出了exception1异常
except exception2 as e:
statements # 如果抛出了exception1异常,获得该异常对象
finally:
statements # 无论是否抛出异常,一定会执行
- 若未发生异常,则将try中的代码执行完,执行之后的代码
- 若捕获到了异常,except子句中有匹配的异常,则处理异常,处理后继续执行之后的语句
- 若异常发生,没有匹配的except子句,则异常被抛到上层try块中,直到程序最上层,结束程序
抛出异常
使用raise关键字手动抛出异常,常见有三种用法
raise
:单独一个raise。该语句引发当前上下文中捕获的异常(比如在except块中继续抛出异常)或默认引发 RuntimeError异常raise Exception
:raise后带一个异常类名称,表示引发执行类型的异常raise Exception(message)
:在引发指定类型的异常的同时,附带异常的描述信息
自定义异常
自定义异常类需要重写构造函数
1
2
3
class Networkerror(Exception):
def __init__(self, arg):
self.args = arg