#!/user/bin/env python
在文件开头加
# encoding=utf-8
或者
# coding=utf-8
或者(官方推荐)
# _*_coding:utf-8_*_
import keyword
print(keyword.kwlist)
查看类型
# 输出
type('需要查看的类型变量或字符串或数字等等')
int
1)二进制:0b+二进制数(注意是数字0不是字母o)
2)八进制:0/0o+八进制数
3)十进制:十进制数
4)十六进制:0x+十六进制数
long(python2的类型,python3可以通过int自动调整)
float
1)由整数和小数组成,如155.66
2)也可以使用科学计数法1.5566e2
complex(复数)
1)a+bj
2)a,b均为浮点数,complex(a, b)
1)非原始字符串(\加上\或者字母表示转义,仅仅\表示续行符)
‘string’
“string”
"""string"""
'''string'''
2)原始字符串(转义字符不生效)
r‘string’
r“string”
r"""string"""
r'''string'''
3)字符串打印与多行关系
# 多行打印(也可以作为多行注释)
str1 = '''string1
string2
string3
.
.
.
'''
# 把换行的连接起来一
str2 = 'string1'\
'string2'
# 把换行的连接起来二
str2 = ('string1'
'string2')
4)字符串拼接
# 方式一:直接+拼接
result = "aaa" + "bbb"
# 方式二: 直接放在一起
result = "aaa""bbb"
# 方式三: ”xxx%sxxx" % (a, b),利用格式化符
result = "%s%s" % ("aaa", "bbb")
# 方式四: 字符串乘法 string * int
result = string * 100
print(result)
5)字符串切片
概念:获取一个字符串的某个片段
# 获取一个字符 下标法获取 注意不能越界,i是字符串下标
# i可以为负,反向遍历获取值
string[i]
# 获取一片字符串,包头不包尾[x1, x2)
string[x1:x2]
string[起始值:结束值:步长]
# 获取所有(取默认值起始值0:结束值len(string):步长1)
string[::]
# 相当于
string[0:len(string):1]
# 反向获取整个字符串
string[::-1]
# 相当于
string[-1:-(len(string)+1):-1]
注:步长大于0,从左到右,小于0,从右到左,不能从头部跳到尾部,从尾部跳到头部,即起始值与结束值要与方向保持一致
6)字符串方法
# 字符串查找的方法
# 获取字符串长度
len(string)
# 查找方法
# 对象.find(目标片段, 起始值, 结束值) 找到返回指定索引并立即停止遍历,找不到返回-1
print(string.find('string1', 0, len(string)))
# rfind()与find()只是方向相反,但是起始值与结束值还是同向
print(string.rfind('string1', 0, len(string))))
# 使用对象.index(string1),找不到不会返回-1,而是直接抛异常
sring.index(string1)
sring.rindex(string1)
# 使用对象.count(string1)统计出现次数
string.count(string1)
# 字符串转换的方法
'''
替换字符串
replace(old, new[, count])
old 需要替换的原字符串
new 新字符串
count 替换个数,不写默认全部
返回值: 返回替换后的新字符串
注意:原来的字符串不会改变
'''
print(string.replace(str1, str2, count))
'''
字符串第一个词首字母的大写
capitalize()
返回值: 返回修改后的新字符串
注意:原来的字符串不会改变
'''
print(string.capitalize())
print(string)
'''
字符串每个单词首字母大写(只要不是字母,其他字符隔开都认为是一个单词)
title()
返回值: 返回修改后的新字符串
注意:原来的字符串不会改变
'''
print(string.title())
print(string)
'''
字符串每个字符小写
lower()
返回值: 返回修改后的新字符串
注意:原来的字符串不会改变
'''
print(string.lower())
print(string)
'''
字符串每个字符大写
upper()
返回值: 返回修改后的新字符串
注意:原来的字符串不会改变
'''
print(string.upper())
print(string)
# 字符串填充压缩
'''
根据指定的一个字符fillchar,将原有字符串填充到指定长度width
ljust(width, fillchar)
返回值: 返回填充后的字符串
注意: 原有字符串不会改变,只有原字符串长度 < 指定结果长度时才会填充
'''
print(string.ljust(10, 'l'))
print(string)
'''
根据指定的一个字符fillchar,将原有字符串向左填充到指定长度width(字符串前面)
rjust(width, fillchar)
返回值: 返回填充后的字符串
注意: 原有字符串不会改变,只有原字符串长度 < 指定结果长度时才会填充
'''
print(string.rjust(10, 'l'))
print(string)
'''
根据指定的一个字符fillchar,将原有字符串两边填充到指定长度width(字符串在中间)
center(width, fillchar)
返回值: 返回填充后的字符串
注意: 原有字符串不会改变,只有原字符串长度 < 指定结果长度时才会填充
'''
print(string.center(10, 'l'))
print(string)
'''
移除原有字符串指定字符(默认为空白字符)
仅仅移除左侧
lstrip(chars)
参数:需要移除的字符集,移除'a'|'b'|'c'...
返回值: 返回移除后的字符串
注意: 原有字符串不会改变
'''
print("|" + string.lstrip() + "|")
print("|" + string.lstrip("wo") + "|")
print("|" + string + "|")
'''
移除原有字符串指定字符(默认为空白字符)
仅仅移除左侧
rstrip(chars)
参数:需要移除的字符集,移除'a'|'b'|'c'...
返回值: 返回移除后的字符串
注意: 原有字符串不会改变,向左没有检测到字符集的字符,直接终止
'''
print("|" + string.rstrip() + "|")
print("|" + string.rstrip("wo") + "|")
print("|" + string + "|")
# 字符串的分隔拼接
'''
将一个大的字符串分隔成几个子字符串
split(sep, maxsplit)
参数一:sep 分隔符
参数二: maxsplit 分隔次数,可以省略,有多少分隔多少
返回值:返回分隔后的字符串,组成为列表(list)
注意:不会改变原字符串
'''
result = string.split("-", 4)
print(result)
print(string)
'''
根据指定的分隔符,返回(分隔符左侧内容, 分隔符, 分隔符右侧内容)
partition(sep)
参数一:sep 分隔符
返回值:
如果找到分隔符,返回(分隔符左侧内容, 分隔符, 分隔符右侧内容) tuple类型
如果没有找到分隔符,返回(原字符串, "", "") tuple类型
注意:不会改变原字符串,从左侧开始找分隔符
'''
result = string.partition("-")
print(result)
print(string)
'''
根据指定的分隔符,返回(分隔符左侧内容, 分隔符, 分隔符右侧内容)
rpartition(sep)
参数一:sep 分隔符
返回值:
如果找到分隔符,返回(分隔符左侧内容, 分隔符, 分隔符右侧内容) tuple类型
如果没有找到分隔符,返回("", "", 原字符串) tuple类型
注意:不会改变原字符串,从右侧开始找分隔符
'''
result = string.rpartition("-")
print(result)
print(string)
'''
按照换行符(\r,\n),将字符串拆成多个元素,保存到列表中
splitlines(keepends)
参数一:keepends 是否保留换行符 bool类型
返回值:
被换行符分隔的多个字符串,作为元素组成的列表
list类型
注意:不会改变原字符串
'''
result = string.splitlines(True)
print(result)
print(string)
'''
根据指定字符串,将给定的可迭代对象,进行拼接,得到拼接后的拼接字符串
join(iterable)
参数一:iterable
可迭代对象
字符串
元祖
列表
...
返回值:拼接好的新字符串
'''
items = ["sz", "18", "gg"]
result = "-".join(items)
print(result)
# 字符串函数判定操作
'''
字符串中是否所有的字符都是字母
不包含该数字,特殊符号,标点符号等等
至少有一个字符
语法:isalpha()
返回值:是否全部是字母,bool类型
'''
print(name.isalpha())
'''
字符串中是否所有的字符都是数字
不包含该字母,特殊符号,标点符号等等
至少有一个字符
语法:isdigit()
返回值:是否全部是数字,bool类型
'''
print(string.isdigit())
'''
字符串中是否所有的字符都是数字或字母
不包含该特殊符号,标点符号等等
至少有一个字符
语法:isalnum()
返回值:是否全部是字母或数字,bool类型
'''
print(string.isalnum())
'''
字符串中是否所有的字符都是空白符
包含空格,缩进,换行等不可见转义符
至少有一个字符
语法:isspace()
返回值:是否全部是空白符,bool类型
'''
print(string.isspace())
'''
判断一个字符串是否以某个前缀开头
语法:startswith(prefix, start=0, end=len(str))
参数一:prefix 需要判断的前缀字符串
参数二:start 判定的起始位置
参数三:end 判定的终止位置
返回值:是否以指定前缀开头
bool 类型
'''
print(string.startswith("21", 2, 4))
'''
判断一个字符串是否以某个后缀结尾
语法:endswith(suffix, start=0, end=len(str))
参数一:suffix 需要判断的后缀字符串
参数二:start 判定的起始位置
参数三:end 判定的终止位置
返回值:是否以指定前缀开头
bool 类型
'''
print(string.endswith(".doc"))
# in 判断一个字符串,是否被另一个字符串包含
# not in 判断一个字符串,是否不被另一个字符串包含
print("wo" in "who am wo")
print("wo" not in "who am wo")
1)概念:有序可变的集合
2)定义:
列表变量名 = [元素1, 元素2, …],列表的嵌套,即列表的元素可以为列表,但注意不能相互嵌套
列表生成式:
range(stop) : [0, 1, 2, …, stop-1];
range(start, stop[, step]) : [start, start+2*step, …],step步长默认为1
注:由于防止生成的列表没有被使用,python3做了一些改变,不会立即生成列表
列表推导式:从一个list推导出另一个list;映射解析:一对一变更;过滤:从多到少
语法:[表达式 for 变量 in 列表] 或 [表达式 for 变量 in 列表 if条件],其中for遍历可以有多个,表示多层循环遍历
# 列表推导式
nums = [1, 2, 3, 4, 5]
# resList = [num ** 2 for num in nums if num % 2 != 0]
# resList = [num ** 2 for num in nums for num2 in nums]
resList = list(num ** 2 for num in nums for num2 in nums)
print(resList)
列表常规方法操作
# 列表添加操作
'''
append
作用:往列表最后追加一个元素
语法:list.append(object)
参数:object为添加的元素
返回值:None
注意:会修改原列表
'''
nums = [1, 2, 3, 4]
print(nums)
print(nums.append(5))
print(nums)
'''
append
作用:往列表指定索引处追加一个元素
语法:list.insert(index, object)
参数:index为索引(下标),object为添加的元素
返回值:None
注意:会修改原列表
'''
nums = [1, 2, 3, 4]
print(nums)
print(nums.insert(1, 5))
print(nums)
'''
extend
作用:往列表拓展另一个可迭代序列
语法:list.extend(iterable)
参数:iterable为可迭代集合
字符串、列表、元组、等等
返回值:None
注意:会修改原列表,和append区别是两个集合的拼接
'''
nums = [1, 2, 3, 4]
nums2 = ["a", "b", "c"]
print(nums)
print(nums.extend(nums2))
print(nums)
# 乘法运算
nums = [1, 2, 3, 4]
print(nums * 3)
# 加法运算
nums1 = [1, 2, 3, 4]
nums2 = ["a", "b", "c"]
# nums3 = "abf" 不能拼接字符串
print(nums1 + nums2)
# 列表删除操作
'''
del
作用:可以删除一个指定元素或对象
语法:del 指定元素
参数:无
返回值:无
注意:可以删除整个列表、某个元素、一个变量
'''
nums = [1, 2, 3, 4, 5]
# 删除某个元素
del nums[0]
# 删除整个列表
del nums
print(nums)
# 删除一个变量
num = 666
del num
print(num)
'''
pop
作用:移除并返回列表中指定索引对应元素
语法:list.pop(index = -1)
参数:index默认是-1,即最后一个元素
返回值:被删除元素
注意:会直接修改原数组,注意越界
'''
nums = [1, 2, 3, 4, 5]
print(nums.pop(2))
print(nums)
'''
remove
作用:移除列表中指定元素
语法:list.remove(object)
参数:object是待移除的元素
返回值:None
注意:会直接修改原数组,如果不存在,报错,存在多个,删除最左边一个,注意循环内删除列表元素的坑
'''
nums = [1, 2, 2, 3, 4, 5]
print(nums.remove(2))
print(nums)
nums2 = [1, 2, 2, 3, 4, 5, 2]
for num in nums2:
print(num)
if num == 2:
nums2.remove(2)
print(nums2)
# 修改列表
'''
通过下标修改指定列表的指定索引处的值
'''
nums = [1, 2, 3, 4, 5]
nums[2] = 6
# 列表查询
# 获取单个,元素通过下标(索引)查询
nums = [1, 2, 3, 4, 5, 5, 2, 6, 6]
print(nums[2])
# 获取元素索引 list.index(value,start,stop)
print(nums.index(5, 5, 6))
# 获取指定元素个数 count()
print(nums.count(5))
# 切片与字符串一样
print(nums[1:4:1])
print(nums[-1:-4:-2])
列表查询遍历操作:
根据元素进行遍历
# for item in list:
values = ['a', 'b', 'c', 'd']
for v in values:
currentIndex = 0
print(v)
print(values.index(v, currentIndex))
currentIndex += 1
根据索引进行遍历
# for index in range(len(list)):
values = ['a', 'b', 'c', 'd', 'e']
for index in range(len(values)):
print(index, values[index])
根据枚举对象进行遍历(了解)
values = ['a', 'b', 'c', 'd', 'e']
# 1.根据列表创建枚举对象
# 语法:enumerate(list, [start=0])
# print(list(enumerate(values)))
# 2.遍历枚举对象,可以直接遍历
for index, value in enumerate(values):
# for tupleValue in enumerate(values):
# print(tupleValue)
# print(tupleValue[0])
# print(tupleValue[1])
# index, value = tupleValue
print(index)
print(value)
根据迭代器进行遍历(了解)
l = [1, 2, 3, 5, 6]
# 创建迭代器对象
it = iter(l)
# 内部自动调整指针,指向下一个索引
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
# 迭代完成,继续迭代会报错StopIteration
print(next(it))
for v in it:
print(v)
print("===========")
# 不能多次迭代,只能重新创建迭代器对象
for v in it:
print(v)
迭代器
可迭代对象:能够被迭代的对象
判断方法:
from collections.abc import Iterable
isinstance(obj, Iterable)
判断依据:能否作用于for in
迭代器是可以记录遍历位置的对象,从第一个元素开始,往后只能通过next()函数进行遍历,只能往前,不能往后
判断方法:
from collections.abc import Iterator
isinstance(obj, Iterator)
判断依据:能否作用于next()函数
注意:迭代器也是可迭代对象,也可以使用for in
迭代器产生原因:
**仅仅迭代到某个元素时才会处理该元素:**在此之前,元素可以不存在,在此之后,元素可以销毁,适用于无限大集合,例如斐波那契数列
**提供了一个统一的访问集合的接口:**可以将所有可迭代对象转换成迭代器使用
iter(Iterable)
iter(str)
iter(list)
iter(tuple)
iter(dict)
...
注:迭代完成,继续迭代会报错StopIteration,使用for in,不能多次迭代,只能重新创建迭代器对象
列表其他操作
# 判断元素是否在集合
# in 判断元素是否在列表中(对其他集合和字符串通用)
# not in 判断元素是否在列表中(对其他集合和字符串通用)
# 比较
'''
cmp(val1,val2)
内建函数
如果比较字符串,列表等集合,从左往右逐个比较
val1 > val2 1
val1 = val2 0
val1 < val2 -1
python3.x不支持
python3使用比较运算符比较
'''
# python3
print([1, 2] > [1, 3])
# 排序方式一:内建函数,返回一个列表,原来列表不变
# s = "happynewYear"
s = [1, 2, 5, 6, 8, 9]
# 升序,返回一个列表
res = sorted(s)
print(res)
# print(s)
# 降序
res1 = sorted(s, reverse=True)
print(res1)
s1 = [("dd1", 18), ("dd5", 16), ("dd2", 28), ("dd1", 15)]
# 第一个值的比较排序
print(sorted(s1))
def getKey(x):
return x[1]
# 第二个值来排序
print(sorted(s1,key=getKey, reverse=True))
# 排序方式二:更改对象本身,返回值为None
val = [11, 2, 45, 56]
print(val.sort(), val)
s = [("dd1", 18), ("dd5", 16), ("dd2", 28), ("dd1", 15)]
print(s.sort())
def getKey(x):
return x[1]
# 第二个元素降序排序
print(s.sort(key=getKey, reverse=True), s)
'''
乱序
import random
random.shuffle(list)
返回值 :None
'''
import random
l = [1, 5, 98, 6, 2]
res = random.shuffle(l)
print(res, l)
'''
反转
list.reverse()
返回值 :None
'''
l = [1, 5, 98, 6, 2]
res = l.reverse()
print(res, l)
# 切片反转,返回值反转,不会改变本身
res1 = l[::-1]
print(res1, l)
1)概念:无序的,不可随机访问的,不可重复的元素集合
2)可变集合定义:
集合变量名 = {元素1, 元素2, …};
集合变量名 = set(iterable), 即可以转换字符串、列表、元组、字典为set集合,字典时,只生成key的集合;
集合的推导式:集合变量名={推导式}或者set(推导式)
# 集合推导式
# set5 = set(x for x in range(10) if x % 2 == 0)
set5 = {x for x in range(10) if x % 2 == 0}
print(set5, type(set5))
集合的嵌套,即元组的元素可以为元组,但注意不能相互嵌套
3) 不可变集合定义:
集合变量名 = frozenset(iterable), 即可以转换字符串、列表、元组、字典为set集合,字典时,只生成key的集合;
集合的推导式:集合变量名=frozenset(推导式)
fs = frozenset(x for x in range(10) if x % 2 == 0)
print(fs, type(fs))
4) 注意:
创建一个空集合时需要使用set()或者frozenset(),不能使用是s={},会被识别为dict字典
集合中的元素必须是可哈希的值:
如果一对象在自己的生命周期中有一哈希值(hash value),是不可变的,那么它是可哈希的(hashable)到,暂时认为是不可变类型
比如字典、列表是可变类型,元组、字符串是不可变类型
如果集合中的元素出现重复,则会被合并为一个
5) 集合常规操作方法:
a)可变集合:(元素为不可变类型,不能修改)
# 集合常用操作方法
# 增 返回值None
add = s.add(4)
print(s, type(s), add)
# 删
# s.remove(element) 返回值None 没有该元素,报错KeyError
remove = s.remove(4)
# remove = s.remove(5)
print(s, type(s), remove)
# s.discard(element) 返回值None 没有该元素,什么都不会发生
discard = s.discard(5)
print(s, type(s), discard)
# s.pop(element) 随机删除并返回集合中的某个元素,集合为空,报错
# p1 = s.pop()
# print(p1)
# s.clear() 返回值None,清空集合,集合仍存在
clear = s.clear()
print(s, clear)
# 查
# 无法通过索引或key进行查询
s = {1, 2, 3}
# for v in s:
# print(v)
# 1.生成一个迭代器
its = iter(s)
# 2.使用迭代器取访问(next() 或 for in)
# print(next(its))
# print(next(its))
# print(next(its))
# 指针为null
# print(next(its))
for it in its:
print(it)
print("==========")
# 迭代一次后,迭代器对象需要重新创建才可以遍历
for it in its:
print(it)
b) 不可变集合常用方法:(不能增删改)
# 不可变集合查询
fs = frozenset([1, 2, 3])
for f in fs:
print(f)
ifs = iter(fs)
# print(next(ifs))
# print(next(ifs))
# print(next(ifs))
for i in ifs:
print(i)
c) 集合之间交并差集判定操作:(可变集合与不可变集合做混合运算,返回值类型以运算符左侧类型为主)
s1 = {1, 2, 3, 5, 6, 9}
s2 = {2, 4, 3, 9, 8}
'''
交集
intersection(iterable)
字符串(只判断非数字)
元组
集合
列表
字典(只判断key)
...
逻辑与'&' 集合本身不会改变
intersection_update(iterable)
交集计算完后会赋值给原集合,所以只适用于可变集合
'''
res = s1.intersection(s2)
# set
print(res, type(res))
s3 = {1, 2, 3, 5, 6, 9}
s4 = frozenset([2, 4, 3, 9, 8])
# frozenset
res1 = s4.intersection(s3)
print(res1, type(res1))
res2 = s1.intersection_update(s2)
# res2:None s1:{9, 2, 3} s2:{2, 3, 4, 8, 9}
print(res2, type(res2), s1, s2)
# 集合本身不会改变
# res3 = s1 & s2
# print(res3, type(res3), s1, s2)
# set() 因为不会判断数字
print(s1.intersection("123"))
s5 = {"1", "2", "5"}
# 只能判定字符串
print(s5.intersection("123"))
print(s5.intersection(["1", "2", "6"]))
# 不能存在不可哈希的值["1", "5"]
print(s5.intersection(["1", "2", ["1", "5"]]))
print(s5.intersection({"1": "vv", "2": "jj", "6": "55"}))
'''
并集
union()
返回并集
逻辑或'|'
返回并集
update()
更新并集,原左侧集合更新为并集
'''
s3 = {1, 2, 3}
# s3 = frozenset([1, 2, 3])
s4 = {4, 2, 5}
# res1 = s3.union(s4)
# res1 = s3 | s4
# None, s3:{1, 2, 3, 4, 5}
res1 = s3.update(s4)
print(res1, type(res1), s3, s4)
'''
差集
difference()
返回差集
算术运算符'-'
返回并集
update()
更新并集,原左侧集合更新为并集
'''
# s3 = {1, 2, 3}
s3 = frozenset([1, 2, 3])
s4 = {4, 2, 5}
# res1 = s3.difference(s4)
res1 = s3 - s4
# None, s3:{1, 3}
# res1 = s3.difference_update(s4)
print(res1, type(res1), s3, s4)
'''
判定
两个集合不相交:isdisjoint()
一个集合包含另一个集合:issuperset()
一个集合包含于另一个集合:issubset()
'''
set1 = {1, 2, 3}
set2 = {1, 2}
# False
print(set1.isdisjoint(set2))
# True
print(set1.issuperset(set2))
# False
print(set1.issubset(set2))
print(set1.issubset(set1))
1)概念:有序不可变的集合
2)定义:
3) 元组常规操作方法:
元组不能增加、删除、修改元素。
'''
元祖查询
获取单个元素,下标法 tuple[index]
获取多个元素
tuple[start:stop:step] 与字符串和列表同理
'''
'''
元组获取
tuple.count(item), 统计元组中指定元素的个数,没有返回0
tuple.index(item), 获取元组中指定元素的索引,没有报错
内建函数
len(tuple), 返回元组的元素个数
max(tuple), 返回元组的元素最大值
min(tuple), 返回元组的元素最小值
'''
'''
in 判定元素是否在元组里面
not in判定元素是否不在元组里面
'''
# 比较
'''
cmp(val1,val2)
内建函数
如果比较字符串,列表等集合,从左往右逐个比较
val1 > val2 1
val1 = val2 0
val1 < val2 -1
python3.x不支持
python3使用比较运算符比较
'''
t = ('aa', 'bb', 'cc', "dd", "ee")
t1 = ('aa', 'bb', 'cc', "dd", "ee", "ff")
print(t > t1)
print(t == t)
print(t < t1)
# 元组拼接
'''
乘法拼接:tuple * int类型
加法拼接:tuple1 + tuple2
注意不同数据类型不能使用+拼接,保错
拆包
变量名1,变量名2... = (元素1,元素2,...)
括号可以省略
变量名1,变量名2... = 元素1,元素2,...
交换变量的值,也可以加括号
变量名1,变量名2 = =变量名2, 变量名1
'''
1)概念:无序的可变的键值对集合
2)定义:
3)字典常规操作方法:
# 字典常规操作
# 添加一个键值对 dictory[key] = value
# 删除操作
# 删除一个键值对 del dic[key],当删除的key不存在时,报错
'''
dic.pop(key[, default])
删除指定的键值对,并返回对应的值
如果key不存在,返回给的的default值,如果没有指定default值,会报错
'''
d = {"name": "admin", "age": 18}
# v = d.pop("age")
v = d.pop("age1", 666)
print(d, v)
'''
dic.popitem()
删除按升序排序后的第一个键值对,并以元组的形式返回键值对
如果字典为空,则报错
'''
d = {"name": "admin", "age": 18}
# 返回元组
dp = d.popitem()
print(d, dp)
'''
dic.clear()
删除字典内所有键值对
返回值:None
注意:字典对象本身还存在,只是清空了内容
del是删除一个键值对或整个字典
'''
clear = d.clear()
print(d, clear)
# 修改字典:只能修改值,不能修改键
'''
修改单个键值对
dic[key] = value
key不存在就是新增操作,存在就是修改操作
'''
dic = {"name": "admin", "age": 18}
dic["age"] = 20
print(dic)
'''
批量修改键值对
oldDic.update(newDic) 返回值:None
根据新的字典,批量修改旧字典的键值对值
如果旧字典没有key,就新增该key
'''
oldDic = {"name": "admin", "age": 18}
newDic = {"name": "root", "height": 180}
update = oldDic.update(newDic)
print(oldDic, newDic, update)
# 字典查询操作
'''
查询单个键值对
方式一: dic[key],key不存在报错
方式二: dic.get(key[, default]), key不存在会返回default值,如果没有给定default值,会返回None,但是原字典不会新增该键值对
方式二: dic.setdefault(key[, default]), key不存在会返回default值,如果没有给定default值,会返回None,原字典会新增该键值对
'''
dic = {"name": "admin", "age": 18}
print(dic["age"])
# dic_get = dic.get("name1")
dic_get = dic.get("name1", "root")
print(dic_get, dic)
# dic_setdefault = dic.setdefault("name1", "root")
dic_setdefault = dic.setdefault("name1")
print(dic_setdefault, dic)
'''
获取字典所有的值: dic.values()
获取字典所有的键: dic.keys()
获取字典所有的键值对: dic.items()
python2.x与python3.x之间获取键、值、键值对之间区别
1.python2.x获取到的直接是一个列表,可以通过下标进行获取指定元素
2.python3.x获取到的是Dictionary view objects改变键值对,获取到也跟着发生变化
3.python2.x提供如下方法:
viewkeys()
viewvalues()
viewitems()
作用如同.python3.x的Dictionary view objects
'''
dic = {"name": "admin", "age": 18, "height": 666}
vs = dic.values()
ks = dic.keys()
its = dic.items()
print(ks, vs, its)
dic["address"] = "shanghai"
print(dic)
print(ks, vs, its)
# 遍历方式一:遍历所有的key,根据key获取所有的值
dic = {"name": "admin", "age": 18, "height": 666}
keys = dic.keys()
for key in keys:
print(key)
print(dic[key])
dic["address"] = "shanghai"
# 遍历方式二:直接遍历所有的键值对
items = dic.items()
print(items)
for k, v in items:
print(k, v)
# 计算键值对个数
print(len(dic))
# 判定
# x in dic判定dic中的key是否存在x
# x not in dic判定dic中的key是否不存在x
# dic.has_key(key) 判定dic是否存在key,python2.x可以使用,但是过期了,使用in代替
print("name1" in dic)
print("name1" not in dic)
#转换为整数
int(x)
#转换为浮点数
float(x)
#转换为表达式字符串
repr(x)
#转换为字符
chr(x)
#转换为Unicode字符
unichr(x)
# 进制转换
#转换为对应整数值十进制
ord(x)
#转换为十六进制字符串
hex(x)
#转换为八进制字符串
oct(x)
#转换为二进制字符串
bin(x)
#计算字符串的有效表达式,返回对象
eval(x)
#转换为字符串
str(x)
#将序列转换为元祖
tuple(S)
#将序列转换为集合
list(S)
+ - * /(不像c++、java,除数为非整数,有小数部分)
**(幂运算符) //(整除,只取整数部分)
%(求模) =(赋值)
# 上面运算符加上=为复合运算符
a, b, c = 1, 2, 3 #批量赋值
> < != <>(python2不等于) >= <= == is(比对唯一标识) x1 <= x <= x3(链式运算符)
not and or # 非零非空为真,返回结果不一定是bool
res = raw_input('请输入:') # 将内容当做字符串
res = input('提示信息') # 将内容作为代码执行 input = raw_input() + eval()
content = raw_input("qingshuru")
res = eval(content)
res = input('提示信息') # 等同于python2的raw_input('请输入:')
# 与python2的input同理
content = input('hh:')
res = eval(content)
print value1
print value1, value2...
# 格式化输出
print '字符串 格式化输出时的数据类型和格式占位符'%(与前面占位符对应类型)
# 也可以使用索引
print '{0} {1} ...'.format(value1, value2...)
# 输出到文件
f = open('text.txt', 'w')
print >> f, 'hhhh'
# 输出不换行
print value1,
print value2,
print value3,
print ...
# 输出带分割符
print '-'.join(["1", "2", "3"])
print(value1)
print(value1, value2...)
# 格式化输出
print('字符串 格式化输出时的数据类型和格式占位符'%(与前面占位符对应类型))
print('{0} {1} ...'.format(value1, value1...))
print(f'{value1} {value1} ...')
# 输出到文件
f = open('text.txt', 'w')
print('hhh', file=f)
# 输出不自动换行
print(values, end="")
# 输出带分隔符
print('a', 'b', 'c', sep="-")
格式控制符
%[(name)][flags][width][.precision]typecode # []表示可选
(name) : 选择指定的名称对应的值
englishSc = 100
mathSC = 60
print('数学成绩 :%(ms)d, 英语成绩:%(es)d' % ({'es': englishSc, 'ms': mathSC}))
flags :
width:表示显示宽度
.precision: 表示小数点后精度
typecode
格式符 | 含义 |
---|---|
i/d | 将整数、浮点数转化成十进制 |
o | 将整数转化成八进制 |
x | 将整数转化成十六进制 |
e | 将整数、浮点数转换成科学计数法 |
E | 将整数、浮点数转换成科学计数法 |
f | 将整数、浮点数转换成科学计数法(默认保留小数点后6位) |
F | 将整数、浮点数转换成科学计数法(默认保留小数点后6位) |
g | 自动调整将整数、浮点数转换成浮点型或科学计数法(超过6位数用科学计数法) |
G | 自动调整将整数、浮点数转换成浮点型或科学计数法(超过6位数用科学计数法) |
字符串
格式符 | 含义 |
---|---|
s | 获取传入对象的_str_方法的返回值 |
r | 获取传入对象的_repr_方法的返回值 |
c | 整数:将数字转换成unicode对应的值 字符:将字符添加到指定为位置 |
注:没有将整数转为二进制,即%b; %%表示打印%
# 单分支
if 条件:
代码块
# 双分支
if 条件:
代码块
else:
代码块
#if-else可以嵌套
if 条件:
if 条件:
代码块
else:
代码块
.
.
.
else:
if 条件:
代码块
else:
代码块
.
.
.
# 上面代码可阅读性差,可以使用多分支
if 条件:
代码块
elif 条件:
代码块
elif 条件:
代码块
...
注:python没有switch语句
while
while 条件体:
条件满足的代码块
# 没有dowhile,而且有break语句else就不会执行
else:
条件不满足代码块
for
# 与java增强for循环相同
# 变量不用先前声明
for 变量名 in 列表、字符串等:
条件满足循环体
# 没有dowhile,而且有break语句else就不会执行
else:
条件不满足循环体
break: 打断本次循环,退出循环
continue : 结束本次循环,继续进入下一次循环
pass: 占位语句,空语句,保持程序结构完整性
注:rang(a, b)函数 --》[1,b-1]
import time
# 获取时间戳
res = time.time()
years = res / (365 * 24 * 60 * 60) + 1970
print(res)
print(years)
# 获取时间元组,可以不传人参数,默认当前时间元组
res = time.localtime(1564727544.8498905)
print(res)
# 时间戳获取格式化时间
t = time.time()
# 格式化时间
res = time.ctime(t)
print(res)
# 默认当前时间戳
res3 = time.ctime()
print(res3)
# 时间元组获取格式化时间
time_tuple = time.localtime()
# 格式化时间
res1 = time.asctime(time_tuple)
print(res1)
# 默认当前时间元组
res2 = time.asctime()
print(res2)
# 时间元组--》格式化日期
# 2022-10-03 09:48:37
# format_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
# 22-10-03 09:49:13
format_time = time.strftime("%y-%m-%d %H:%M:%S", time.localtime())
print(format_time)
# 格式化时间--》时间元组 time.strptime(日期字符串, 格式符字符串)
# time.struct_time(tm_year=2022, tm_mon=10, tm_mday=3, tm_hour=10, tm_min=3, tm_sec=41, tm_wday=0, tm_yday=276, tm_isdst=-1)
pt = time.strptime("2022-10-03 10:03:41", "%Y-%m-%d %H:%M:%S")
print(pt)
# 通过时间元组时间戳
time_mktime = time.mktime(pt)
print(time_mktime)
# 获取当前cpu时间
# python3.8后不支持time.clock(),使用time.perf_counter()代替
# startClock = time.clock()
startClock = time.perf_counter()
for i in range(0, 1000):
print(i)
# endClock = time.clock()
endClock = time.perf_counter()
print(endClock-startClock)
# 休眠时间,让线程暂停secs秒 time.sleep(secs)
while True:
format_time = time.strftime(" %Y-%m-%d %H:%M:%S ", time.localtime())
print(format_time)
time.sleep(1)
import calendar
# 时间日历
print(calendar.month(2022, 10))
import datetime
# 获取当天日期
datetime_now = datetime.datetime.now()
print(datetime_now, type(datetime_now))
print(datetime.datetime.today())
# 单独获取年月日时分秒
print(datetime_now.year)
print(datetime_now.month)
print(datetime_now.day)
print(datetime_now.hour)
print(datetime_now.minute)
print(datetime_now.second)
t = datetime.datetime.today()
# 计算n天后的日期
# res = t + datetime.timedelta(days=7)
res = t + datetime.timedelta(days=-7)
print(t, res)
# 时间间隔
first = datetime.datetime(2020, 12, 26, 10, 30, 10)
second = datetime.datetime(2020, 12, 27, 10, 30, 10)
delta = second - first
# datetime.timedelta 时间间隔类型
print(delta, type(delta))
# 对应的秒数
print(delta.total_seconds())
符号 | 说明 |
---|---|
%a | 当前区域设置下星期简写,如星期二Tue。 |
%A | 当前区域设置下星期全名,如星期二Tuesday。 |
%b | 当前区域设置下月份简写,如九月Sep。 |
%B | 当前区域设置下月份全名,如九月September。 |
%c | 当前区域设置下的日期和时间表示。 |
%C | 世纪,如2019年,21世纪,则返回20。 |
%d | 十进制数字表示的月份的某一天,范围[01,31]。 |
%D | 日期,等效于“%m/%d/%y”(美国格式),如“09/03/19” |
%e | 十进制数字表示的月份的某一天,范围[1,31]。如果小时10,则数字前用一个填充一个空格。 |
%F | ISO 8601格式的完整日期,等效于“%Y-%m-%d”,如“2019-09-03”。 |
%g | ISO周数对应的不包含世纪的年份,等效于“%y”,除非ISO周数属于前一年或后一年,则使用前一年或后一年,范围[00,99]。 |
%G | ISO周数对应的年份,等效于“%Y”,除非ISO周数属于前一年或后一年,则使用前一年或后一年,范围[0000,9999]。 |
%h | 等效于“%b”。 |
%j | 十进制表示的在一天中的天数,范围[001,366]。 |
%m | 十进制表示的月份,范围[01,12]。 |
%u | 十进制表示的星期,范围[1-7]。周一为一周的第一天。周一为1,依次递增。 |
%U | 十进制表示的一年中的周数,[00,53]。星期日为一周的第一天,新年第一个星期日之前的所有日子都视为第0周。 |
%V | 十进制表示的一年中的ISO周数,[01,53]。星期一为一周的第一天,如果包含1月1日的一周在新的一年里有四天或四天以上,则认为这周是第一周,否则就是前一年的第53周,下一周是新年的第一周。 |
%w | 十进制表示的星期,范围[0-6]。周日为一周的第一天。周日为0,依次递增。 |
%W | 十进制表示的一年中的周数,[00,53]。星期一为一周的第一天,新年第一个星期一之前的所有日子都视为第0周。 |
%x | 按当前区域设置下的日期格式,如“09/03/19”。 |
%y | 年份的后两位,范围[00,99]。 |
%Y | 年份,范围[0000,9999]。 |
%H | 十进制数字表示的小时(24小时制),范围[00,23]。 |
%I(大写i) | 十进制数字表示的小时(12小时制),范围[01,12]。 |
%M | 分钟,范围[00,59]。 |
%p | 本地区域设置下等价于“AM”或“PM”,在许多地区是空字符串。中午视为“PM”,午夜视为“AM”。 |
%r | 本地区域设置下12小时制时间,如02:15:11 PM。 |
%R | 24小时制的时和分,等效于“%H%M”,如“14:16”。 |
%S | 十进制数字表示的秒,范围[00,61]。60在表示闰秒的时间戳中有效,61是出于历史原因而支持的。 |
%T | 24小时制的时分秒,等效于“%H:%M:%S”。 |
%X | 按当前区域设置下的日期格式,如“02:20:24 PM”。 |
%z | 表示与UTC/GMT的正或负时差的时区偏移量,格式为+HHMM或-HHMM,其中H表示小时数,M表示分钟数,范围是[-23:59,+23:59]。 |
%Z | 时区名。没有时区则返回空字符。 |
调用:先定义后调用,类似c语言,不同于java(调用的代码可以在方法前)
作用:方便代码重用;分解任务,简化程序逻辑;使代码更加模块化
定义:
'''
函数定义方式一:
def 函数名(形式参数名列表):
代码块
注意,参数列表不是数据类型的列表
函数调用:
方式一:
函数名(实际参数列表)
实际参数列表的参数与形式参数的列表一一对应
此时的参数列表可以写一个类似元组去掉括号,例如 函数名(参数1, 参数2, 参数3, 参数4, 参数5,...)
方式二:
函数名(实际参数名=参数的值,...) 也可叫关键字参数:键值对
实际参数列表的参数与形式参数的列表不需要位置上一一对应,只需要参数名对应即可,例如mysum(num2=5, num1=2)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
函数定义方式二: *args代表的接收一个元组
def 函数名(*形式参数名)
代码块
函数调用:
函数名(实际参数列表)
实际参数列表的参数与形式参数的列表一一对应
此时的参数列表可以写一个元组,此时元组括号必须省略 ,例如 函数名(参数1, 参数2, 参数3, 参数4, 参数5)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
函数定义方式三: **args代表的接收一个字典
def 函数名(**形式参数名)
代码块
函数调用:
方式一:
函数名(实际参数列表)
实际参数列表的参数与形式参数的列表一一对应
此时的参数列表是类似字典,此时字典{}必须省略,冒号用等号代替,参数名称没有引号,例如 函数名(参数名称1=参数1, 参数名称2=参数2, 参数名称3=参数3, ...)
'''
参数拆包:
def mySum(a, b, c, d):
print(a + b + c + d)
def myFun(*args):
print(args)
# 拆包
print(*args)
mySum(*args)
mySum(args[0], args[1], args[2], args[3])
# 此时只有a能接收值,且为元组,报错
mySum(args)
myFun(1, 2, 3, 4)
def mySum(a, b):
print(a + b)
def test(**kwargs):
print(kwargs, type(kwargs))
# 拆包操作
# 无法打印,报错
# print(**kwargs)
# 同理一个字典传参,b没有接收值报错
# mySum(kwargs)
mySum(**kwargs)
#必须传a,b不然不错,即传递对应的名称才能正确的拆包传参
test(a=15, b=12)
'''
参数装包:把传递进来的参数包装成一个集合
参数拆包:把集合参数再次分解成单独的个体
'''
缺省参数:
1) 场景:使用一个函数,使用某个数据的一个固定值或者主功能之外的小功能实现
2) 定义:def 函数名(变量名1=默认值1, 变量名2=默认值2, …):
函数体中即使没有传参,也可以使用,但是使用的是默认值
3) 使用:函数名(变量1, 变量2, …) 缺省参数可以不写,为默认值
参数传递:
1)值传递:只传递值的副本,不传递地址(引用),修改值的副本对原参数值没有影响
2)引用传递(地址传递):通过传递过来的地址可以操作原参数
注意:python只有引用传递,如果数据类型是可变类型,可以改变原件,如果数据类型是不可变类型,不能改变原件!
函数返回值:
1) 场景:使用一个函数处理数据,需要获取数据的处理结果
2) 定义:
def 函数名(参数列表):
函数体
return 返回值
只能返回一次,因为return后函数执行完毕,不会向下执行
如果返回多个数据,包装成一个集合返回,可以返回列表、字典、元祖等等
函数的使用描述:
1) 场景:编写三方函数,方便别人使用,添加函数的功能和使用方式等描述在函数体最上面
2) 定义:使用双引号引起来注释
def 函数名(参数列表):
"""
帮助信息
"""
函数体
3)一般函数的使用描述
4) 查看函数帮助文档
help(函数名)
# 注意函数名后面没有括号
1) 场景:编写较多参数的函数时,如果某些参数是一个固定值,为了简化使用,可以创建一个新函数,指定使用的函数的某个参数为某个固定值,这个新函数就是偏函数。
2) 语法:
方式一:自己写一个新的
def mySum(a, b, c, d=1):
print(a + b + c + d)
# 偏函数
def mySum1(a, b, c=1, d=2):
mySum(a, b, c, d)
mySum1(1, 2)
方式二:借助functools模块的partial函数
import functools
def mySum(a, b, c, d=1):
print(a + b + c + d)
# 偏函数
newFunc = functools.partial(mySum, c=5)
print(newFunc, type(newFunc))
# 利用functools.partial(mySum, c=5)生成的偏函数不能多写参数,会报错
# newFunc(1, 2, 3, 4)
newFunc(1, 2)
# 场景
numStr = "1000010"
# 二进制转换成十进制
print(int(numStr, base=2))
# 使用偏函数,不用重复写base参数
int2 = functools.partial(int, base=2)
print(int2(numStr))
1) 概念:当一个函数A的参数,接收的又是另一个函数时,则把这个函数A称为是高阶函数。例如sorted函数
2) 语法:
# 高阶函数
l = [{"name": "ssd1", "age": 15}, {"name": "ssd4", "age": 125}, {"name": "ssd2", "age": 25},
{"name": "ssd3", "age": 18}, {"name": "ssd5", "age": 14}]
# def getKey(dic):
# return dic["name"]
#
#
# l1 = sorted(l, key=getKey)
# print(l1)
# 自定义高阶函数
def calculate(num1, num2, calculateFunc):
return calculateFunc(num1, num2)
def addFunc(num1, num2):
return num1 + num2
def subFunc(num1, num2):
return num1 - num2
print(calculate(3, 2, addFunc))
print(calculate(3, 2, subFunc))
1) 概念:一个函数的内部,它的返回值数据是另一个函数,把这样的操作称为返回函数。
2) 语法:
# 返回函数
def getFunc(flag):
def getAdd(num1, num2, num3):
return num1 + num2 + num3
def getSub(num1, num2, num3):
return num1 - num2 - num3
# 根据flag值判断返回哪一个函数
if flag == "+":
return getAdd
elif flag == "-":
return getSub
func = getFunc("+")
print(func, type(func))
print(func(1, 3, 5))
1) 概念:没有名字的函数。
2) 语法:lambda 参数1, 参数2, …: 表达式
3) 限制:只能写一个表达式,不能直接return;表达式的结果就是返回值;只适用于简单的操作处理。
# 匿名函数
res = (lambda x, y: x + y)(1, 2)
print(res)
func = lambda x, y: x + y
print(func(1, 2))
l = [{"name": "ssd1", "age": 15}, {"name": "ssd4", "age": 125}, {"name": "ssd2", "age": 25},
{"name": "ssd3", "age": 18}, {"name": "ssd5", "age": 14}]
# def getKey(dic):
# return dic["name"]
l1 = sorted(l, key=lambda dic: dic["age"])
print(l1)
1) 概念:在函数嵌套的前提下,内层函数引用了外层函数的变量(包括参数),外层函数又把内层函数当作返回值返回,这个内层函数+所引用的外层变量,称为闭包。
2) 语法:
# 闭包函数
def func1():
a = 100
def func2():
print(a)
return func2
# 得到func2
newFunc = func1()
# 调用内部函数
newFunc()
3) 应用场景:外层函数,根据不同的参数生成不同功能的内层函数
# 案例:生成分割线
def line_config(content, length):
def line():
print("-" * (length // 2) + content + "-" * (length // 2))
return line
f = line_config("闭包函数", 100)
f()
4) 注意事项
闭包中如果想要修改引用的外层变量,需要使用nonlocal关键字修饰变量,不能同时赋值,先修饰然后赋值,没有加关键字,就是闭包内新定义的变量
# external and internal
def external_func():
num = 10
def internal_func():
# nonlocal关键字 非局部的
nonlocal num
num = 666
print(num)
# 没有加nonlocal 10
print(num)
internal_func()
# 没有加nonlocal 10
print(num)
return internal_func
func = external_func()
func()
闭包内引用了一个后期会发生变化的变量是需要注意
# 闭包注意事项二
def external_func():
num = 10
def internal_func():
print(num)
num = 100
return internal_func
func = external_func()
# 函数被调用时才确定内部变量标识对应的值
# 100
func()
def external_func1():
funcs = []
for i in range(1, 4):
def internal_func1():
print(i)
funcs.append(internal_func1)
return funcs
func_ = external_func1()
print(func_, type(func_))
# 全是3
func_[0]()
func_[1]()
func_[2]()
def external_func2():
funcs = []
for i in range(1, 4):
def internal_func2(num):
# 增加内层函数,保持num = i = 1、2、3
def inner():
print(num)
return inner
funcs.append(internal_func2(i))
return funcs
func2 = external_func2()
print(func2, type(func2))
# 1、2、3
func2[0]()
func2[1]()
func2[2]()
1) 作用:在函数名以及函数体不改变的前提下,给一个函数附加一些额外代码
2) 案例:
优化前
# 装饰器
# 开放封闭原则:已经写好的代码,尽可能不要修改,如果想新增功能,在原来代码基础上,单独进行扩展
# 单一职责原则:单一功能
def publish_novels():
# print("login_check")
login_check()
print("发说说")
def publish_pictures():
# print("login_check")
login_check()
print("发图片")
def login_check():
print("login_check")
# 业务逻辑代码
btn = 2
if btn == 1:
# print("login_check")
publish_novels()
else:
# print("login_check")
publish_pictures()
# 方式一:在业务逻辑代码添加登录验证代码,代码冗余度大,维护性能差
# 方式二:在功能函数添加登录验证代码,减少代码重复度,复用性好
使用装饰器优化后
def login_check(func):
def inner():
print("login_check")
func()
return inner
# 使用@login_check立马执行login_check方法
@login_check
def publish_novels():
# print("login_check")
# login_check()
print("发说说")
# publish_novels = login_check(publish_novels)相当于
# publish_novels = def inner():
# print("login_check")
# func()
# 利用python语法题@函数名代替下式
# publish_novels = login_check(publish_novels)
# print(publish_novels)
@login_check
def publish_pictures():
# print("login_check")
# login_check()
print("发图片")
# 利用python语法题@函数名代替下式
# publish_pictures = login_check(publish_pictures)
# print(publish_pictures)
# 业务逻辑代码
btn = 1
if btn == 1:
# print("login_check")
publish_novels()
# login_check(publish_novels)
else:
# print("login_check")
publish_pictures()
# login_check(publish_pictures)
装饰器的叠加使用(使用多个注解)
# decorator 装饰器叠加使用,加@decorator方法的注解,从上往下执行
def decorator_line(func):
def inner():
print("-" * 100)
func()
return inner
def decorator_star(func):
def inner():
print("*" * 100)
func()
return inner
@decorator_line
# content = decorator_line(content)
@decorator_star
# content = decorator_star(content)
def content():
print("社会我小谢,人狠话不多")
content()
对有参函数进行装饰
# 对有参函数进行装饰
def decorator(func):
def inner(*args, **kwargs):
print("*" * 50)
print(args, kwargs)
# 拆包
func(*args, **kwargs)
return inner
@decorator
def print_number(num1, num2, num3):
print(num1, num2, num3)
@decorator
def print_number2(num1):
print(num1)
print_number(123, 666, num3=666)
print_number2(123)
对有返回值的函数进行装饰(无论什么场景下,保证函数返回值一致)
# 对有返回值的函数进行装饰
def decorator(func):
def inner(*args, **kwargs):
print("*" * 50)
print(args, kwargs)
# 拆包
res = func(*args, **kwargs)
return res
return inner
@decorator
def print_number(num1, num2, num3):
print(num1, num2, num3)
return num1 + num2 + num3
@decorator
def print_number2(num1):
print(num1)
# inner函数必须要有返回值,且与被装饰者返回值一致
res1 = print_number(123, 666, num3=666)
res2 = print_number2(123)
print(res1, res2)
通过装饰器的注解加参数获取不同的装饰器
# 获取装饰器,通过char控制获取不同装饰器
def getDecorator(char):
def decorator(func):
def inner():
print(char * 50)
func()
return inner
return decorator
@getDecorator("*")
def fp():
print("中华人民共和国万岁")
fp()
1) 概念:是一个特殊的迭代器(迭代器的抽象层次更高)
拥有迭代器特性:惰性计算数据,节省内存;能够记录状态,通过next()函数访问下一个状态;具备可迭代特性;
也可以自己实现迭代器
2) 创建方式一:生成器变量名 = (推导式),即列表推导式的[]改为()
3) 创建方式二:生成器函数,函数中包含yield语句,函数执行结果就是生成器
# yield,可以阻断当前函数执行,当使用next(generator)或者generator.__next__()函数,让函数继续执行,当执行下一个yield时,又阻断
def test():
print("test函数执行")
# 遇到yield,阻断执行
yield 1
print("a")
yield 2
print("b")
yield 3
print("c")
yield 4
print("d")
yield 5
print("e")
def test():
for i in range(1, 9):
yield i
# print("a" + str(i))
g = test()
print(g)
print(next(g))
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
# print(g.__next__())
4) send()方法:
send方法有一个参数,指定的是上一次被挂起的yield语句的返回值
相比于.__next__(),可以额外的给yield语句传值
注意第一次调用t.send(None)
def test():
print("test函数执行")
res1 = yield 1 # "000"
print(res1)
res2 = yield 2
print(res2)
g = test()
# 开启调用函数
print(g.__next__())
# print(g.__next__())
# g.__next__(),默认是None,使用g.send("000")可以给上一次挂起的yield传值
print(g.send("000"))
print(g.send(None))
5) 关闭生成器
g.close()
# 遇到return语句,直接终止函数 StopIteration
return 返回值
# 与迭代器一样,生成器只能迭代一次
1) 概念:函数A内部继续调用A
2)案例:
# 递归求n!
def recursion(n):
if n == 1:
return 1
else:
return n * recursion(n - 1)
print(recursion(9))
概念:只能位置传参,不能键值对传参,最后一个是正斜杠/,该参数不用传
# 保证按位置传参且只能传一个
def new_method(self, /):
print("我是新来的,给我一个实例")
new_method("kk")
文件概念:数据存放的容器
文件的作用:持久性的存储数据内容
文件组成:
文本内容
文件使用流程
打开:open(“文件”, “模式”),文件指定文件名称,模式控制操作模式,返回文件对象
模式:
模式 | 含义 |
---|---|
r | 以只读方式打开文件(默认文件打开模式),文件的指针放在文件的开头,注意:文件不存在报错 |
w | 以只写方式打开文件,文件的指针放在文件的开头,所以写入新的内容会覆盖原文件的所有内容,注意:文件不存在会自动创建文件 |
a | 以追加方式(只写)打开文件,文件的指针放在文件的结尾,所以写入新的内容会新增原文件的结尾,注意:文件不存在会自动创建文件 |
增加b | rb、wb、ab,如果是二进制文件,则选择此项;如图片、视频、音频等等(b为binary) |
增加+ | r+、w+、a+、wb+、rb+、ab+,都是以读写模式打开,其他特性基本和+前面的模式一致,但部分操作,有细节区别 |
r+ | 可读可写打开文件,没有文件 No such file or directory报错;可以读操作,指向文件头,读取全部内容;可以写入,指针指向文件头部,覆盖写入的内容长度,不会全部覆盖;读写同时进行,先读后写,指针先移到读完后的位置,再写入;读写同时进行,先写后读(会等读语句执行后写入),指针移到写完后的位置,若原文件空,读写不到数据,非空,则读到指针后面剩下内容 |
w+ | 可读可写打开文件,文件不存在,创建文件;打开文件就清空文件,指针指向头部,所以读操作,指向文件头,返回空;可以写入,指针指向文件头部,覆盖原文件全部内容;读写同时进行,先读后写(打开文件就清空了内容),不管先读后写,还是先写后读(执行完写语句不会写入内容,执行完读操作(缓冲区内容到磁盘)才会写入成功),不会读到内容,总结不可读,但是使用读操作不报错 |
a+ | 可读可写打开文件,文件不存在,创建文件;可以读操作,不管是否存在内容,读取不到内容,返回空;可以写入,指针指向文件尾,追加写入;读写同时进行,不管先读后读(写入到缓冲区,执行完close语句写入磁盘),还是先写后读(执行完读语句写入),不会读到内容,总结不可读,但是使用读操作不报错 |
rb+ | 可读可写打开文件,文件不存在,创建文件;以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
读写:
a)定位:
# 偏移
f.seek(偏移量[, 0, 1, 2])
# 查看文件指针
f.tell()
# 通过命令行查看seek帮助文档
f = open("py文件操作/a.txt", "r")
help(f.seek)
'''
seek的第二个参数
0.文件指针在文件头,偏移量为正
1.文件指针在文件中,表示当前位置,有可能偏移量可以为负
2.文件指针在文件尾部,偏移量为负
注意:文本文件不带"b"seek第二参数只能写0,二进制文件(加b)操作模式下可以为1或2
'''
b)读:
'''
f.read(字节数)
字节数默认是文本内容长度,下标自动移动
* f.readline([limit])
读取一行数据,limit限制最大读取字节数
f.readlines()
自动将文件按照换行符处理,将处理好的每一行数据组成列表返回
* for in (动态加载内存)
1.遍历行列表
2.遍历文件本身(文件对象就是迭代器)
判断文件是否可读(容错处理)
file对象.readable()
注意:
文件比较大时使用readline方法,按行加载,可节省内存,但相对于其他两个读取方法,性能较低
其他两个方法一次读取全部内容,虽然占用内存,但处理性能比较高
'''
c)写:
'''
file对象.write()
返回写入字节的长度
判断文件是否可写(容错处理)
file对象.writable()
'''
关闭:
'''
file对象.close()
关闭一个打开的文件
可以释放系统资源,会立即清空缓冲区的数据内容到磁盘文件
file对象.flush()
将缓冲区的数据内容刷新到磁盘文件中
'''
文件常用操作
import os
# 重命名文件 os.rename(原, 新), 没有文件或目录报错
# os.rename("b.txt", "one.txt")
# 重命名目录
# os.rename("first", "one")
# 同时修改目录名和文件名 renames()
# os.renames("one/one.txt", "two/two.txt")
# 删除文件,不存在报错 remove()
# os.remove("m52.jpg")
# 删除目录,文件夹非空报错 rmdir()
# os.rmdir("one")
# 只删除two目录
# os.rmdir("one/two")
# 递归删除目录,文件夹非空报错 removedirs()
# os.removedirs("one/two")
# 创建一级目录 mkdir()
# os.mkdir("one")
# 无法递归创建多级目录,报错
# os.mkdir("a/b/c")
os.mkdir("a", 0o777)
'''
数字权限模式,windows忽略,可以参照linux的文件权限(读r:4、写w:2、可执行x:1)
文件拥有者 八进制第一位数(读r:4、写w:2、可执行x:1)
同组用户 八进制第二位数(读r:4、写w:2、可执行x:1)
其他用户 八进制第三位数(读r:4、写w:2、可执行x:1)
'''
# 切换默认目录,os.chdir(target目录),目标目录不存在会报错
# os.chdir("one")
# open("ddd.txt", "w")
# 获取当前目录 os.getcwd()
# print(os.getcwd())
# 获取目录内容列表 os.listdir(path) 目录默认是当前目录下("./") 返回一个列表
print(os.listdir("../"))
案例:
# 文件复制案例
import os
os.chdir("../file/")
# 1.以只读模式打开要复制的文件
# 以追加模式打开副本文件
# 两个文件编码一致,不会乱码
source_file = open("poem.txt", "r", encoding="utf-8")
target_file = open("poem_copy.txt", "a", encoding="utf-8")
# 2.从原文件中读取内容
# 目标文件写内容
# if source_file.readable():
# content = source_file.read()
# if target_file.writable():
# target_file.write(content)
while True:
content = source_file.read(1024)
if len(content) == 0:
break
target_file.write(content)
# 刷新流
target_file.flush()
# 3.关闭流
source_file.close()
target_file.close()
'''--------------------------------------------'''
# 创建于扩展名相同目录并移动到该目录下,进行分类
# 获取文件名称列表
import os
import shutil
path = "../file"
if not os.path.exists(path):
exit()
os.chdir(path)
file_list = os.listdir("./")
# print(file_list)
# 1 遍历所有文件
for file_name in file_list:
# print(file_name)
# 2 分解文件后缀名
# 2.1获取最后一个.的索引位置
index = file_name.rfind(".")
# print(index)
# 2.2根据这个索引开始截取后续内容
extension = file_name[index + 1:]
# print(extension)
if extension == -1:
continue
# 3 查看一下, 是否存在同名的目录
# 4 如果不存在这样的目录,创建该名称的目录
if not os.path.exists(extension):
# 创建
os.mkdir(extension)
# 移动
# 5 目录存在后,移动对应文件
shutil.move(file_name, extension)
'''------------------------------------'''
# 打印文件目录文件夹及文件清单
# 获取文件名称列表
import os
import shutil
# path = "../file"
# if not os.path.exists(path):
# exit()
# listdir = os.listdir(path)
# print(listdir)
def listFiles(dir, f):
file_list = os.listdir(dir)
# print(file_list)
for file_name in file_list:
new_file_name = dir + "/" + file_name
# 判断是不是目录
if os.path.isdir(new_file_name):
# print(new_file_name)
f.write(new_file_name + "\n")
# 是目录,递归
listFiles(new_file_name, f)
else:
# print("\t" + file_name)
f.write("\t" + file_name + "\n")
# print("")
f.write("\n")
f = open("list.txt", "a")
listFiles("../file", f)
class 类名:
pass
# 类名驼峰命名法,与java一致
# 类名也可以作为变量,可以给他赋值
对象名 = 类名()
'''
对象(实例)属性(java没有对象属性概念,python有)
* 使对象具有一些属性(增)
1.直接通过对象,动态添加,对象.属性 = 值
2.通过类的初始化方法(构造方法) __init__方法(当我们创建好一个对象后,会自动调用该方法,初始化对象)
* 访问对象的属性(查)
对象.属性
查看对象属性是否添加成功:打印对象.属性,或者获取所有该对象属性,对象.__dict__
* 修改对象的属性(改)
对象.属性 = 新值
修改操作,属性会指向新的空间(不可变类型),可变类型的值会修改值,指向的内存地址不变
* 删除对象的属性(删)
del 对象.属性
* 对象名访问属性,其实是访问对象的__dict__属性指向地址的属性值,可以通过(对象.__dict__ = 字典)给对象设置属性,说明了__dict__属性可以修改
可以通过对象.__class__ = 类名 来修改所属类
类属性(类本身、及根据该类创建的对象都可以共享)
* 使类具有一些属性(增)
1.直接通过类名,动态添加,类名.属性 = 值
2.在类的代码块直接写属性名 = 值
* 访问类的属性(查)
类名.属性
查看类属性是否添加成功:打印 类名.属性,或者获取所有该类属性,类名.__dict__
* python对象属性查找机制,python对象会优先查找对象自身属性,找不到才根据__class__去对象对应的类属性查找
* 修改类的属性(改)
类名.属性 = 新值
修改操作,属性会指向新的空间(不可变类型),可变类型的值会修改值,指向的内存地址不变
* 属于该类创建的对象修改类属性,成为对象自己的属性,属于新增操作,但不会修改类属性
* 删除类的属性(删)
del 类名.属性
不能使用del 对象.属性,会报错,即不能通过对象删除类属性
通过设置__slots__属性(在类的内部设置)
列表中的元素,即为通过这个类创建出的对象可以添加的对象属性
如果这个类实例出的对象,添加了非列表之内的属性,则会报错
'''
'''
方法与普通函数异同:
都封装了一系列行为动作
都可以被调用的之后,执行一系列行为动作
最主要的区别就是:调用方式,方法需要对象调
方法的划分:
* 实例方法
默认第一个参数需要接收到一个实例
* 类方法(加@classmethod注解,原理就是装饰器)
默认第一个参数需要接收到一个类
* 静态方法(加@staticmethod注解)
第一个参数什么都不默认接收
* 注意:
1.划分的依据是:方法的第一个参数必须要接收的数据类型
2.不管是哪一种类型的方法,都是存储在类当中;没有在实例当中的
3.不同类型方法的调用方式不同
'''
'''
class 类名:
def 方法名(self):
方法体
标准调用:
使用实例调用实例方法,不用手动传参,解释器默认将当前实例本身传递过去
注意:至少有一个参数,不然报错,一般形参用self,也可以自定义
其他调用:
使用类调用: 类名.方法名(参数列表)
间接调用: 函数名 = 类名.方法名 函数名(参数列表)
本质就是找到函数本身取调用它
'''
'''
class 类名:
@classmethod
def 方法名(cls):
方法体
类调用:不用手动传递第一个参数,会自动的把调用的类本身给传递过去(一般使用类调用)
实例调用:不用手动传递第一个参数,会自动的把调用的对象对应的类给传递过去
'''
'''
class 类名:
@staticmethod
def 方法名():
方法体
类调用:不用传递参数
实例调用:不用传递参数
看场景使用什么调用方法
'''
'''
另一种创建类方式:使用type创建类
自定义的类变量 = type(类名, 元组, 字典{属性键值对或方法键值对})
实例 = 自定义的类变量()
'''
'''
类创建流程:
1. 检测类中是否有明确 __metaclass__属性,有, 则通过指定元类来创建这个类对象
2. 检测父类中是否存在__metaclass__属性,有, 则通过指定元类来创建这个类对象
3. 检测模块中是否存在__metaclass__属性,有, 则通过指定元类来创建这个类对象
4. 通过内置的type这个元类,来创建这个类对象
4. 通过内置的type这个元类,来创建这个类对象
场景:1) 拦截类的创建 2) 修改类 3) 返回修改之后的类
'''
'''
方式1:
使用内置模块pydoc
具体步骤
1.查看文档描述
python -m pydoc 模块名称
2.启动本地服务, 浏览文档
python -m pydoc -p 1234
# 自动生成端口号
python -m pydoc -b
3.生成指定模块html文档
python -m pydoc -w 模块名称
方式2
使用三方模块
Sphinx
epydoc
doxygen
'''
'''
私有化属性
概念
是指将一些原本公开的属性设置权限, 只能小范围访问, 其他地方访问不了
意义
保证数据的安全性
提高代码的可维护性
* 注意
Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果
类属性(方法)和实例属性(方法)遵循相同的规则
x
公有属性
类内部访问
子类内部访问
模块内其他位置访问
类访问
父类
派生类(继承的类)
实例访问
父类实例
派生类实例
跨模块访问
import形式导入
from 模块 import * 形式导入
_y
受保护属性
类内部访问
子类内部访问
模块内其他位置访问(有警告,但是可以访问)
类访问
父类
派生类
实例访问
父类实例
派生类实例
跨模块访问
import形式导入(有警告,但是可以访问)
from module import * 形式导入
* 有__all__指明对应变量(提前使用__all__ = ["_y"],可以访问,不警告)
* 没有__all__指明对应变量(报错,不能访问)
__z
私有属性
类内部访问
子类内部访问(报错,不能访问)
模块内其他位置访问(报错,不能访问)
类访问
父类
派生类
实例访问
父类实例
派生类实例
跨模块访问(属性报错,不能访问,模块可以按照下面方案访问)
import形式导入(可以访问)
from module import * 形式导入
* 有__all__指明对应变量(提前使用__all__ = ["_y"],可以访问,不警告)
* 没有__all__指明对应变量(报错,不能访问)
私有属性的实现机制
名字重整(Name Mangling)
重改__x为另外一个名称, 如
_类名__x
目的
防止外界直接访问
防止被子类同名称属性覆盖
应用场景
数据保护
数据过滤
补充
xx_
"变量名_" 这个格式是为了与系统属性作区分
__xx__
两端__一般为系统内置属性或方法, 所以以后命名注意避免
'''
'''
只读属性
概念
一个属性(一般指实例属性), 只能读取, 不能写入
应用场景
有些属性, 只限在内部根据不同场景进行修改, 而对外界来说, 不能修改, 只能读取
比如
电脑类的网速属性, 网络状态属性
方式1
方案
全部隐藏
私有化
既不能读
也不能写
部分公开
公开读的操作(设置方法返回私有属性)
具体实现
私有化
通过"属性前置双下划线"实现
部分公开
通过公开的方法
优化(加装饰器@property)
property
作用
将一些"属性的操作方法"关联到某一个属性中
概念补充(使用__bases__属性查看继承的基类)
经典类
没有继承(object)
新式类
继承(object)
Python2.x版本定义一个类时, 默认不继承(object)
Python3.x版本定义一个类时, 默认继承(object)
建议使用
新式类
property
在经典类中
只能管理一个属性的读取操作
在新式类中
可以管理一个属性的删改查操作
方式2
方案
借助系统内置的方法进行拦截
具体实现
__setattr__方法
当我们使用 "实例.属性 = 值" 这种格式给一个实例增加或修改属性的时候, 都会调用系统内置的这个方法
在这个方法的内部, 才会真正的把属性以及对应的值给存储到 __dict__当中
解决方案
在这个方法中, 进行拦截
'''
# 在python3.x环境下
# property在新式类使用方式一
class Person(object):
def __init__(self):
self.__age = 18
def set_age(self, age):
print("setAge...")
self.__age = age
def get_age(self):
print("getAge...")
return self.__age
# 参数顺序不能反
age = property(get_age, set_age)
# p = Person()
# p.age = 666
# print(p.age)
# print(p.__dict__)
# property在新式类使用方式二
class Animal(object):
def __init__(self):
self.__age = 15
@property
def age(self):
print("get___________")
return self.__age
@age.setter
def age(self, age):
print("set__________")
self.__age = age
animal = Animal()
animal.age = 666
print(animal.age)
print(animal.__dict__)
# python2.x环境下测试
# property在经典类使用方式一
class Person:
def __init__(self):
self.__age = 18
def set_age(self, age):
print "setAge..."
self.__age = age
def get_age(self):
print "getAge..."
return self.__age
# 参数顺序不能反
age = property(get_age, set_age)
# p = Person()
# # 经典类不能修改属性,只会新增属性,只关联了property的读取方法
# p.age = 666
# print p.age
# print p.__dict__
# property在经典类使用方式二
class Animal:
def __init__(self):
self.__age = 15
@property
def age(self):
print "get___________"
return self.__age
@age.setter
def age(self, age):
print "set__________"
self.__age = age
animal = Animal()
# # 经典类不能修改属性,只会新增属性,只关联了property的读取方法
animal.age = 666
print animal.age
print animal.__dict__
# 只读属性的方式二
class Person:
# 当我们使用 "实例.属性 = 值" 这种格式给一个实例增加或修改属性的时候, 都会调用系统内置的这个方法
# 在这个方法的内部, 才会真正的把属性以及对应的值给存储到 __dict__当中
def __setattr__(self, key, value):
print(key, value)
if key == "age" and key in self.__dict__.keys():
print("只读属性,不能设置属性")
else:
# self.key = value 死循环
self.__dict__[key] = value
p = Person()
p.age = 15
print(p.age)
# p.name = "zz"
p.age = 66
print(p.age)
print(p.__dict__)
'''
# 内置特殊属性
# 类属性
# __dict__ : 类的属性
# __bases__ : 类的所有父类构成元组
# __doc__ :类的文档字符串
# __name__: 类名
# __module__: 类定义所在的模块
# 实例属性
# __dict__ : 实例的属性
# __class__: 实例对应的类
'''
私有方法(与私有化属性类似)
def __方法():
pass
注意
不要定义 "_类名__方法名" 这种方法,会把名字重整机制的方法覆盖掉
'''
# ----------------信息格式化操作:__str__方法-------------------------
# class Person:
# # 类的构造方法,self相当于java的this关键字
# def __init__(self, weight, height):
# self.weight = weight
# self.height = height
#
# # 相当于java自己重写的toString()方法
# def __str__(self):
# # return "这个人的身高是%s, 年龄是%s" % (self.height, self.weight)
# # return "这个人的身高是%(height)s, 年龄是%(weight)s" % ({"height": self.height, "weight": self.weight})
# # return "这个人的身高是{0}, 年龄是{1}".format(self.height, self.weight)
# return f"这个人的身高是{self.height}, 年龄是{self.weight}"
#
#
# p1 = Person(40, 152)
# print(p1.height)
# print(p1.weight)
# print(p1)
#
#
# p2 = Person(70, 190)
# print(p2.height)
# print(p2.weight)
# print(p2)
#
# s = str(p1)
# print(s, type(s))
# ----------------信息格式化操作:__repr__方法-------------------------
# class Person:
# # 类的构造方法,self相当于java的this关键字
# def __init__(self, weight, height):
# self.weight = weight
# self.height = height
#
# # 相当于java自己重写的toString()方法
# def __str__(self):
# # return "这个人的身高是%s, 年龄是%s" % (self.height, self.weight)
# # return "这个人的身高是%(height)s, 年龄是%(weight)s" % ({"height": self.height, "weight": self.weight})
# # return "这个人的身高是{0}, 年龄是{1}".format(self.height, self.weight)
# return f"这个人的身高是{self.height}, 年龄是{self.weight}"
#
# def __repr__(self):
# return "vvv"
#
# p1 = Person(40, 152)
# print(p1)
#
#
# p2 = Person(70, 190)
# print(p2)
#
# # s = str(p1)
# # print(s, type(s))
#
# print(repr(p1))
# import datetime
#
# t = datetime.datetime.now()
# print(t)
# tmp = repr(t)
# # 面向开发人员
# print(tmp)
# # 面向用户
# print(eval(tmp))
# ----------------调用操作: __call__方法-------------------------
# class Person:
# def __call__(self, *args, **kwargs):
# print("xxx", args, kwargs)
#
# pass
#
#
# p = Person()
# p(12, 56, name="jj")
import collections.abc
import functools
# 关键字参数放后面
# def getColorPen(pen_color, pen_type):
# print(f"{pen_type}的颜色是{pen_color}")
#
#
# pen = functools.partial(getColorPen, pen_type="钢笔")
# pen("红色")
# pen("绿色")
# pen("蓝色")
# class PenFactory:
# def __init__(self, pen_type):
# self.pen_type = pen_type
#
# def __call__(self, pen_color):
# print(f"{self.pen_type}的颜色是{pen_color}")
#
#
# p = PenFactory("钢笔")
# p("红色")
# p("绿色")
# p("蓝色")
# pencil = PenFactory("铅笔")
# pencil("红色")
# pencil("绿色")
# pencil("蓝色")
# ----------------索引操作-------------------------
# class Person:
# def __init__(self):
# self.cache = {}
#
# def __setitem__(self, key, value):
# # print("__setitem__", key, value)
# self.cache[key] = value
#
# def __getitem__(self, item):
# # print("__getitem__", item)
# return self.cache[item]
#
# def __delitem__(self, key):
# # print("__delitem__", key)
# del self.cache[key]
# pass
#
#
# person = Person()
# person["name"] = "zhangsan"
# print(person["name"])
# del person["name"]
# # print(person["name"])
# print(person.cache)
# ----------------索引操作-------------------------
# class Person:
# def __init__(self):
# self.items = [1, 2, 3, 5, 6, 8, 9]
#
# def __setitem__(self, key, value):
# # 判断是不是切片对象
# if isinstance(key, slice):
# self.items[key.start: key.stop: key.step] = value
#
# def __getitem__(self, item):
# # print("get", item)
# if isinstance(item, slice):
# return self.items[item.start:item.stop:item.step]
#
# def __delitem__(self, key):
# # print("del", key)
# del self.items[key]
#
#
# p = Person()
# p[0:4:2] = ["l", "m"]
# print(p[0:4:2])
# del p[0:4:2]
# print(p.items)
# ----------------比较操作-------------------------
# python 2.x 可以直接使用 > < >= <= != ==比较
# python3.x需要实现六个方法才能使用,实现逻辑,但是方法不会叠加操作,不如eq方法与lt方法不会叠加为le方法
# class Person:
# def __init__(self, age, height):
# self.age = age
# self.height = height
#
# # """
# # 等于,可以由__ne__通过调换参数反推导出来,也可以自己写
# # """
# #
# # def __eq__(self, other):
# # print("__eq__")
# # return self.age == other.age
# #
# # """
# # 不等于,可以由__eq__通过调换参数反推导出来,也可以自己写
# # """
# #
# # def __ne__(self, other):
# # print("__ne__")
# # return self.age != other.age or self.height != other.height
# #
# # """
# # 大于,可以由__lt__通过调换参数反推导出来,也可以自己写
# # """
# #
# # def __gt__(self, other):
# # print("__gt__")
# #
# """
# 小于,可以由__gt__通过调换参数反推导出来,也可以自己写
# """
#
# def __lt__(self, other):
# print("__lt__")
# # 当为大于号时参数调换
# print(self.age)
# print(other.age)
# return self.age < other.age
#
# # """
# # 于等于,可以由__le__通过调换参数反推导出来,也可以自己写
# # """
# #
# # def __ge__(self, other):
# # print("__ge__")
# #
# # """
# # 大于等于,可以由__ge__通过调换参数反推导出来,也可以自己写
# # """
# #
# # def __le__(self, other):
# # print("__le__")
#
#
# p1 = Person(10, 160)
# p2 = Person(19, 170)
# print(p1 < p2)
# print(p1 > p2)
# ----------------比较操作_补充-------------------------
# import functools
#
#
# # 加下面装饰器至少必须有六个方法的其中一个
# @functools.total_ordering
# class Person:
# def __eq__(self, other):
# print("eq")
# pass
#
# def __lt__(self, other):
# print("lt")
# return False
#
#
# p1 = Person()
# p2 = Person()
# print(p1 <= p2)
# # print(Person.__dict__)
# # ----------------上下文环境中的布尔值-------------------------
# class Person:
# def __init__(self):
# self.age = 18
#
# def __bool__(self):
# return self.age >= 18
#
#
# p1 = Person()
# if p1:
# print("实例为真")
# ----------------遍历操作-------------------------
# 遍历操作方式一
# class Person:
# def __init__(self):
# self.res = 1
#
# def __getitem__(self, item):
# self.res += 1
# if self.res >= 6:
# raise StopIteration("停止遍历")
# return self.res
#
#
# p = Person()
# for i in p:
# print(i)
# 遍历操作方式二
# class Person:
# def __init__(self):
# self.res = 1
#
# def __iter__(self):
# print("iter")
# # 返回迭代器
# # return iter([1, 2, 3, 4, 6])
# return self
#
# def __next__(self):
# self.res += 1
# if self.res >= 6:
# raise StopIteration("停止遍历")
# return self.res
#
# p = Person()
# # for i in p:
# # print(i)
# print(next(p))
# print(next(p))
# print(next(p))
# print(next(p))
# # print(next(p))
# ----------------遍历操作,恢复迭代器初始值-------------------------
# class Person:
# def __init__(self):
# self.res = 1
#
# # 方式一
# # def __getitem__(self, item):
# # self.res += 1
# # if self.res >= 6:
# # raise StopIteration("停止遍历")
# # return self.res
#
# # 方式二
# def __iter__(self):
# # 每次迭代重新赋值,使得迭代器重用
# self.res = 1
# return self
#
# # def __next__(self):
# # self.res += 1
# # if self.res >= 6:
# # raise StopIteration("停止遍历")
# # return self.res
#
# def __call__(self, *args, **kwargs):
# self.res += 1
# if self.res >= 6:
# raise StopIteration("停止遍历")
# return self.res
#
#
# p = Person()
# # 前提是实现了__getitem__方法,才可以使用iter()
# # pt = iter(p.__next__, 4)
# # 实例可以被调用,实现call方法
# pt = iter(p, 4)
# print(pt)
# print(p is pt)
# for i in pt:
# print(i)
#
# # for i in p:
# # print(i)
#
# # 可迭代对象或迭代器肯定可以for in,但是可以for in 不一定是可迭代对象或迭代器
# from collections.abc import *
#
# # 实例成为迭代器条件:写__iter__方法与__next__方法
# # 判断是不是迭代器对象
# print(isinstance(p, Iterator))
# # 判断是不是可迭代对象
# print(isinstance(p, Iterable))
# print(isinstance(pt, Iterator))
# print(isinstance(pt, Iterable))
# ----------------描述器定义方式一-------------------------
# class Person:
# def __init__(self):
# self.__age = 18
#
# @property
# def age(self):
# return self.__age
#
# @age.setter
# def age(self, value):
# if value < 0:
# value = 0
# self.__age = value
#
# @age.deleter
# def age(self):
# del self.__age
#
# num = "jj"
#
#
# person = Person()
# person.age = 10
# print(person.age)
# del person.age
# # print(person.age)
# help(person)
# ----------------描述器定义方式二-------------------------
# class Age(object):
# def __get__(self, instance, owner):
# print("get")
#
# def __set__(self, instance, value):
# print("set")
#
# def __delete__(self, instance):
# print("delete")
#
#
# class Person(object):
# age = Age()
# # def __getattribute__(self, item):
# # print("kkkk")
#
# # 只要新式类才会转换操作描述器
# person = Person()
# person.age = 10
# print(person.age)
# del person.age
# print(person.age)
# help(person)
# 只打印get。不会转换set和delete。所以一般通过实例操作描述器
# print(Person.age)
# Person.age = 20
# del Person.age
# 如果实现了__get__, 判定为"非资料描述器"
# 如果实现了__get__、 __set__,判定为"资料描述器"
# 资料描述器 > 实例字典 > 非资料描述器
# ----------------描述器优先级-------------------------
# class Age(object):
# def __get__(self, instance, owner):
# print("get")
#
# # def __set__(self, instance, value):
# # print("set")
# #
# # def __delete__(self, instance):
# # print("delete")
#
#
# class Person(object):
# age = Age()
#
# def __init__(self):
# self.age = 100
#
#
# # 只要新式类才会转换操作描述器
# person = Person()
# person.age = 10
# print(person.age)
# # del person.age
# print(person.__dict__)
# ----------------描述器值存在问题-------------------------
# class Age(object):
# def __get__(self, instance, owner):
# print("get")
# return instance.v
#
# def __set__(self, instance, value):
# print("set", self, instance, value)
# instance.v = value
#
# def __delete__(self, instance):
# print("delete")
# del instance.v
#
#
# class Person(object):
# age = Age()
#
#
# # 多个实例的age对象相同,通过instance来修改值
# person = Person()
# person.age = 10
# print(person.age)
# # del person.age
# person2 = Person()
# person2.age = 100
# print(person2.age)
# print(person.age)
# ----------------使用类实现装饰器-------------------------
# def check(func):
# def inner():
# print("登录验证")
# func()
#
# return inner
class Check:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("登录验证")
self.func()
# 语法糖装饰器 函数装饰器:@check 类装饰器:@Check
# @check
# @Check
def publish_novels():
print("发说说")
# 函数装饰器
# publish_novels = check(publish_novels)
# 类装饰器
publish_novels = Check(publish_novels)
publish_novels()
'''
内置特殊方法
1.生命周期方法[链接过去]
2.其他内置方法
a.信息格式化操作
__str__方法
作用
一个对象的描述字符串, 更加方便用户阅读, 对用户更友好
触发方式
print 打印一个对象时
str() 函数时
格式
def __str__(self):
return "描述信息"
__repr__方法
作用
一个对象的描述字符串, 更加方便机器处理, 对机器更友好(开发人员查看)
触发方式
当我们在交互模式下, 直接执行某个变量, 就会输出对应信息
repr() 函数时
格式
def __repr__(self):
return "描述信息"
注意
一般情况下, 应满足如下等式
obj == eval(repr(obj))
或者描述一个实例详细的信息(类名等等)
b.调用操作
__call__方法
作用
使得“对象”具备当做函数,来调用的能力
使用
1. 实现实例方法 __call__
2. 那么创建好的实例, 就可以通过函数的形式来调用
实例(参数)
应用场景
有点类似于之前所讲的"偏函数"的应用场景
可以将"常变参数"和"不常变参数"进行分离
案例
不同类型的笔, 画不同的图形
c.索引操作
作用
可以对一个实例对象进行索引操作
步骤
1. 实现三个内置方法
设置元素的方法
def __setitem__(self, key, value):
获取元素的方法
def __getitem__(self, item):
删除元素的方法
def __delitem__(self, key):
2. 可以以索引的形式操作对象
增/改
p[1] = 666
p["name"] = "sz"
查
p["name"]
p[1]
删
del p["name"]
del p[1]
d.切片操作
作用
可以对一个实例对象进行切片操作
步骤
Python2.x
1. 实现三个内置方法
__setspice__
设置某个元素切片时调用
__getspice__
获取某个元素切片时调用
__delspice__
删除某个元素切片时调用
2. 可以直接按照切片的方式操作对象
p[1, 6, 2]
* 注意: 过期
Python3.x
统一由"索引操作"进行管理
def __setitem__(self, key, value):
def __getitem__(self, item):
def __delitem__(self, key):
e.比较操作
作用
可以自定义对象 "比较大小, 相等以及真假" 规则
步骤
实现6个方法
相等
__eq__
不相等
__ne__
小于
__lt__
小于或等于
__le__
大于
__gt__
大于或等于
__ge__
注意
如果对于反向操作的比较符, 只定义了其中一个方法, 但使用的是另外一种比较运算, 那么, 解释器会采用调换参数的方式进行调用该方法
例如
定义了 "小于" 操作
x < y
使用 x > y
会被调换参数, 调用上面的 "小于操作"
但是, 不支持叠加操作
例如
定义了 "小于" 和 "等于" 操作
不能使用 x <= y
补充
使用装饰器, 自动生成"反向" "组合"的方法
步骤
1. 使用装饰器装饰类
@functools.total_ordering
2. 实现
> 或 >= 或 < 或 <= 其中一个
实现 ==
上下文环境中的布尔值
控制类中__bool__方法,返回布尔值来控制实例真假
f.遍历操作
怎样让我们自己创建的对象可以使用for in 进行遍历?
* 实现__getitem__方法
优先级低
每次for in 获取数据时, 都会调用这个方法
* 或者实现__iter__方法
优先级高
这个方法, 必须返回一个"迭代器";即, 具备"__iter__"和"__next__"方法
当for in 遍历这个对象时, 会调用这个__iter__方法;返回的迭代器对象的__next__方法
怎样让我们自己创建的对象可以使用next函数进行访问?
实现__next__方法
补充
1. __iter__方法可以恢复迭代器的初始化值, 复用迭代器
2. "可迭代" 与 "迭代器"必须实现的方法
3. iter方法的使用
描述器
概念
可以描述一个属性操作的对象
对象
属性的操作
增/改
删
查
描述
作用
可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等
如果一个类属性被定义为描述器,那么以后对这个类属性的操作(读写删), 都将由这个描述器代理
定义
定义方式1
property
定义方式2
三个方法
__get__
__set__
__delete__
调用细节
使用实例进行调用
最多三个方法都会被调用
使用类进行调用
最多会调用get方法
不能够顺利转换的场景
新式类和经典类
描述器仅在新式类中生效
方法拦截
一个实例属性的正常访问顺序
实例对象自身的__dict__字典
对应类对象的__dict__字典
如果有父类, 会再往上层的__dict__字典中检测
如果没找到, 又定义了__getattr__方法, 就会调用这个方法
而在上述的整个过程当中, 是如何将描述器的__get__方法给嵌入到查找机制当中?
就是通过这个方法进行实现
__getattribute__
内部实现模拟
如果实现了描述器方法__get__就会直接调用
如果没有, 则按照上面的机制去查找
注意
"资料描述器"和"非资料描述器"
如果实现了
_get__
判定为"非资料描述器"
如果实现了
__get__
__set__
判定为"资料描述器"
描述器和实例属性同名时, 操作的优先级问题
资料描述器 > 实例字典 > 非资料描述器
装饰器
使用类当做装饰器来使用
'''
变量的赋值操作:只是形成两个变量,实际上还是指向同一个对象
浅拷贝:python拷贝一般都是浅拷贝,使用copy模块的copy函数拷贝时,对象包含的子对象内容不拷贝,因此源对象与拷贝对象会引用同一个子对象
深拷贝:使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象与拷贝对象的所有子对象也不同
# -----------------------深拷贝-----------------------------------
class Cpu:
def __init__(self, value):
self.cpu = value
class Disk:
def __init__(self, value):
self.disk = value
class Computer:
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
# print("--------------变量赋值---------------")
# num1 = 12
# num2 = num1
# 同时指向一块内存空间
# print(id(num1), id(num2))
# print("--------------实例变量赋值---------------")
# cpu = Cpu("英特尔")
# disk = Disk("联想")
# computer = Computer(cpu, disk)
# 你要是认为是computer2没有实例化才会一模一样,你也可以实例化,发现就是一样的
# computer2 = computer
# print(computer, computer.disk, computer.cpu)
# print(computer2, computer2.disk, computer2.cpu)
print("--------------实例浅拷贝---------------")
# import copy
# cpu = Cpu("英特尔")
# disk = Disk("联想")
# computer = Computer(cpu, disk)
# computer2 = copy.copy(computer)
# # 只有子对象相同,指明子对象没有拷贝,对象本身拷贝了
# print(computer, computer.disk, computer.cpu)
# print(computer2, computer2.disk, computer2.cpu)
print("--------------实例深拷贝---------------")
import copy
cpu = Cpu("英特尔")
disk = Disk("联想")
computer = Computer(cpu, disk)
computer2 = copy.deepcopy(computer)
# 对象本身与他的子对象都拷贝了
print(computer, computer.disk, computer.cpu)
print(computer2, computer2.disk, computer2.cpu)
[返回](# 2.13 内置特殊方法)
'''
__new__方法
当我们创建一个对象是, 用于给这个对象分配内存的方法
通过拦截这个方法, 可以修改对象的创建过程
比如:单例设计模式
__init__方法
每个对象实例化的时候,都会自动执行这个方法
可以在这个方法里面,初始化一些实例属性
__del__方法
当对象被释放的时候调用这个方法
可用于在这个方法中清理资源
'''
'''
1. 在Python中万物皆对象
* 不存在基本数据类型
* 0, 1.2, True, False, "abc",这些全都是对象
2. 所有对象, 都会在内存中开辟一块空间进行存储
* 会根据不同的类型以及内容, 开辟不同的空间大小进行存储
* 返回该空间的地址给外界接收(称为"引用"), 用于后续对这个对象的操作
a.可通过id()函数获取内存地址(10进制)
b.通过hex()函数可以查看对应的16进制地址
3. 对于整数和短小的字符, Python会进行缓存; 不会创建多个相同对象;此时, 被多次赋值, 只会有多份引用
4. 容器对象, 存储的其他对象, 仅仅是其他对象的引用, 并不是其他对象本身
* 比如字典, 列表, 元组这些"容器对象"
* 全局变量是由一个大字典进行引用;global()查看
'''
引用计数器机制
举例
查看引用计数
import sys
sys.getrefcount(对象) # **注意会大1,结果要减1**
垃圾回收机制
主要作用:从经历过"引用计数器机制"仍未被释放的对象中, 找到"循环引用", 干掉相关对象
底层机制(了解&难)
怎样找到"循环引用"?
1. 收集所有的"容器对象", 通过一个双向链表进行引用
容器对象
可以引用其他对象的对象
列表
元组
字典
自定义类对象
…
非容器对象
不能引用其他对象的对象
数值
字符串
布尔
…
注意: 针对于这些对象的内存, 有其他的管理机制
2. 针对于每一个"容器对象", 通过一个变量gc_refs来记录当前对应的引用计数
3. 对于每个"容器对象",找到它引用的"容器对象", 并将这个"容器对象"的引用计数 -1
4. 经过步骤3之后, 如果一个"容器对象"的引用计数为0, 就代表这玩意可以被回收了, 肯定是"循环引用"导致它活到现在的
如何提升查找"循环引用"的性能?
如果程序当中创建了很多个对象, 而针对于每一个对象都要参与"检测"过程; 则会非常的耗费性能
所以, 基于这个问题, 产生了一种假设:
a.越命大的对象, 越长寿
b.假设一个对象10次检测都没给它干掉, 那认定这个对象一定很长寿, 就减少这货的"检测频率"
基于这种假设, 设计了一套机制
1.分代回收机制
a.默认一个对象被创建出来后, 属于 0 代
b.如果经历过这一代"垃圾回收"后, 依然存活, 则划分到下一代
c."垃圾回收"的周期顺序为
1)0代"垃圾回收"一定次数, 会触发 0代和1代回收
2)1代"垃圾回收"一定次数, 会触发0代, 1代和2代回收
2.查看和设置相关参数
import gc
print(gc.get_threshold())
gc.set_threshold(700, 10, 5)
垃圾回收器当中, 新增的对象个数-消亡的对象个数 , 达到一定的阈值时, 才会触发, 垃圾检测
垃圾回收时机(掌握&简单)
1. 自动回收
- 触发条件
开启垃圾回收机制
gc.enable()
开启垃圾回收机制(默认开启)
gc.disable()
关闭垃圾回收机制
gc.isenabled()
判定是否开启
并且达到了垃圾回收的阈值
垃圾回收器中, 新增的对象个数和释放的对象个数之差到达某个阈值
涉及方法
gc.get_threshold()
获取自动回收阈值
gc.set_threshold()
设置自动回收阈值
2. 手动回收
- 触发条件
gc.collect()
执行一次垃圾回收(开关状态无效)
测量对象的引用个数
辅助工具
objgraph
http://mg.pov.lt/objgraph/
xdot
graphviz
# 私有装饰器
import win32com.client
# 创建播报器对象(window系统适用)
# speaker = win32com.client.Dispatch("SAPI.SpVoice")
# 通过播报器对象,播报语音字符串
# speaker.Speak("你好,小谢")
class Calc:
# 注意这里需要有self参数
def __say_decorator(self, word):
# 创建播报器对象(window系统适用)
speaker = win32com.client.Dispatch("SAPI.SpVoice")
# 通过播报器对象,播报语音字符串
speaker.Speak(word)
def __create_say_decorator(operator_sign=""):
def say_decorator(func):
def inner(self, num):
self.__say_decorator(operator_sign + str(num))
return func(self, num)
return inner
return say_decorator
def __check_num_decorator(func):
def inner(self, num):
if not isinstance(num, int):
raise TypeError("类型错误,应该是一个整型数据")
return func(self, num)
return inner
@__check_num_decorator
@__create_say_decorator()
def __init__(self, num):
self.__res = num
@__check_num_decorator
@__create_say_decorator("加上")
def add_method(self, value):
self.__res += value
return self
@__check_num_decorator
@__create_say_decorator("减去")
def sub_method(self, value):
self.__res -= value
return self
@__check_num_decorator
@__create_say_decorator("乘以")
def mut_method(self, value):
self.__res *= value
return self
@__check_num_decorator
@__create_say_decorator("除以")
def div_method(self, value):
self.__res //= value
return self
# @__say_decorator
def show_value(self):
str1 = f"计算结果是{self.__res}"
self.__say_decorator(str1)
print(str1)
return self
def clear(self):
self.__res = 0
return self
@property
def result(self):
return self.__res
calc = Calc(100)
calc.add_method(56).sub_method(30).mut_method(3).div_method(120).show_value().clear().sub_method(200).show_value()
print(calc.result)
概念:
单继承
概念:仅仅继承了一个父类
语法:
class Dog(Animal):
pass
多继承
概念:继承了多个父类
语法
class child(Father, Mather):
pass
新式类:直接或者间接继承自object的类(python3.x没有显式继承object,但实际继承了object)
经典类:没有直接或者间接继承自object的类(python2.x没有显式继承object,需要手动继承了object)
资源的继承
资源的使
继承的几种形态
单继承链:一个子类只有一个父类
无重叠的多继承链:继承链无交叉, 无公共父类
有重叠的多继承链:继承链有交叉, 有公共父类
几种形态应该遵循的标准原则
针对于几种标准原则的方案演化
import inspect
# 查看资源顺序三种方式
print(inspect.getmro(A))
print(A.mro())
print(A.__mro__)
资源的覆盖(属性覆盖,方法重写)
原理:
在MRO的资源检索链当中,优先级比较高的类写了一个和优先级比较低的类一样的一个资源(属性或方法),到时候, 再去获取相关资源, 就会优先选择优先级比较高的资源;,而摒弃优先级比较低的资源; 造成"覆盖"的假象。
注意事项:当调用优先级比较高的资源时, 注意self的变化
资源的累加:在一个类的基础之上, 增加一些额外的资源
子类相比于父类, 多一些自己特有的资源,直接添加
在被覆盖的方法基础之上, 新增内容:
方案一:在高优先级类的方法中, 通过"类名"调用低优先级类的方法,弊端是代码维护性差、容易产生重复调用;
方案二:在低优先级类的方法中, 通过"super"调用高优先级类的方法
概念:一个类,在新式类中有效
作用:
问题:沿着谁的MRO链条? 找谁的下一个节点? 如何应对类方法, 静态方法以及实例方法的传参问题?
语法原理:
super(参数1[, 参数2]) 参数1:当前类,参数2为当前类获实例
工作原理:
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
问题解决:
常用具体语法形式:
# python2.2+
super(type, obj) -> bound super object;
# 需要链条的类与实例
requires isinstance(obj, type)
super(type, type2) -> bound super object;
# 需要链条的类
requires issubclass(type2, type)
# python3+
super()
注意:
抽象类:抽象出来的类,没有具体的实现,不能创建实例,否则会报错
抽象方法:抽象出来的方法,没有具体实现,不能直接被调用,需要子类实现(子类不实现会报错)
python中实现抽象:
具体抽象方法和属性实现查看官方文档
class Animal(object):
def __init__(self, name, age=1):
self.name = name
self.age = age
def eat(self):
print(f"{self}吃饭")
def play(self):
print(f"{self}玩")
def sleep(self):
print(f"{self}睡觉")
class Dog(Animal):
def work(self):
self.__see_home()
def __see_home(self):
print(f"{self}在看家")
def __str__(self):
return f"名字是{self.name}, 年龄{self.age}岁的小狗在"
class Cat(Animal):
def work(self):
self.__catch_mouse()
def __catch_mouse(self):
print(f"{self}捉老鼠")
def __str__(self):
return f"名字是{self.name}, 年龄{self.age}岁的小猫"
class Person(Animal):
def __init__(self, name, pets, age=1):
super(Person, self).__init__(name, age)
self.pets = pets
def keep_pets(self):
for pet in self.pets:
pet.eat()
pet.play()
pet.sleep()
def make_pets_work(self):
for pet in self.pets:
pet.work()
def __str__(self):
return f"名字是{self.name}, 年龄{self.age}岁的天才"
dog = Dog("旺财", 12)
# dog.eat()
# dog.sleep()
cat = Cat("小花")
person = Person("xie", [dog, cat], 15)
print(person)
person.keep_pets()
person.make_pets_work()
错误:没法通过其他的代码进行处理的问题
语法错误
逻辑错误
语法层面没有问题, 但是自己设计的逻辑出现问题
例如
用户输入年龄, 判定是否成年
if age < 18:
print("已经成年")
这种错误, IDE或者解释器无法帮我们检测出, 只有我们通过代码测试进行排查
异常:多指程序在执行的过程中, 出现的未知错误; 语法和逻辑都是正确的; 可以通过其他代码进行处理修复
'''
除零异常
示例代码
1 / 0
异常名称
ZeroDivisionError
名称异常
示例代码
sz
异常名称
NameError
类型异常
示例代码
"1" + 2
异常名称
TypeError
索引异常
示例代码
l = [1, 2]
l[3]
异常名称
IndexError
键异常
示例代码
dic = {"name": "sz", "age": 18}
dic["add"]
异常名称
KeyError
值异常
示例代码
int("abc")
异常名称
ValueError
属性异常
示例代码
name = "sz"
print(name.xx)
异常名称
AttributeError
迭代器异常
示例代码
it = iter([1, 2])
print(next(it))
print(next(it))
print(next(it))
异常名称
StopIteration
'''
系统异常类继承树:
BaseException 所有内建的异常的基类:
系统一开始已经内置了一些特定的应用场景; 当我们写代码的过程当中, 一旦触发了这个场景, 系统内部就会自动的向外界抛出这个问题, 也就是我们所谓的异常;不做处理,程序被终止执行; 软件的崩溃。
弊端:容错代码不属于我们主要的业务逻辑; 如果容错代码过多, 会造成代码混乱, 主业务不清晰
方式一处理异常
try:
# 这里不管以后会抛出多少个异常, 只会从上往下检测, 检测到一个后, 就立即往下去匹配, 不会多次检测
可能会出现异常的代码
except 你要捕捉的异常类别 as(Python3使用as, python使用英文逗号) 接收异常的形参:
# 这一块可以有多个重复, 用于捕捉可能的其他异常; 如果针对于多个不同的异常有相同的处理方式, 那么可以将多个异常合并,通过写出元组合并
对于这个异常的处理
else:
# 这一块必须放在上一块except结束后(可以省略)
没出现异常时做的处理
finally:
# 这一块必须放最后(可以省略)
不管有没有出现异常, 都会执行的代码
注意:
try语句没有捕获到异常,先执行try代码段后,在执行else,最后执行finally
如果try捕获异常,首先执行except处理错误,然后执行finally
如果异常名称不确定, 而又想捕捉, 可以直接写Exception
方式二处理异常
作用:适用于执行某一段代码A之前, 进行预处理, 执行代码A结束后, 进行清理操作;不管出现了什么异常, 最终都要执行一些清理操作
语法:
with context_expression [as target(s)]:
with-body
语法图解:
示例:
try:
f = open("m5.jpg", "r")
f.readlines()
except Exception as e:
print(e)
finally:
print("ccc")
f.close()
# 但是以上写法过于繁琐, 于是有了这个方案
# 但是如果产生了异常, 依然会报错; 并没有进行异常处理操作
with open("m5.jpg", "r") as f:
f.readlines()
3.自定义上下文管理器
import traceback
class Test(object):
def __enter__(self):
print("enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(self, exc_type, exc_val, exc_tb)
print(traceback.extract_tb(exc_tb))
print("exit")
# True 不显示异常信息, False:显示异常信息
return True
with Test() as x:
# print("body", x)
1 / 0
'''
定义的类, 实现"上下文管理协议"
__enter__
做一些预处理操作
__exit__
做一些清理操作
接收抛出的异常
如果返回True, 则忽略异常; 如果返回的False, 则再次抛出异常
'''
contextlib 模块
import contextlib
# @contextlib.contextmanager
# def test():
# # __enter__方法的具体实现
# print(1)
# # __exit__方法的具体实现
# yield "kkkk"
# print(2)
#
#
# with test() as x:
# print(3, x)
@contextlib.contextmanager
def ze():
try:
yield
except Exception as e:
print("error", e)
num1 = 1
num2 = 0
with ze():
num1 /num2
# try:
# num1 / num2
# except Exception as e:
# print("666")
a = 10
b = 0
with ze():
a / b
class Test:
def t(self):
print("tttt")
# 必须写
def close(self):
print("资源释放")
# 使用contextlib.closing取代
# def __enter__(self):
# return self
#
# def __exit__(self, exc_type, exc_val, exc_tb):
# self.close()
with contextlib.closing(Test()) as test:
test.t()
# python2.7
# with open("m5.jpg", "rb") as from_file:
# with open("m52.jpg", "wb") as to_file:
# contents = from_file.read()
# to_file.write(contents)
# python3.x, 以后写法
with open("m5.jpg", "rb") as from_file, open("m52.jpg", "wb") as to_file:
contents = from_file.read()
to_file.write(contents)
# python2.7之前
# with contextlib.nested(open("m5.jpg", "rb"), open("m52.jpg", "wb")) as (from_file, to_file):
# contents = from_file.read()
# to_file.write(contents)
'''
@contextlib.contextmanager
使用装饰器, 让一个生成器变成一个"上下文管理器"
contextlib.closing
这个函数, 让一个拥有close方法但不是上下文管理器的对象变成"上下文管理器"
contextlib.nested
python2.7之前: 完成多个上下文管理器的嵌套
'''
根据严重程度是抛出异常还是处理解决异常,通过 raise 语句直接抛出相关类型的异常
def setAge(age):
if age <= 0 or age > 200:
raise ValueError("值错误")
else:
print(age)
try:
setAge(-2)
except Exception as e:
print(e)
class MyException(Exception):
def __init__(self, msg, error_code=200):
self.msg = msg
self.error_code = error_code
def __str__(self):
return self.msg + ":" + str(self.error_code)
def setAge(age):
if age <= 0 or age > 200:
raise MyException("年龄不符合,值错误", 404)
else:
print(age)
try:
setAge(-2)
except MyException as e:
print(e)
一些开发人员直接写的包,供给其他人下载使用
自己写的包/模块,发布出去就是第三方包/模块
包/模块的名称:模块名称为去掉.py的文件名,包名为文件夹名
包和模块存放的位置:
import os
# 打印当前文件路径
print(os.path)
# 打印os模块存放位置路径
print(os.__file__)
查看包/模块的里面的内容
print(dir(包名/模块名))
常规导入(import语句导入)
'''
以下的包模块可以使用点语法定位
1.导入单个模块
import 同级目录的模块名/包名.模块名(注意包名可以嵌套,但是自己定义的模块与包使用这种方式导入只能导入当前py文件目录下的,不然报错找不到)
2.导入多个模块
import 同级目录的模块名/包名.模块名, 同级目录的模块名/包名.模块名...
3.导入单个/多个模块并起别名(使用as关键字,与sql语法不同的是as不能省略)
import 同级目录的模块名/包名.模块名 as 别名, 同级目录的模块名/包名.模块名 as 别名 ...
注意:
1.使用时,需要指定资源的模块名称,即写全,例如p1.tool_module.name
2.如果仅仅导入一个包,在__init__.py再次导入相关模块,一般使用from... import...方式导入
'''
2.from… import语句导入
'''
语法:
from A import B[ as 别名]
A的资源必须包含B,即A顺序在前
资源排序:
包 > 模块 > 模块资源
注意面向关系:
包只能看到模块,看不到模块资源
模块只能看到模块资源
最终组合:
1.从包中导入导入模块(包是可能有层级关系,模块没有层级,但可以多个,可以起别名)
2.从模块中导入导入模块资源(模块是可能有层级关系(包有层级的),模块资源没有层级,但可以多个,可以起别名)
注意:
保持import后面最简化,即所有层级关系放在from后面;
注意导入模块,模块是当前文件目录下的或文件目录的上级目录下的等等,需要写全包的路径名,即类似idea的全类名去掉类
特例:
1.from 模块 import *
"*"代表所有非下划线_开头资源导入到当前位置(定义__all__看列表的,这个规定需要看列表有没有写入来判断)
与在引入模块声明的__all__ = ["资源1", "资源2", ...]配合使用,代表"*"匹配到的资源,注意列表内都是字符串
注意:慎用,避免当前位置与导入资源的变量冲突
2.from 包 import *
与在引入包的__init__.py中声明的__all__ = ["资源1", "资源2", ...]配合使用,代表"*"匹配到的模块,注意列表内都是字符串
必须写__all__,没有什么都不导入
'''
导入模块具体发生的事情:
从什么位置找到需要导入的模块:
第一从导入:
第一级:内置模块
第二级:
sys.path构成:
当前目录:
import os
print(os.getcwd())
环境变量中PYTHONPATH(这个的路径是按照自己定义的)中指定的路径列表
特定路径下的.pth文件中的文件路径列表
查看特定路径
# 查看特定路径
import site
print(site.getsitepackages())
后缀名.pth,名字随意,一个路径占一行
在python安装路径的lib库中搜索
追加路径的方式:
直接追加到sys.path列表,只作用本次
修改环境变量
添加.pth文件(在特定路径下创建该文件,并且文件内容的路径不能为中文)
第二次导入:
从已经加载过的模块去找
查看已加载文件
# 查看已加载文件
import sys
print(sys.modules)
局部导入:
覆盖导入:
循环导入:
可选导入
包内导入:python相对导入与绝对导入是基于包内导入而言的,包内导入就是包内导入包内部的模块
绝对导入:
参照sys.path路径进行检索
例如指明包名或模块名
import a
from a import b
注意:以上结论是基于python3.x以上
相对导入:
使用**.来指明相对路径,.是根据模块名称获取的当前目录,…**是根据模块名称所获取的上层目录
例如:
from . import a
from .. import a
注意:解释器是根据模块名称而确定层级关系,而不是存放目录,通过下划线下划线__name__下划线下划线查看模块名称。
结论:
# __name__
# 如果一个py文件直接以脚本形式执行 python file,它的名称就是__main__
# 如果一个py文件使用模块的形式,进行加载的,那么它的名称由加载路径决定的,包名(顶级名称).子包名.模块名
# import tool2
# import tool2 python2.x 隐式相对导入等同于 from . import tool2
# import tool2
# 使用from __future__ import absolute_import禁用隐式相对导入
from __future__ import absolute_import
import tool2
具体含义看源码
import(name, globals=None, locals=None, fromlist=(), level=0):动态加载模块(import前后有双下划线)
hasattr(object, name, default=None):判断实例obj是否存在字符串name对应的属性
getattr(object, name, default=None):获取字符串name对应的属性
setattr(x, y, v):设置属性到实例
delattr(x, y):删除实例中字符串对应的属性,等同del x.y
反射案例:
# 案例一
class User(object):
def add_user(self):
print("添加用户")
def delete_user(self):
print("删除用户")
def update_user(self):
print("更新用户")
def select_user(self):
print("查找用户")
def before_process(self, method):
if method == "add":
self.add_user()
elif method == "delete":
self.delete_user()
elif method == "update":
self.update_user()
elif method == "select":
self.select_user()
else:
print("无效调用")
def after_process(self, method):
"""
去除ifelse的繁琐,类似理由转发
"""
# p判断是否存在该方法
if hasattr(self, method):
# 获取方法
user_method = getattr(self, method)
user_method()
else:
print("无效调用")
if __name__ == "__main__":
# 没有处理,好多if
User().before_process("delete")
# 处理后
User().after_process("delete_user")
# 案例二
# 保证按位置传参且只能传一个
def new_method(self, /):
print("我是新来的,给我一个实例")
def main():
"""
动态加载模块,创建类实例执行其中方法
"""
# 动态导入模块Func
func_module = __import__("Func", fromlist=True)
print(func_module)
# 判断是否找到对应类
if hasattr(func_module, "Func"):
# 通过模块对象实例获取类对象实例
func_class = getattr(func_module, "Func")
# print(type(func_class))
print(func_class)
# 判断是否存在方法
if hasattr(func_class, "process"):
# 通过类对象获取成员方法
process_method = getattr(func_class, "process")
# print(type(process_method))
print(process_method)
# 执行该方法
process_method(func_class)
else:
print("没有找到当前方法")
# 向类添加方法
setattr(func_class, "newFunc", new_method)
# 是否成功添加方法
if hasattr(func_class, "newFunc"):
# 获取该方法
new_func = getattr(func_class, "newFunc")
# 执行方法
new_func(func_class)
else:
print("添加失败")
# 删除Func类中法
delattr(func_class, "newFunc")
if not hasattr(func_class, "newFunc"):
print("删除成功")
else:
print("没有找到该类")
# 测试代码
if __name__ == "__main__":
main()
特定路径下的.pth文件中的文件路径列表
1. 查看特定路径
```python
# 查看特定路径
import site
print(site.getsitepackages())
```
2. 后缀名.pth,名字随意,一个路径占一行
- 在python安装路径的lib库中搜索
- 追加路径的方式:
1. 直接追加到sys.path列表,只作用本次
2. 修改环境变量
- 修改PYTHONPATH,把需要的模块路径定义到环境变量(不用添加到path),仅仅在shell起作用
- 在pycharm需要另外一种设置方式,设置里面的python Interpreter –> show ALL –>修改Interpreter path后点击ok,apply
3. 添加.pth文件(在特定路径下创建该文件,并且文件内容的路径不能为中文)
第二次导入:
从已经加载过的模块去找
查看已加载文件
# 查看已加载文件
import sys
print(sys.modules)