基础
行末的\表示续行
#开头为注释
缩进严格的语言,缩进不同代表属于不同的代码块文章来源地址https://www.toymoban.com/news/detail-519545.html
命名
变量名为字母/数字/下划线组成,不能以数字开头,大小写敏感
类名采用大驼峰命名法,其他采用下划线命名法
变量以单下划线开头,代表不能被直接访问,类似于C++中的protected型,这样的变量也不能被 import module_name导入。
变量以双下划线开头,表示为类的私有成员,不能被导入和其他类变量访问。
对于类中的方法,使用双下划线开头开头表示子类不能覆写该方法。
以双下划线开头和双下划线结尾的变量是Python的专用标识,有其特殊的身份。我们一般称这样的方法为“魔法方法”(magicmethod)。
魔法方法是python内置方法,不需要主动调用,存在的目的是为了给python的解释器进行调用,几乎每个魔法方法都有一个对应的内置函数,或者运算符,
当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法,可以理解为重写这些python的内置函数。
类型
布尔型
True/False
空值
None
数值
整数没有大小限制
a = 10
#如果数字的长度过大,可以使用下划线作为分隔符
c = 123_456_789
# 二进制 0b开头
c = 0b10
# 八进制 0o开头
c = 0o10
# 十六进制 0x开头
c = 0x10
所有小数都是float类型
c = 1.23
字符串
使用单引号或者双引号引起来
三重单引号或者双引号可以表示多行文字
s = "hello"
s = '子曰:"学而时习之,乐呵乐呵!"'
s = '锄禾日当午,\
汗滴禾下土'
s = '''锄禾日当午,
汗滴禾下土'''
转义符为\,可以使用\uxxxx 表示Unicode编码字符
s = "子曰:\"学而时习之,\\\\n乐呵乐呵!\"\u2250"
格式化字符串
'Hello %s'%'孙悟空'
'hello %s 你好 %s'%('tom','孙悟空')
'hello %3.5s'%'abcdefg' # %3.5s字符串的长度限制在3-5之间
'hello %s'%123.456
'hello %.2f'%123.456
'hello %+d'%123.95
"name: %-*s, age: %0*d"%(10, "June", 10, 27)
student={"name":"Wilber", "age":27}
print("%(name)s is %(age)d years old"%student)
%c 格式化字符及其ASCII码
%s 格式化字符串
%d 格式化整数
%u 格式化无符号整型
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同%e,用科学计数法格式化浮点数
%g %f和%e的简写
%G %F 和 %E 的简写
%p 用十六进制数格式化变量的地址
* 定义宽度或者小数点精度
- 用做左对齐(默认右对齐)
+ 在正数前面显示加号( + )
<sp> 在正数前面显示空格
# 在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于用的是'x'还是'X')
0 显示的数字前面填充'0'而不是默认的空格
% '%%'输出一个单一的'%'
(var) 映射变量(字典参数)
m.n. m是显示的最小总宽度,n是小数点后的位数(如果可用的话)
"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序
"{1} {0}".format("hello", "world") # 设置指定位置
"name:{name}, url:{url}".format(name="myname", url="myurl") # 指定变量名
obj = {"name": "myname", "url": "myurl"}
"name:{name}, url:{url}".format(**obj) # 使用对象
my_list = ['hello', 'world']
"{0[0]}, {0[1]}".format(my_list) # 使用数组
"{age:x<4d}".format(**student)
数字格式化
# ^, <, > 分别是居中、左对齐、右对齐,后面带宽度, : 号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。
# + 表示在正数前显示 +,负数前显示 -; (空格)表示在正数前加空格
# b、d、o、x 分别是二进制、十进制、八进制、十六进制。
# 此外我们可以使用大括号 {} 来转义大括号
{:b} # 二进制
{:d} # 十进制
{:o} # 八进制
{:x} # 十六进制
{:#x} # 十六进制,前面带0x
{:#X} # 十六进制,前面带0X
{:+.2f} # 带符号保留2位小数
{:-.2f} # 只在负数时保留符号
{:0>2d} # 数字补零 (填充左边, 宽度为2)
{:x<4d} # 数字补x (填充右边, 宽度为4)
{:,} # 以逗号分隔的数字格式
{:.2%} # 百分比格式,保留两位小数
{:.2e} # 指数记法
{:^10d} # 中间对齐 (宽度为10)
{{0}} # 直接输出{0}
字符串前面的特殊字符
f 表示字符串内支持大括号内的python表达式
f"Total time taken: {time.time() - start_time}"
r 去掉反斜杠的转移机制
r"Test\n\n\n"
u 后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面
u"我是含有中文字符组成的字符串。"
b 表示这是一个bytes类型对象,在网络编程中,服务器和浏览器只认bytes类型数据
b'<h1>Hello World</h1>'
字符串运算符
+ 字符串连接
* 重复输出字符串
[索引] 通过索引获取字符串中字符
[起始:结束] 截取字符串中的一部分,包括起始,不包括结束
in 成员运算符 - 如果字符串中包含给定的字符返回 True
not in 成员运算符 - 如果字符串中不包含给定的字符返回 True
内建函数
string.capitalize()
把字符串的第一个字符大写
string.center(width)
返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string.count(str, beg=0, end=len(string))
返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.decode(encoding='UTF-8', errors='strict')
以 encoding 指定的编码格式解码 string,如果出错默认报一个 ValueError 的 异 常 , 除非 errors 指 定 的 是 'ignore' 或 者'replace'
string.encode(encoding='UTF-8', errors='strict')
以 encoding 指定的编码格式编码 string,如果出错默认报一个ValueError 的异常,除非 errors 指定的是'ignore'或者'replace'
string.endswith(obj, beg=0, end=len(string))
检查字符串是否以 obj 结束,如果beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.
string.expandtabs(tabsize=8)
把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8。
string.find(str, beg=0, end=len(string))
检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
string.format() 格式化字符串
string.index(str, beg=0, end=len(string))
跟find()方法一样,只不过如果str不在 string中会报一个异常.
string.isalnum()
如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False
string.isalpha()
如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False
string.isdecimal()
如果 string 只包含十进制数字则返回 True 否则返回 False.
string.isdigit()
如果 string 只包含数字则返回 True 否则返回 False.
string.islower()
如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
string.isnumeric()
如果 string 中只包含数字字符,则返回 True,否则返回 False
string.isspace()
如果 string 中只包含空格,则返回 True,否则返回 False.
string.istitle()
如果 string 是标题化的(见 title())则返回 True,否则返回 False
string.isupper()
如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
string.join(seq)
以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
string.ljust(width)
返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.lower()
转换 string 中所有大写字符为小写.
string.lstrip()
截掉 string 左边的空格
string.maketrans(intab, outtab)
用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
max(str)
返回字符串 str 中最大的字母。
min(str)
返回字符串 str 中最小的字母。
string.partition(str)
有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元 素 的 元 组 (string_pre_str,str,string_post_str),如果 string 中不包含str 则 string_pre_str == string.
string.replace(str1, str2, num=string.count(str1))
把 string 中的 str1 替换成 str2,如果 num 指定,则替换不超过 num 次.
string.rfind(str, beg=0,end=len(string) )
类似于 find() 函数,返回字符串最后一次出现的位置,如果没有匹配项则返回 -1。
string.rindex( str, beg=0,end=len(string))
类似于 index(),不过是返回最后一个匹配到的子字符串的索引号。
string.rjust(width)
返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
string.rpartition(str)
类似于 partition()函数,不过是从右边开始查找
string.rstrip()
删除 string 字符串末尾的空格.
string.split(str="", num=string.count(str))
以 str 为分隔符切片 string,如果 num 有指定值,则仅分隔 num+1 个子字符串
string.splitlines([keepends])
按照行('\r', '\r\n', '\n')分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
string.startswith(obj, beg=0,end=len(string))
检查字符串是否是以 obj 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查.
string.strip([obj])
在 string 上执行 lstrip()和 rstrip()
string.swapcase()
翻转 string 中的大小写
string.title()
返回"标题化"的 string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
string.translate(str, del="")
根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中
string.upper()
转换 string 中的小写字母为大写
string.zfill(width)
返回长度为 width 的字符串,原字符串 string 右对齐,前面填充0
取得类型
type(1) # <class 'int'>
type(1.5) # <class 'float'>
type(True) # <class 'bool'>
type('hello') # <class 'str'>
type(None) # <class 'NoneType'>
类型转换
类型转换四个函数 int() float() str() bool()
bool()会把所有表示空的值转换成False,包括0/None/空字符串/空数组/空对象
运算符(操作符)
算术运算符
+ 加法运算符(如果是两个字符串之间进行加法运算,则会进行拼串操作)
- 减法运算符
* 乘法运算符(如果将字符串和数字相乘,则会对字符串进行复制操作,将字符串重复指定次数)
/ 除法运算符,运算时结果总会返回一个浮点类型
// 整除,只会保留计算后的整数位
** 幂运算,求一个值的几次幂
% 取模,求两个数相除的余数
赋值运算符
= += -= *= **= /= //= %=
算术运算符加等号的写法为简写,比如a+=b表示a=a+b
关系运算符
> >= < <=
== != 相等和不等比较的是对象的值,而不是id
is 比较两个对象是否是同一个对象,比较的是对象的id
is not 比较两个对象是否不是同一个对象,比较的是对象的id
逻辑运算符
not 逻辑非,可以对符号右侧的值进行非运算
对于布尔值,非运算会对其进行取反操作,True变False,False变True
对于非布尔值,非运算会先将其转换为布尔值,然后再取反
and 逻辑与,可以对符号两侧的值进行与运算
只有在符号两侧的值都为True时,才会返回True,只要有一个False就返回False
Python中的与运算是短路的与,如果第一个值为False,则不再看第二个值
or 逻辑或,可以对符号两侧的值进行或运算
或运算两个值中只要有一个True,就会返回True
Python中的或运算是短路的或,如果第一个值为True,则不再看第二个值
非布尔值的与或运算
当我们对非布尔值进行与或运算时,Python会将其当做布尔值运算,最终会返回原值
与运算的规则
与运算是找False的,如果第一个值是False,则不看第二个值
如果第一个值是False,则直接返回第一个值,否则返回第二个值
1 and 2 # 2
1 and 0 # 0
0 and 1 # 0
0 and None # 0
或运算的规则
或运算是找True的,如果第一个值是True,则不看第二个值
如果第一个值是True,则直接返回第一个值,否则返回第二个值
1 or 2 # 1
1 or 0 # 1
0 or 1 # 1
0 or None # None
逻辑运算符可以连着使用
1 < 2 < 3 # 相当于 1 < 2 and 2 < 3
10 < 20 > 15
位运算符
& 按位与运算符,参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0;
| 按位或运算符,只要对应的二个二进位有一个为1时,结果位就为1;
^ 按位异或运算符,当两对应的二进位相异时,结果为1;
~ 按位取反运算符,对数据的每个二进制位取反,即把1变为0,把0变为1;
>> 右移动运算符,把 >> 左边的运算数的各二进位全部右移若干位,>> 右边的数指定移动的位数;
<< 左移动运算符,运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数,高位丢弃,低位补0。
条件运算符(三元运算符)
语句1 if 条件表达式 else 语句2
条件判断语句(if语句)
if 条件表达式:
代码块
elif 条件表达式:
代码块
else:
代码块
代码块以缩进开始,直到代码恢复到之前的缩进级别时结束
循环语句
while循环
while 条件表达式 :
代码块
else :
代码块
while后面如果有else,只在正常退出循环后执行一次,如果以break退出循环,else代码块不执行
for循环
for 序列项目 in 序列:
代码块
else :
代码块
for后面如果有else,只在正常退出循环后执行一次,如果以break退出循环,else代码块不执行
for letter in 'Python':
print("当前字母: %s" % letter)
fruits = ['banana', 'apple', 'mango']
for fruit in fruits:
print ('当前水果: %s'% fruit)
for index in range(len(fruits)):
print ('当前水果 : %s' % fruits[index])
break
立即退出循环语句(包括else)
continue
跳过当次循环
pass
空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。
for表达式
for表达式使用其他区间,元组,列表等可迭代对象创建新的列表。
[表达式 for 循环计数器 in 可迭代对象 [if 条件表达式]]
for表达式与普通for循环的区别有两点:
for关键字之前定义一个表达式,该表达式通常会包含循环计数器。
for表达式没有循环体,因此没有冒号。
用中括号的for表达式,返回列表
my_list2 = [i*i for i in my_list if i%2==0]
用大括号的for表达式,返回字典
my_dict2 = {k: v for k, v in my_dict if k in key_list}
用圆括号的for表达式,他最终返回的是生成器,因此这种for表达式也被称为生成器推导式。
该生成器同样可以使用for循环迭代。
my_generator = (x*x for x in a_range if x%2==0)
序列
列表(list)
my_list = [10,'hello',True,None,[1,2,3],print] # 列表中可以保存任意的对象
正向索引以0开始,0代表第一个,从左到右递增。
负向索引以-1开始,-1代表倒数第一个,从右到左递减。
切片
列表[起始:结束:步长]
通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素
做切片操作时,总会返回一个新的列表,不会影响原来的列表
起始和结束位置的索引都可以省略不写
如果起始位置和结束位置全部省略,则相当于创建了一个列表的副本
步长表示,每次获取元素的间隔,默认值是1
步长不能是0,但是可以是负数,如果是负数,则会从列表的后部向前边取元素
+可以将两个列表拼接为一个列表
[1,2,3] + [4,5,6]
*可以将列表重复指定的次数
[1,2,3] * 5
in用来检查指定元素是否存在于列表中
'a' in ['b', 'a']
not in用来检查指定元素是否不在列表中
'a' not in ['b', 'a']
del list[idx] # 删除指定坐标的元素
cmp(list1, list2) # 比较两个列表的元素
len(list) # 列表元素个数
max(list) # 返回列表元素最大值
min(list) # 返回列表元素最小值
list(seq) # 将元组转换为列表
list.append(obj) # 在列表末尾添加新的对象
list.clear() # 清空列表元素
list.count(obj) # 统计某个元素在列表中出现的次数
list.extend(seq) # 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.index(obj) # 从列表中找出某个值第一个匹配项的索引位置
list.insert(index, obj) # 将对象插入列表
list.pop([index=-1]) # 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
list.remove(obj) # 移除列表中某个值的第一个匹配项
list.reverse() # 反向列表中元素
list.sort(cmp=None, key=None, reverse=False) # 对原列表进行排序
cmp -- 可选参数, 如果指定了该参数会使用该参数的方法进行排序
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。
range
range([start, ]end[, step]) # 生成一个自然数的序列。
start:开始,默认为0,可以省略
end: 结束,不包含
step: 默认为1,可以省略
range(5) # 相当于[0, 1, 2, 3, 4]
range(0,10,2) # 相当于[0, 2, 4, 6, 8]
元组(tuple)
元组是一个不可变的序列
它的操作的方式基本上和列表是一致的
所以你在操作元组时,就把元组当成是一个不可变的列表就ok了
my_tuple = (1,2,3,4,5) # 创建了一个5个元素的元组
my_tuple = 10,20,30,40 # 当元组不是空元组时,括号可以省略
my_tuple = 40, # 当省略括号时,它里边至少要有一个,
元组的解包(解构)
解包指就是将元组当中每一个元素都赋值给一个变量
a,b,c,d = my_tuple
交互a 和 b的值,这时我们就可以利用元组的解包
a , b = b , a
在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致
也可以在变量前边添加一个*,这样变量将会获取元组中所有剩余的元素,不能同时出现两个或以上的*变量
a , b , *c = my_tuple
a , *b , c = my_tuple
*a , b , c = my_tuple
字典(Dictionary)
字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:
d = {key1 : value1, key2 : value2 }
字典的键可以是任意的不可变对象(int、str、bool、tuple ...),但是一般我们都会使用str
字典的键是不能重复的,如果出现重复的后边的会替换到前边的
字典的值可以是任意对象
使用 dict()函数来创建字典
d = dict(name='孙悟空',age=18,gender='男')
d = dict([('name','孙悟饭'),('age',18)])
tinydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
tinydict['Age'] = 8 # 更新
tinydict['School'] = "RUNOOB" # 添加
tinydict['Alice'] # 如果用字典里没有的键访问数据,会输出错误KeyError
del tinydict['Name'] # 删除键是'Name'的条目
del tinydict # 删除字典
cmp(dict1, dict2) # 比较两个字典的元素
len(dict) # 计算字典元素个数,即键的总数。
str(dict) # 输出字典可打印的字符串表示。
dict.clear() # 清空字典所有条目
dict.copy() # 返回一个字典的浅复制
dict.fromkeys(seq[, val]) # 创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值
dict.get(key, default=None) # 返回指定键的值,如果值不在字典中返回default值
dict.has_key(key) # 如果键在字典dict里返回true,否则返回false
dict.items() # 以列表返回可遍历的(键, 值) 元组数组
dict.keys() # 以列表返回一个字典所有的键
dict.setdefault(key, default=None) # 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
dict.update(dict2) # 把字典dict2的键/值对更新到dict里
dict.values() # 以列表返回字典中的所有值
pop(key[,default]) # 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
popitem() # 返回并删除字典中的最后一对键和值。
集合(set)
集合和列表非常相似
不同点:
1.集合中只能存储不可变对象
2.集合中存储的对象是无序(不是按照元素的插入顺序保存)
3.集合中不能出现重复的元素
使用 {} 来创建集合
s = {10,3,5,1,2,1,2,3,1,1,1,1}
使用 set() 函数来创建集合
s = set() # 空集合
s = set([1,2,3,4,5,1,1,2,3,4,5])
s = set('hello')
s = set({'a':1,'b':2,'c':3}) # 使用set()将字典转换为集合时,只会包含字典中的键
len(set) # 元素的数量
set.add(val) # 向集合中添加元素
set.update(set2) # 把set2集合中的元素添加到当前集合中
set.pop() # 随机删除并返回一个集合中的元素
set.remove(val) # 删除集合中的指定元素
set.clear() # 清空集合
set.copy() # 对集合进行浅复制
在对集合做运算时,不会影响原来的集合,而是返回一个运算结果
s = {1,2,3,4,5}
s2 = {3,4,5,6,7}
result = s & s2 # & 交集运算,{3, 4, 5}
result = s | s2 # | 并集运算,{1,2,3,4,5,6,7}
result = s - s2 # - 差集,{1, 2}
result = s ^ s2 # ^ 异或集 获取只在一个集合中出现的元素,{1, 2, 6, 7}
# <= 检查一个集合是否是另一个集合的子集
# 如果a集合中的元素全部都在b集合中出现,那么a集合就是b集合的子集,b集合是a集合超集
result = {1,2,3} <= {1,2,3} # True
result = {1,2,3,4,5} <= {1,2,3} # False
# < 检查一个集合是否是另一个集合的真子集
# 如果超集b中含有子集a中所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集
result = {1,2,3} < {1,2,3} # False
result = {1,2,3} < {1,2,3,4,5} # True
# >= 检查一个集合是否是另一个的超集
# > 检查一个集合是否是另一个的真超集
函数
参数
指定了默认值以后,如果用户传递了参数则默认值没有任何作用
如果用户没有传递,则默认值就会生效
def fn(a = 5 , b = 10 , c = 20):
实参的传递方式
位置参数就是将对应位置的实参复制给对应位置的形参
fn(1 , 2 , 3)
关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数
fn(b=1 , c=2 , a=3)
位置参数和关键字参数可以混合使用,混合使用关键字和位置参数时,必须将位置参数写到前面
fn(1,c=30)
形参的修改
在函数中对形参进行重新赋值,不会影响其他的变量
a = 20
如果形参执行的是一个对象,当我们通过形参去修改对象时会影响到所有指向该对象的变量
a[0] = 30
不定长的参数
在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参
它将会将所有的实参保存到一个元组中
def sum(*nums):
print(type(nums)) # <class 'tuple'>
带星号的形参只能有一个,不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
def fn2(a,*b,c):
fn2(1, 2, 3, 4, c=5)
如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递
def fn2(*,a,b,c):
**形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中,字典的key就是参数的名字,字典的value就是参数的值,**形参只能有一个,并且必须写在所有参数的最后
def fn3(b,c,**a):
print('a =',a,type(a)) # a为字典类型
fn3(b=1,d=2,c=3,e=10,f=20)
参数的解包(拆包)
传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递,这里要求序列中元素的个数必须和形参的个数的一致
def fn4(a,b,c):
t = (10,20,30)
fn4(*t)
通过**来对一个字典进行解包操作,要求字典里的key必须与形参的名称一致,不能多也不能少
d = {'a':100,'b':200,'c':300}
fn4(**d)
参数
通过 return 来指定函数的返回值
在函数中,return后的代码都不会执行,return 一旦执行函数自动结束
return 后边可以跟任意的对象,返回值甚至可以是一个函数
def fn(a):
def fn2():
print('a:%s'%a)
return fn2
r=fn(1)
r()
文档字符串(doc str)
help()是Python中的内置函数,通过help()函数可以查询python中的函数的用法,语法:help(函数对象)
help(print) # 获取print()函数的使用说明
在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明
当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串
def fn(a:int,b:bool,c:str='hello') -> int:
'''
这是一个文档字符串的示例
函数的参数:
a,作用,类型,默认值。。。。
b,作用,类型,默认值。。。。
c,作用,类型,默认值。。。。
'''
return 10
def fn2():
'函数2的描述'
print(1)
help(fn)
help(fn2)
作用域与命名空间
全局作用域
- 全局作用域在程序执行时创建,在程序执行结束时销毁
- 所有函数以外的区域都是全局作用域
- 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
函数作用域
- 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域
- 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
变量的查找
- 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
如果没有则继续去上一级作用域中寻找,如果有则使用,
如果依然没有则继续去上一级作用域中寻找,以此类推
直到找到全局作用域,依然没有找到,则会抛出异常
在函数中为变量赋值时,默认都是为局部变量赋值
如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量
def fn3():
global x
x=10
命名空间(namespace)
命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
每一个作用域都会有一个它对应的命名空间,全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
命名空间实际上就是一个字典,是一个专门用来存储变量的字典
locals()用来获取当前作用域的命名空间,返回的是一个字典
如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
scope = locals()
scope['c'] = 1000 # 向字典中添加key-value就相当于在作用域中创建了一个变量(一般不建议这么做)
globals() 函数可以用来在任意位置获取全局命名空间
global_scope = globals()
global_scope['a'] = 30
高阶函数
接收函数作为参数,或者将函数作为返回值的函数是高阶函数
匿名函数 lambda 函数表达式 (语法糖)
lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
语法:lambda 参数列表 : 返回值
匿名函数一般都是作为参数使用,其他地方一般不会使用
fn6 = lambda a,b : a + b
fn6(1,2)
filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
参数:
1.函数,根据该函数来过滤序列
2.需要过滤的序列(可迭代的结构)
返回值:filter对象,可以通过list()或者for循环取出内容
my_list=[1,2,3,4]
r=filter(lambda i: i%2==0, my_list)
list(r)
map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
返回值:map对象,可以通过list()或者for循环取出内容
my_list=[1,2,3,4]
r=map(lambda i: i ** 2, my_list)
list(r)
闭包
通过闭包可以创建一些只有当前函数能访问的变量,可以将一些私有的数据藏到的闭包中
形成闭包的要件
① 函数嵌套
② 将内部函数作为返回值返回
③ 内部函数必须要使用到外部函数的变量
def make_averager():
# 创建一个列表,用来保存数值
nums = []
# 创建一个函数,用来计算平均值
def averager(n) :
# 将n添加到列表中
nums.append(n)
# 求平均值
return sum(nums)/len(nums)
return averager
averager = make_averager()
print(averager(10))
print(averager(20))
装饰器
装饰器本质上就是一个闭包,在不改变原函数的前提下拓展被装饰函数的功能。
使用时只需要在函数前加上@wrapper。
装饰器可以分为内置装饰器(@staticmethod,@classmethod,@property),自定装饰器两大类。
装饰器可以应用在授权,日志、事务处理、缓存等场景
内置装饰器
@staticmethod
静态方法
不需要 self ,cls参数
调用方式:类名.方法名()
@classmethod
类方法
cls做为方法的第一个参数,隐式的将类做为对象传递给方法,调用时无须实例化。
调用方式:类名.方法名()
@property
类属性
使调用类中的方法像引用类中的字段属性一样。被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式。
调用方式:实例名.方法名,注意不加()
自定义装饰器
使用位置参数 *args 和关键字参数 **kwargs ,自定义一个通用的装饰器函数 wrapper。
# 通用装饰器
def wrapper(func): # 装饰器函数
def inner(*args, **kwargs): # 接受被装饰函数传参
print('inner')
return func(*args, **kwargs) # 执行被装饰函数
return inner # 闭包,外部函数返回值是内部函数
@wrapper
def test(): # 被装饰函数
print("test")
装饰器函数的执行步骤:
把被装饰函数对象test 作为入参func 传给装饰器函数 wrapper
执行装饰器函数的外函数 wrapper()
执行装饰器函数的内函数 inner()
执行被装饰函数 test()
对于多个装饰器,和单个装饰器类似,只是把上一个装饰器返回的函数对象又作为下一个装饰器的参数传递进去了而已。
对象(Object)
定义类
# 在Python中是支持多重继承的
# 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法和属性
# 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
class MyClass([ParentClass1[, ParentClass2][, ParentClass3][...]]):
# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问到
# 但是类属性只能通过类对象来修改,无法通过实例对象修改
count = 0
# 类代码块,只执行一次
print('Hello MyClass')
# 以双下划线开头和双下划线结尾的特殊方法为“魔法方法”(magicmethod),不需要手动调用
# init会在对象创建以后立即执行,用于对象的初始化
def __init__(self, name):
# super() 可以用来获取当前类的父类,
# 并且通过super()返回对象调用父类方法时,不需要传递self
super().__init__(name)
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
self._name = name
# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 实例方法可以通过实例和类去调用
# 当通过实例调用时,会自动将当前调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时我们必须手动传递self
def test(self, arg1):
print('这是test方法~~~ ' , self)
# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
# 类方法可以通过类去调用,也可以通过实例调用,没有区别
@classmethod
def test_2(cls, arg1):
print('这是test_2方法,他是一个类方法~~~ ',cls)
print(cls.count)
# 静态方法
# 在类中使用 @staticmethod 来修饰的方法属于静态方法
# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
# 静态方法一般都是一些工具方法
@staticmethod
def test_3(arg1):
print('test_3执行了~~~')
创建对象
myclass = MyClass('name1')
# 当使用对象访问属性时,先寻找实例属性,如果没找到,再找所属类的类属性,还没找到会找父类的类属性
print(myclass.count)
# 这样不会改变类属性的值,而是myclass对象新增了一个count实例属性
myclass.count = 1
# 找到实例属性,值为1
print(myclass.count)
# 删除实例属性
del myclass.count
# 找到类属性,值为0
print(myclass.count)
# 改变类属性的值
MyClass.count = 2
# 如果使用类调用:MyClass.test(myclass, 'abcd')
myclass.test('abcd')
封装
Python中没有提供严格意义上的外部不可访问的属性,只能按照约定俗成的方式去遵守
变量以单下划线开头,代表不能被直接访问,类似于C++中的protected型,这样的变量也不能被 import module_name导入
通过import *引入模块时不会引入对应的变量
模块内部可以直接访问到
通过模块.变量名也可以访问到
变量以双下划线开头,表示为类的私有成员,不能被导入和其他类变量访问
实际是Python会自动改名为_类名__属性名,可以使用_类名__属性名强制访问
因为双下划线并不能真正保证属性私有,所以实际运用时一般把不想外部直接访问的属性名/方法名统一使用单下划线开头的命名方式
可以提供setter/getter方法用来访问内部属性
def get_name(self):
return self._name
def set_name(self , name):
self._name = name
可以使用Property装饰器把getter方法变成属性的方式访问
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# setter方法的装饰器:@属性名.setter
@name.setter
def name(self , name):
print('setter方法调用了')
self._name = name
# deleter方法的装饰器:@属性名.deleter
@name.deleter
def name(self):
print('deleter方法调用了')
del self._name
魔术方法/特殊方法
特殊方法,也称为魔术方法,都是使用__开头和结尾的,一般不需要我们手动调用,需要在一些特殊情况下自动执行
# 在创建类实例时被调用,返回值应该是新的对象实例
# 典型的实现通过使用super().__new__(cls[, ...])创建实例,然后根据需要修改实例,然后再返回
__new__(cls[, ...])
# 如果__new__返回了实例,则自动调用__init__进行对象的初始化。__init__不能有非None返回值。
__init__(self[, ...])
# 在Python中有自动的垃圾回收机制,它会自动将没有被引用的对象删除,__del__会在对象被垃圾回收前调用
# 如果基类实现了__del__,子类实现时需要显示调用父类的__del__以确保正确删除实例的基类部分。
__del__(self)
# __repr__()这个特殊方法会在对当前对象使用repr()函数时调用
# 它的作用是指定对象在 ‘交互模式’中直接输出的效果
def __repr__(self):
return 'Hello'
# __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用
# 它的作用可以用来指定对象转换为字符串的结果 (print函数)
def __str__(self):
return 'Person [name=%s , age=%d]'%(self.name,self.age)
# bytes函数调用时把对象转换成bytes对象
__bytes__(self)
# format函数调用时会调用此方法,format_spec是代表格式的字符串。返回值为格式化后的字符串。
__format__(self, format_spec)
# 使用比较运算符时调用下面的方法
__lt__(self, other)
__le__(self, other)
__eq__(self, other)
__ne__(self, other)
__gt__(self, other)
__ge__(self, other)
# hash函数调用时会调用此方法,返回值为整数。
# 建议的做法是把参与比较的对象全部组件的哈希值混在一起,即将它们打包为一个元组并对该元组做哈希运算。
# hash() 会从一个对象自定义的 __hash__() 方法返回值中截断为 Py_ssize_t 的大小。通常对 64 位构建为 8 字节,对 32 位构建为 4 字节。
# 如果一个类没有定义__eq__()方法,它也不应该定义__hash__()操作;如果它定义了__eq__()而没有定义__hash__(),那么它的实例将不能用作可散列集合中的项。
# 如果一个类定义了可变对象并实现了__eq__()方法,那么它就不应该实现__hash__(),因为可哈希集合的实现要求键的哈希值是不可变的(如果对象的哈希值发生变化,那么它将位于错误的哈希桶中)。
def __hash__(self):
return hash((self.name, self.nick, self.color))
# 调用此方法以实现真值检测以及内置的 bool() 操作;应该返回 False 或 True。
# 如果未定义此方法,则会查找并调用 __len__() 并在其返回非零值时视对象的逻辑值为真。
# 如果一个类既未定义 __len__() 也未定义 __bool__() 则视其所有实例的逻辑值为真。
__bool__(self)
# 算术运算方法(+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |),self为运算符左边的值
__add__(self, other)
__sub__(self, other)
__mul__(self, other)
__matmul__(self, other)
__truediv__(self, other)
__floordiv__(self, other)
__mod__(self, other)
__divmod__(self, other)
__pow__(self, other[, modulo])
__lshift__(self, other)
__rshift__(self, other)
__and__(self, other)
__xor__(self, other)
__or__(self, other)
# 算术运算方法(+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |),self为运算符右边的值
# 当算术运算符左边的对象没有定义对应的方法时,对右边对象尝试下面的方法。x-y = type(y).__rsub__(y, x)
__radd__(self, other)
__rsub__(self, other)
__rmul__(self, other)
__rmatmul__(self, other)
__rtruediv__(self, other)
__rfloordiv__(self, other)
__rmod__(self, other)
__rdivmod__(self, other)
__rpow__(self, other[, modulo])
__rlshift__(self, other)
__rrshift__(self, other)
__rand__(self, other)
__rxor__(self, other)¶
__ror__(self, other)
# 扩展算术赋值(+=, -=, *=, @=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=)
# 这些方法应该尝试进行自身操作 (修改 self) 并返回结果 (结果应该但并非必须为 self)。
# 如果某个方法未被定义,相应的扩展算术赋值将回退到普通方法。例如,如果 x 是具有 __iadd__() 方法的类的一个实例,则 x += y 就等价于 x = x.__iadd__(y)。否则就如 x + y 的求值一样选择 x.__add__(y) 和 y.__radd__(x)。
__iadd__(self, other)
__isub__(self, other)
__imul__(self, other)
__imatmul__(self, other)
__itruediv__(self, other)
__ifloordiv__(self, other)
__imod__(self, other)
__ipow__(self, other[, modulo])
__ilshift__(self, other)
__irshift__(self, other)
__iand__(self, other)
__ixor__(self, other)
__ior__(self, other)
# 调用此方法以实现一元算术运算 (-, +, abs() 和 ~)
__neg__(self)
__pos__(self)
__abs__(self)
__invert__(self)
# 调用这些方法以实现内置函数 complex(), int() 和 float()。应当返回一个相应类型的值。
__complex__(self)
__int__(self)
__float__(self)
# 调用此方法以实现 operator.index() 以及 Python 需要无损地将数字对象转换为整数对象的场合(例如切片或是内置的 bin(), hex() 和 oct() 函数)。
# 存在此方法表明数字对象属于整数类型。 必须返回一个整数。
# 如果未定义 __int__(), __float__() 和 __complex__() 则相应的内置函数 int(), float() 和 complex() 将回退为 __index__()。
__index__(self)
# 调用这些方法以实现内置函数 round() 以及 math 函数 trunc(), floor() 和 ceil()。
# 除了将 ndigits 传给 __round__() 的情况之外这些方法的返回值都应当是原对象截断为 Integral (通常为 int)。
__round__(self[, ndigits])
__trunc__(self)
__floor__(self)
__ceil__(self)
# len函数调用时会调用此方法返回一个>=0的整数
__len__(self)
# 调用此方法以实现 operator.length_hint()。 应该返回对象长度的估计值(可能大于或小于实际长度)。
# 此方法纯粹是为了优化性能,并不要求正确无误。
__length_hint__(self)
# 实现self[key]用法的返回值
# 对于 sequence 类型,接受的键应为整数和切片对象。 请注意负数索引(如果类想要模拟 sequence 类型)的特殊解读是依赖于 __getitem__() 方法。
# 如果 key 的类型不正确,则会引发 TypeError;如果为序列索引集范围以外的值(在进行任何负数索引的特殊解读之后),则应当引发 IndexError。
# 对于 mapping 类型,如果 key 找不到(不在容器中),则应当引发 KeyError。
__getitem__(self, key)
# 调用此方法以实现向 self[key] 赋值。
__setitem__(self, key, value)
# 调用此方法以实现 self[key] 的删除。
__delitem__(self, key)
# 此方法由 dict.__getitem__() 在找不到字典中的键时调用以实现 dict 子类的 self[key]。
__missing__(self, key)
# 此方法会在需要为一个容器创建 iterator 时被调用。 此方法应当返回一个新的迭代器对象,它可以对容器中的所有对象执行迭代。 对于映射,它应当对窗口中的键执行迭代。
__iter__(self)
# 此方法(如果存在)会被 reversed() 内置函数调用以实现逆向迭代。它应当返回一个新的以逆序逐个迭代容器内所有对象的迭代器对象。
# 如果未提供 __reversed__() 方法,则 reversed() 内置函数将回退到使用序列协议 (__len__() 和 __getitem__())。
# 支持序列协议的对象应当仅在能够提供比 reversed() 所提供的实现更高效的实现时才提供 __reversed__() 方法。
__reversed__(self)
# 调用此方法以实现成员检测运算符。如果 item 是 self 的成员则应返回真,否则返回假。对于映射类型,此检测应基于映射的键而不是值或者键值对。
# 对于未定义 __contains__() 的对象,成员检测将首先尝试通过 __iter__() 进行迭代,然后再使用 __getitem__() 的旧式序列迭代协议
__contains__(self, item)
类型判断方法
type(对象/类) 返回对象/类的类型
isinstance(对象, 类) 用来判断对象是否是类的实例
类名.__bases__ 这个属性可以用来获取当前类的所有父类
issubclass(类1 , 类2) 用来判断类1是否是类2的子类
metaclass
metaclass是什么
metaclass直译为元类,他可以控制类的属性和类实例的创建过程。使用metaclass的主要目的也是在创建类实例的时候,精准的控制和定义类的创建过程和类对象的创建过程。
在python中一切皆对象:一个整数是对象,一个字符串是对象,一个类实例是对象,类本身也是对象。一个类也是一个对象,和其他类一样,它是metaclass的一个实例。
默认的metaclass是type类型的
type和object的关系
在Python3中,object是所有类的基类,内置的类、自定义的类都直接或间接的继承自object类。在python源码中type类也继承自object类。
这就对我们造成了极大的困扰,主要有以下三点:
1.type是一个metaclass,而且是一个默认的metaclass。也就是说,type是object的类型,object是type的一个实例;
2.type是object的一个子类,继承了object的所有属性和方法;
3.type还是可以callable的,即实现了__call__方法,可以当做一个函数使用。
type和object的关系有点像“鸡生蛋,蛋生鸡”一样。type是object的子类,同时object又是type的一个实例(type是object的类型),二者是不可分离的。另外,type的类型也是type。
所有的类都继承自object,包括内置的类和用户自定义的类。一般来说,类Class的类型为type(即一般的类的metaclass是type,是type的一个实例)。如果要改变类的metaclass,必须要在定义类时显式地指定它的metaclass: class ClassA(metaclass=CustomMetaclass)
自定义metaclass
自定义的metaclass必须继承自type。自定义的metaclass通常以Metaclass或Meta作为后缀结尾。
此外,自定义metaclass,需要注意以下几点:
object的__init__方法只有一个参数: def __init__(self)。
但type重写了__init__方法,有四个参数:def __init__(cls, what, bases=None, dict=None)。
因为自定义metaclass类继承自type,所以重写__init__方法时也要有4个参数。
对于普通的类,重写__call__方法说明类的对象是可调用的。
在metaclass中__call__方法还负责对象的创建。
一个对象的创建过程:
metaclass.__init__进行一些初始化的操作,如一些全局变量的初始化;
metaclass.__call__创建实例,在创建过程中会调用class的__new__和__init__方法;
class.__new__进行具体的实例化操作,并返回一个实例对象obj;
class.__init__对返回的实例对象obj进行初始化,如一些状态和属性的设置;
返回一个用户真正需要使用的对象obj。
class CustomMetaclass(type):
def __init__(cls, what, bases=None, dict=None):
print('CustomMetaclass.__init__ cls: ', cls)
super().__init__(what, bases, dict)
def __call__(cls, *args, **kwargs):
print('CustomMetaclass.__call__ args: ', args, kwargs)
self = super(CustomMetaclass, cls).__call__(*args, **kwargs)
print('CustomMetaclass.__call__ self: ', self)
return self
class CustomClass(metaclass=CustomMetaclass):
def __new__(cls, *args, **kwargs):
self = super().__new__(cls)
print('CustomClass.__new__ self: ', self)
return self
def __init__(self, *args, **kwargs):
print('CustomClass.__init__ self: ', self)
super().__init__()
def __call__(self, *args, **kwargs):
print('CustomClass.__call__ args: ', args)
obj = CustomClass('arg1', 'arg2', kwarg1=1, kwarg2=2)
抽象基类(ABC, Abstract Base Classes)
abstract base class – 抽象基类:抽象基类简称ABC,是对duck-typing(鸭子类型)的补充,它提供了一种定义接口的新方式,相比之下其他及其例如hasattr()显得过于笨拙或有微妙错误(例如使用魔法方法)。
ACB引入了虚拟子类,这种类并非继承自其他类,但却能被isinstance()和issubclass()所认可。
Python 自带许多内置的 ABC 用于实现数据结构(在 collections.abc 模块中)、数字(在 numbers 模块中)、流(在 io 模块中)、导入查找器和加载器(在 importlib.abc 模块中)。
Python库包中的abc定义了抽象基类(ABC, Abstract Base Classes)的组件。abc模块提供了一个抽象基类元类(ABCMeta),用来定义抽象类。同时提供了一个工具类ABC,可以用它以继承的方式定义抽象基类。
指定元类的方式定义抽象类(Python3.0+)
class MyClass(metaclass=abc.ABCMeta)
@abc.abstractmethod
def mymethod(self, args):pass
指定父类的方式定义抽象类(Python3.4+)
class MyClass(abc.ABC)
@abc.abstractmethod
def mymethod(self, args):pass
模块与包
模块
在Python中一个py文件就是一个模块,模块名要符合标识符的规范
在一个模块中引入外部模块
import 模块名 [as 模块别名]
可以引入同一个模块多次,但是模块的实例只会创建一个
import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
可以使用模块名/模块别名.变量名引用模块内的变量/类/函数
from 模块名 import 变量[ as 别名][,变量[ as 别名]]....
可以只引入模块中的部分内容
from 模块名 import *
引入模块的所有内容,一般不会使用
添加了_的变量,只能在模块内部访问,在通过import * 引入时,不会引入_开头的变量
在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
__name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块,主模块就是我们直接通过 python 执行的模块
模块内的测试代码不需要被别的模块引入
if __name__ == '__main__':
test()
test2()
包
包也是一个模块,普通的模块就是一个py文件,而包是一个文件夹
包中必须要有一个 __init__.py 这个文件,包被导入时__init__.py文件被隐式执行,它所定义的对象被绑定到包的名字空间中。
实际应用中可以不在__init__.py中写逻辑,而是引入包中的包含逻辑的模块
引入包内容
import 包名[ as 包别名]
from 包名 import 模块[ as 别名][,模块[ as 别名]]...
from 包名.模块 import 变量[ as 别名][,变量[ as 别名]]....
缓存
__pycache__ 是模块的缓存文件夹
py代码在执行前,需要被解析器先转换为机器码,然后再执行
所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码然后再交由计算机执行
而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中
这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可
异常
处理异常
try:
代码块(可能出现错误的语句)
except 异常类型 as 异常名:
代码块(出现错误以后的处理方式)
except 异常类型 as 异常名:
代码块(出现错误以后的处理方式)
except 异常类型 as 异常名:
代码块(出现错误以后的处理方式)
else:
代码块(没出错时要执行的语句)
finally:
代码块(该代码块总会执行)
try是必须的 else语句有没有都行
except和finally至少有一个
异常的传播(抛出异常)
当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,
如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,
如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播
直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息
当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,
而异常传播时,实际上就是异常对象抛给了调用处
比如 : ZeroDivisionError类的对象专门用来表示除0的异常
NameError类的对象专门用来处理变量错误的异常
....
抛出异常
可以使用 raise 语句来抛出异常,
raise语句后需要跟一个异常类 或 异常的实例
文件
打开关闭
# 打开文件,参数说明参见Python的标准库->内置函数->open
file_obj = open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# 关闭文件
file_obj.close()
# 使用with的写法可以省去手动关闭文件
with open(file_name) as file_obj :
# 文件的读写处理,不用手动关闭file_obj
读写操作
# 读取更新模式打开文本文件,读取/写入的为字符串
file_obj = open(file_name, 'r+', encoding='utf-8')
# 读取更新模式打开二进制文件,读取返回的是bytes对象,写入时为bytes/bytearray/array.array/memoryview
file_obj = open(file_name, 'r+b', encoding='utf-8')
# 读取100个字符(文本模式)/字节(二进制模式),返回字符串/bytes对象,如果之前已经读到了文件结尾则返回''/b''
content = file_obj.read(100)
# 一次读取完剩余的内容,返回字符串/bytes对象
content = file_obj.read()
# 读取1行文字,返回字符串/bytes对象,如果之前已经读到了文件结尾则返回''/b''
content = file_obj.readline()
# 读取10行文字,返回行符串/bytes对象列表
content = file_obj.readlines(10)
# 一次读完剩余的内容,返回行符串/bytes对象列表
content = file_obj.readlines()
# 写出文本内容,返回写出的字符数
count = file_obj.write('aaa\n')
count = file_obj.write(b'aaa\n')
# 写出序列中的内容,方法本身不会添加换行,需要自己为输出字符串添加换行符
file_obj.writelines(["line 1\n", "line 2"])
file_obj.writelines([b"line 1\n", b"line 2"])
# 返回当前读取的位置(字节数)
file_obj.tell()
# 读取位置移动到第55字节
file_obj.seek(55)
file_obj.seek(55, 0)
# 读取位置从当前位置计算移动70个字节
file_obj.seek(70, 1)
# 读取位置移动到倒数第10个字节
file_obj.seek(-10, 2)
文章来源:https://www.toymoban.com/news/detail-519545.html
到了这里,关于Python3 学习(一)-语法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!