python笔记
2024-05-05 09:53:48 1 举报
AI智能生成
基础语法
作者其他创作
大纲/内容
基础语法
python是动态语言
给变量赋值的时候,不需要指定变量的数据类型
尽管会警告,但还是照样运行
告诉程序员看:我这个函数规定了数据类型,你传错类型后续出了什么事不负责
告诉程序员看:我这个函数规定了数据类型,你传错类型后续出了什么事不负责
print
print("{0}+{1}={2}".format(1, 2, 3))
1+2=3
这个在下面字符串格式化里会详细讲
print("balabalabala", end=" ")
不写end,默认换行(end="\n")
"这个是%s常用的%s格式化" % ("我", "字符串")
%s
字符串
%10s,表示10个字符的宽度
%i or %d
整数
同上
%f
浮点数
%.3f,保留三位小数
%10.3f,宽10并保留三位小数
f'我叫{"你猜"},今年{88}岁'
保留字
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
转义字符
\n
换行,一般在末尾,strip对其也有效
\0
空字符
\t
tab,四个空格
\'
‘
\''
“
\\
\
以下不常用
\a
发出系统响铃声
\b
退格符,覆盖删除前一个
\r
换行,并将当前字符串之前的所有字符删除
\v
不常用
\f
不常用
数据类型
内置的 type() 函数可以用来查询变量所指的对象类型
Number(数字)
String(字符串)
List(列表)
Tuple(元组)
Set(集合)
Dictionary(字典)
String(字符串)
List(列表)
Tuple(元组)
Set(集合)
Dictionary(字典)
不可变数据(3 个):Number(数字<包括int(整型)、float(浮点型:小数)、bool(布尔型)、complex(复数)>)
String(字符串)、Tuple(元组);
不可以增删改
做改变之后 id() 查看内存地址,改变
String(字符串)、Tuple(元组);
不可以增删改
做改变之后 id() 查看内存地址,改变
可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
可以增删改
增删改后用内置函数 id() 查看内存地址,不变
可以增删改
增删改后用内置函数 id() 查看内存地址,不变
作用:
number:用来存储数字类型的数据,多用于运算,布尔型也属于number,用于逻辑运算,true为真,false为假
string:用来存储字符串,如中文、英文等,一般用于一些描述性的文字输出
list:用来存储列表,即多个数据类型任意的元素
tuple:用来存储元组,一种有序的且不可更改的集合
set:用来存储集合,一种无序的,且可以更改的集合
dictionary:用来存储字典,一种无序的,可变的有索引的集合
number:用来存储数字类型的数据,多用于运算,布尔型也属于number,用于逻辑运算,true为真,false为假
string:用来存储字符串,如中文、英文等,一般用于一些描述性的文字输出
list:用来存储列表,即多个数据类型任意的元素
tuple:用来存储元组,一种有序的且不可更改的集合
set:用来存储集合,一种无序的,且可以更改的集合
dictionary:用来存储字典,一种无序的,可变的有索引的集合
字符类型转化
str()
int()
float()
注释
单行:#
多行: ''' 或者"""
input
运算符
算数
+
-
*
/
%取余
**幂
//取整除,向下取整
赋值
=
+=
-=
*=
/=
%=
**=
/=
:=,不常用
比较
==
!=
<
>
<=
>=
逻辑(布尔)
and,与
or,或
not,非
位运算
将数字转成二进制进行计算
python中可用bin(4).replace('0b','')得到对应二进制数
python中可用bin(4).replace('0b','')得到对应二进制数
&
按位与,都是1才是1,其他全是0
|
按位或,有1就是1
^
按位异或,不同就是1
~
按位取反,0变1,1变0
<<
左移动相应位数,高位丢弃,低位补0
x<<n==x*(2**n)
>>
右移动相应位数,低位丢弃,高位补0
x>>n==x/(2**n)
int除完会变成float
所以只是数值上相等,type上还是不同的
所以只是数值上相等,type上还是不同的
优先级
**
*,/,//,%
+,-
<<,>>
&
|
>,<,>=,<=,==,!=
and
or
=
三大结构(顺序,选择,循环)
顺序结构
选择结构
对象的布尔值
python一切皆对象,所有对象都有一个布尔值,
bool()
bool()
以下都为false
false
数值0
None
空字符串
"", ''
空列表
[], list()
空元组
(), tuple()
空字典
{}, dict()
空集合
set()
其他对象布尔值都为true
判断方法
==
比较值
is
是否是同一个地址
isinstance
判断当前对象是否是指定对象的子类
if isinstance (当前对象,指定对象)
单分支
if
双分支
if else
多分支
if elif elif (else)
嵌套
if 套 if
插一嘴
pass语句
一个占位符:没想好if判断后执行啥,先pass占个位
三元运算
语句1 if 判断语句 else 语句2
判断语句成立执行语句1,否则执行语句2
循环结构
range()
range(stop)
range(start, stop)
range(start, stop, step)
while循环
一般while true,也可以while+条件
for_in 循环
break跳出
if...break
结束当前循环,本层
或者直接break
continue
if...continue
结束当前循环,直接进入下次循环,本层
或者直接continue
else
for...else
当循环中不执行break,则执行else
while...else
break会让else中的代码不执行,continue就没这个功能
嵌套循环
字符串
驻留
在内存中保存一份且不可变字符串的方法。(相同的字符串只保留一份)
交互模式(cmd)
字符串长度为0或者1
符合标识符的字符串(只包含字符 数字 下划线)
字符串只在编译时进行驻留,而非运行时
a = 'abc'
b = 'ab' + 'c'
c = ''.join(['ab','c'])
print(a is b)>>True
print(a is c)>>False
b = 'ab' + 'c'
c = ''.join(['ab','c'])
print(a is b)>>True
print(a is c)>>False
a b c值一样,type也都是str
b的值在运行之前就连接完毕了
c的值是程序运行的时候通过join的方法和列表连接的,
运行的时候会开辟新的存储空间,所以和a b的存储空间不一样
b的值在运行之前就连接完毕了
c的值是程序运行的时候通过join的方法和列表连接的,
运行的时候会开辟新的存储空间,所以和a b的存储空间不一样
[-5,256]之间的整数数字
通过a == b,查看值是否相等,通过a is b,查看存储位置是否相等,用id( )也可以查看存储位置
相同的值可以强制驻留
import sys
a = sys.intern(b)
a = sys.intern(b)
pycharm对字符串进行了优化,有些不驻留的进行了强制驻留处理
优点
避免频繁重复创建销毁,提升效率节约内存
因为字符串的拼接和修改比较影响性能
用str类型的join来拼接字符串,而非+
join()是先计算所有字符串的长度,再拷贝,只new一次对象,效率比+高
查
index()
查询substr(子串)第一次出现的位置
找不到报valueerror
rindex()
查询substr(子串)最后一次出现的位置
找不到报valueerror
find()
查询substr(子串)第一次出现的位置
找不到返回-1
rfind()
查询substr(子串)最后一次出现的位置
找不到返回-1
count()
返回str在start和end之间,在my_str里出现的次数
my_str.count(str, start=0, end=len(my_str))
startswith()
检查字符串是否以指定字符串开头,返回True或False
endswith()
检查字符串是否以指定字符串结束,返回True或False
大小写转换
a.upper()
所有都大写
a.lower()
所有都小写
a.swapcase()
大转小,小转大
a.capitalize()
第一个大写,其余小写
a.title()
每个单词的,第一大写,其余小写
对齐
居中
a.center(20,'*')
参数第一个是宽度,第二个是填充符(默认空格)
如果宽度参数小于字符串长度,则返回原字符串
左对齐
a.ljust(20, '*')
同上
右对齐
a.rjust(20, '*')
同上
右对齐,左0补齐
a.zfill(20)
一个参数,如果是-87654,在 - 后面填0
分割
split()
从左开始分割,默认从空格开始分割
放回一个列表
a.split(spe='分隔符参数', maxsplit=1最大分割次数)
maxsplit是可选参数
rsplit()
从右侧,同上
partition(str)
字符串分割为str前+str+str后三部分
splitlines()
若字符串中有换行,则按行分割,返回各行为元素的列表
判断
a.isidentifier()
是否为合法标识符字符串(只包含字母(中文) 数字 下划线)
a.isspace()
是否全是空白字符(空格 换行 tab)
a.isalpha()
是否全是字母(中文)
a.isdecimal()
是否全是十进制数字
a.isnumeric()
是否全是数字
只要是数字就行,中文数字,中文大写数字,罗马数字
a.isdigit()
是否只含数字
这个就只是阿拉伯数字
a.isalnum()
是否全是字母(中文)和数字
替换
a.replace('原字符串',‘替换成的字符串’,2)
第三个参数是最大替换次数,可选
合并
join()
'*'.join(list)
将列表中的元素用 * 合并成一个字符串
元组同上
字符串序列
单个字符当一个元素
a = '*'.join('hello world')
print(a)
>>h*e*l*l*o* *w*o*r*l*d
print(a)
>>h*e*l*l*o* *w*o*r*l*d
比较
>, >=, <, <=, ==, !=
比较规则:从第一个字符开始比较,到第一个不相同的字符
比较原理:比较的是字符的原始值order value
ord('a')
查看a的原始值
chr(97)
查看原始值为97的字符
切片
a[start : end : step]
a[:5]
从0到4
a[6:]
从6到最后
step正从前开始,step负从后开始
其他方法
删除两端空白字符
strip()
格式化(按固定格式输出)
在字符串中加入变量
在字符串中加入变量
"这个是%s常用的%s格式化" % ("我", "字符串")
%s
字符串
%10s,表示10个字符的宽度
%i or %d
整数
同上
%f
浮点数
%.3f,保留三位小数
%10.3f,宽10并保留三位小数
"这个是{0}比较常用的{1}格式化".format("我", "字符串")
{0:.3}
一共三位
{0:.3f}
三位小数
{0:10.3}
宽10位,共三位小数
f'我叫{"你猜"},今年{88}岁'
编码转换
编码
将字符串转换成二进制数据(bytes)
word = "赞美愚者"
encoding1 = word.encode(encoding='GBK') # GBK编码格式 一个中文两个字节
encoding2 = word.encode(encoding='utf-8') # utf-8 一个中文三个字节
print(encoding1)
print(encoding2)
encoding1 = word.encode(encoding='GBK') # GBK编码格式 一个中文两个字节
encoding2 = word.encode(encoding='utf-8') # utf-8 一个中文三个字节
print(encoding1)
print(encoding2)
>>b'\xd4\xde\xc3\xc0\xd3\xde\xd5\xdf'
>>b'\xe8\xb5\x9e\xe7\xbe\x8e\xe6\x84\x9a\xe8\x80\x85'
>>b'\xe8\xb5\x9e\xe7\xbe\x8e\xe6\x84\x9a\xe8\x80\x85'
解码
将bytes数据转换成字符串
decoding1 = encoding1.decode(encoding='GBK')
decoding2 = encoding2.decode(encoding='utf-8')
print(decoding1)
print(decoding2)
decoding2 = encoding2.decode(encoding='utf-8')
print(decoding1)
print(decoding2)
>>赞美愚者
>>赞美愚者
>>赞美愚者
列表
1. 列表对象有序排序
2. 索引映射唯一数据
3. 列表可以存储重复数据
4. 任意数据类型混存
5. 根据需要动态分配和回收内存
2. 索引映射唯一数据
3. 列表可以存储重复数据
4. 任意数据类型混存
5. 根据需要动态分配和回收内存
创建
lst=["a", "b", 98]
lst=list(["a", "b", 98])
列表生成式
lst = [i for i in range(1, 10)]
lst = [2*i for i in range(1, 6)]
>>[2, 4, 6, 8, 10]
>>[2, 4, 6, 8, 10]
获取
lst.index("a")
获取制定元素的索引(第一个)
lst[1]
获取列表中index为1的元素
切片
lstChild = lst[start : stop : step]
step为正
从前往后start
step为负
从后往前start
增删改查
查
判断元素是否存在
in
not in
遍历
首选
for item in lst:
item是可迭代对象
while
>>1
>>2
>>3
>>2
>>3
统计元素个数
L.count('a')
查询元素的索引
list.index('元素')
增
append()
列表末尾添加一个元素
extend()
列表末尾添加至少一个元素,增加的是另一个序列的多个值,但用的时候()里面是一个参数
这样不行list_ouput.extend(user_input1, user_input2, user_input3)
得这样list_ouput.extend([user_input1, user_input2, user_input3])
insert()
任意位置插入一个元素
insert(1,90):在index 1 位置上加入90
删
remove()
一次删除一个,有重复的删除第一个
lst.remove(元素值)
pop()
删除指定索引的元素,不写索引默认最后一个元素
lst.pop(索引号)
clear()
清空列表
del
根据下标删除
del list[2]
删除列表
改
lst[index]=修改后的元素
lst[start:stop]=[........]
切片修改
排序
lst.sort()
lst.sort(reverser=True),表示降序
通过id(lst)可查看还是同一个列表
lst.sort(key=function( ))
key参数主要用于自主选择排序的方式,一般=某函数
stus = [
{'name': 'yucas', 'age': 18},
{'name': 'wayne', 'age': 20}
]
stus.sort(key=lambda x: x['age'])
print(stus)
{'name': 'yucas', 'age': 18},
{'name': 'wayne', 'age': 20}
]
stus.sort(key=lambda x: x['age'])
print(stus)
sorted(lst)
sorted(lst, reverser=True), 降序
创建了一个新列表
reverse()
将列表倒叙
给程序传递参数
import sys
print(sys.argv)
print(sys.argv)
sys.argv就是一个列表,这个列表中存储着运行是传递的参数,注意全部是字符串
python test.py 卢卡斯
>>卢卡斯
>>卢卡斯
元组
创建
("元素",“有一个元素”, 8 )
()可以省略
tuple(......)
tuple(("元素",“有一个元素”, 8 ))
("元素",)
一个元素的元组,一定要加逗号
()
元组不可变,但元组中的可变数据可以改变,比如有个list元素
遍历
t = tuple(("python", "good", 98))
for item in t:
print(item)
for item in t:
print(item)
>>python
>>good
>>98
>>good
>>98
集合
没有value的字典
也有hash表计算存储位置
元素不允许重复,无序
也有hash表计算存储位置
元素不允许重复,无序
创建
{......}
set(......)
set([列表])
将列表转成集合
set((元组))
将元组转成集合
set("字符串")
将字符串转成集合
s1 = set("python")
print(s1)
>>{'o', 'p', 'n', 'y', 'h', 't'}
print(s1)
>>{'o', 'p', 'n', 'y', 'h', 't'}
set() 空集合
用{}创建的是空字典
增删改查
查
in
not in
增
s.add(一个元素)
s.update(至少一个元素)
删
s.remove(元素)
元素不存在报keyerror
s.discard(元素)
元素不存在不报错
s.pop()
不能加参数,随意删一个
s2 = s1.pop(),s2是s1中拿出的那个元素
s.clear()
清空元素
del s
删除集合
改
集合的元素为不可变类型,所以无法修改
集合之间的关系
相等
==
!=
子集
s1.issubset(s2)
s1是否是s2的子集
超集
s2.issuperset(s1)
s2是否是s1的超集
不相交
s1.isdisjoint(s2)
s1和s2是否不相交
交并差
交集
s1.intersection(s2)
s1 & s2
并集
s1.union(s2)
s1 | s2
差集
s1.difference(s2)
s1 - s2
对称差集(s1并s2 - s1交s2)
s1.symmetric_difference(s2)
s1 ^ s2
集合生成式(和列表差不多)
s1 = {i for i in range(1, 10)}
s4 = {2*i for i in range(1, 6)}
>>{2, 4, 6, 8, 10}
>>{2, 4, 6, 8, 10}
序列类型的类型转换(不包括字典)
tuple()
列表,集合转换为元组
set()
列表,元组转换为集合
可完成对list和tuple的快速去重
list()
元组,集合转换为列表
判断数据是否可迭代
from collections.abc import Iterable
print(isinstance([], Iterable))
>>True
print(isinstance([], Iterable))
>>True
zip()
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表
字典
1.键值对,键不可以重复,值可以重复
2.元素是无序的
3.key必须是不可变对象
4.动态调整内存
5.消耗较大内存
6.hash表计算存储位置
2.元素是无序的
3.key必须是不可变对象
4.动态调整内存
5.消耗较大内存
6.hash表计算存储位置
创建
a = {"name": 'Lucas', "age": 30}
b = dict(name='LucasLu', age=32),内置函数
c={},空字典
字典生成式
items = ["a", "b", "c"]
values = [1, 2, 3]
values = [1, 2, 3]
d = {item.upper() : value for item, value in zip(items, values)}
>>{'A': 1, 'B': 2, 'C': 3}
增删改查
查(键对应的值)
[键]
a["name"]
>>Lucas
>>Lucas
如果键不存在,报错,keyerror
get(键)
a.get("name")
如果键不存在,返回None
a.get("gaga", 99)
如果键不存在,返回默认值
key的判断
in
not in
遍历
所有键
for key in dict.keys():
print(key)
print(key)
所有值
for val in dict.values():
print(val)
print(val)
所有元素
for item in dict.items():
print(item)
print(item)
每对键值输出为一个元组tuple
删
del a["name"]
删除指定键值对
del a
删除整个字典a
a.clear
清空字典a
增
a["新键"]=对应的值
改
a["要修改的键"]=新值
视图操作
dict.keys()
获取字典中所有的键(key)
dict.values()
获取字典中所有的值(value)
dict.items()
获取字典中所有的键值对(key.value)
遍历元素
for item in a:
print(item)
获取键keys
print(a[item])
获取值values
print(a.get(item))
获取值values
推导式
快速生成数据
列表(List Comprehension列表解析)
[变量 for 变量 in 可迭代对象]
[x for x in range(4)]
加条件
[x for x in range(4) if x % 2 ==0]
for嵌套循环
a = [(x, y) for x in range(1, 3) for y in range(5, 10)]
自动x和y在取值范围内排列组合
列子[1, ..., 100]变成[[1,2,3], [4,5,6],...]
a = [x for x in range(1, 101)]
print(a)
b = [a[x:x+3] for x in range(0, len(a), 3)]
print(b)
print(a)
b = [a[x:x+3] for x in range(0, len(a), 3)]
print(b)
集合
同上
字典
name = ['张三', '李四', '王五', '赵六']
sign = ['水瓶', '射手', '摩羯', '双鱼']
dict = {x+'爷':y+'座' for x,y in zip(name, sign)}
print(dict)
sign = ['水瓶', '射手', '摩羯', '双鱼']
dict = {x+'爷':y+'座' for x,y in zip(name, sign)}
print(dict)
拆包
快速提取
元组
a, b = [11, 22]
列表
同上
集合
同上
字典
同上,默认取到的是key
# 这样可以去键值对
for k,v in dict.items():
print(k, v)
for k,v in dict.items():
print(k, v)
经典python交换变量值
a, b = b, a
=右边b, a 会被当做一个元组(b, a)
函数
创建
def 函数名([函数参数]):
函数体
[return xxx]
函数体
[return xxx]
def calc(a, b):
result = a+b
return result
result = a+b
return result
部分内置函数
len
返回长度
max
返回最大值
del
del a或者del(a)
time包
稍后再说
random包
用到再说
自定义函数记得加说明文档
参数传递
形参实参
形参(定义处)
a和b
实参(调用处)
a和b的实际值
参数调用
print(calc(10, 20))
print(calc(b=20, a=10))
print(calc(b=20, a=10))
形参实参名称可以不同
参数传递时的内存
如果是不可变对象,在函数体内的修改不影响实参的值
记住python赋值不是改变对象的值而是将对象指向存储值的内存就行
如果是可变对象,在函数体内的修改影响实参的值
参数定义
函数定义时,给形参定义默认值,调用时只有和默认值不符时传递实参
def fun(a, b=10):
print(a, b)
fun(100) # a=100, b=10
fun(20, 30) # a=20, b=30
print(a, b)
fun(100) # a=100, b=10
fun(20, 30) # a=20, b=30
*args(未命名参数)
个数可变的位置参数
结果是元组
def fun(*args):
print(args)
fun(10)
fun(10, 20, 30)
print(args)
fun(10)
fun(10, 20, 30)
>>(10)
>>(10, 20, 30)
>>(10, 20, 30)
这时args是一个元组,可以进行元组的各种操作
表示调用函数时多余的未命名参数都会以元组的方式存储到args里
一个函数只能定义一个位置参数
**args(**kwagrs)(命名参数)
个数可变的关键字参数
结果是字典
def fun(**args):
print(args)
fun(a=10)
fun(a=10, b=20, c=30)
print(args)
fun(a=10)
fun(a=10, b=20, c=30)
>>{'a': 10}
>>{'a': 10, 'b': 20, 'c': 30}
>>{'a': 10, 'b': 20, 'c': 30}
表示调用函数时多余的命名参数都会以键值对的方式存储到kwagrs
def fun(a, b, *, c, d)
*之后的参数只能用关键字参数传递
一个函数只能定义一个关键字参数,且要放在位置参数后面
不过这样也可以def fun(a, b, *, c, **arges)
因为本质上它还是只有一个关键字参数,*只不过是个条件
因为本质上它还是只有一个关键字参数,*只不过是个条件
总结
def fun(a, b, c):
print('a=', a)
print('b=', b)
print('c=', c)
print('a=', a)
print('b=', b)
print('c=', c)
fun(1, 2, 3)
a= 1
b= 2
c= 3
b= 2
c= 3
lst = [10, 20, 30]
fun(*lst)
fun(*lst)
a= 10
b= 20
c= 30
b= 20
c= 30
dic = {'a': 11, 'b': 12, 'c': 13}
fun(**dic)
fun(**dic)
a= 11
b= 12
c= 13
b= 12
c= 13
返回值return
返回值和结束函数2个作用
return后面的语句不会被执行,只执行第一个return
返回多个值时,结果为元组
是元组就能拆包
通过星号拆包
*对列表、元组、集合可以拆包,但一般都是在调用函数时用
**可以对字典进行拆包,拆包的结果是命名参数
4种函数
无参,无返回
一般情况下用来打印提示等类似的功能
无参,有返回
一般情况下像采集数据等功能会用到
有参,无返回
一般情况下对某些变量设置数据而不需结果时用此类函数
有参,有返回
大多数
函数嵌套
# 例1 画线
def line():
print('---------------'*3)
def print_lines(num):
for i in range(num):
line()
i += 1
print_lines(5)
def line():
print('---------------'*3)
def print_lines(num):
for i in range(num):
line()
i += 1
print_lines(5)
# 算平均数
def sum_up(n1, n2, n3):
return n1 + n2 + n3
def average(n1, n2, n3):
return sum_up(n1, n2, n3)/3
print(average(1, 5, 9))
def sum_up(n1, n2, n3):
return n1 + n2 + n3
def average(n1, n2, n3):
return sum_up(n1, n2, n3)/3
print(average(1, 5, 9))
变量的作用域
局部变量
函数内的
全局变量
函数外的
要在函数内修改全局变量,先用global声明
匿名函数(lambda)
add_up = lambda 形参1,形参2:表达式
用add_up(1, 2)调用
接收任何数量的参数但只能返回一个表达式的值,
其默认就是返回的,不用写return
其默认就是返回的,不用写return
使用方式
1.像普通函数一样,变量名( )
2.在其他函数实参的位置,直接定义一个lambda
def fun(a, b, opt):
print(opt(a, b))
fun(1, 4, lambda x, y: x+y)
print(opt(a, b))
fun(1, 4, lambda x, y: x+y)
递归函数
就是函数内调用自己
占内存效率低,但简单易懂啊
阶乘函数
def fac(n):
if n == 1:
return 1
else:
res = n*fac(n-1)
return res
def fac(n):
if n == 1:
return 1
else:
res = n*fac(n-1)
return res
斐波拉契数列
F[n]=F[n-1]+F[n-2] (n>=2,F[0]=0,F[1]=1)
F[n]=F[n-1]+F[n-2] (n>=2,F[0]=0,F[1]=1)
def fib(n):
if n == 1:
return 0
elif n == 2:
return 1
else:
return fib(n-1)+fib(n-2)
for i in range(1, 8):
print(fib(i))
if n == 1:
return 0
elif n == 2:
return 1
else:
return fib(n-1)+fib(n-2)
for i in range(1, 8):
print(fib(i))
有调用有终止
其实递归是一种算法,一般用来解决“树”、“图”等操作,还能解决像“汉罗塔问题”等
面向对象 特殊属性和方法 类的赋值和浅拷贝
面向过程 VS 面向对象
类
类 VS 对象
不同的数据类型属于不同的类
900就是int数据类型下的一个对象
python中一切皆对象
有id(内存空间),有type(数据类型),有值
有id(内存空间),有type(数据类型),有值
类的创建
class Student:
pass
pass
一般首字母大写,其余小写
组成
类属性
可以在外面通过Student.gender = None,加一个类属性
self
当通过实例对象调用方法的时候,self能够自动指向实例对象,从而拥有了操作这个对象中的属性或者方法的可能。
静态方法
静态方法之所以不需要self,是因为方法内不需要实例对象的引用
比如上面的例子中,eat方法,并没有指向name或者age,所以其实属于静态方法
能获取构造函数定义的变量,也不可以获取类的属性。
类方法
不能获取构造函数定义的变量,可以获取类的属性。
对象的创建
stu = Student(初始化方法的参数)
stu.eat()
对象名.方法名
Student.eat(stu)
类名.方法名(类的对象)----方法定义处的self
stu.name
调用属性
删除属性
调用
类属性
类中方法外的变量,被该类所有对象共享
# 直接写在类里面的变量
native_pace = '江苏'
native_pace = '江苏'
print(Student.native_pace)
print(stu.native_pace)
print(stu.native_pace)
类方法
使用类名直接访问的方法
@classmethod
def cm(cls):
print('类方法写cls')
def cm(cls):
print('类方法写cls')
Student.cm()
静态方法
使用类名直接访问的方法
@staticmethod
def method():
print('静态方法不加self')
def method():
print('静态方法不加self')
Student.method()
对象关联
类A,实例对象a=A()
类B,实例对象b=B()
类B,实例对象b=B()
B.新属性aa=a
再用B.aa就可以调用A的属性和方法了
三大特征(封装,继承,多态)
封装
将数据(属性)和行为(方法)包装到类对象中。(转为私有属性or隐藏属性)
如果属性不希望被外部调用,可以前面加2个_
self.__age = age
再用stu.__age是访问不到的,
但用stu._Student__age还是能访问,纯靠自觉
再用stu.__age是访问不到的,
但用stu._Student__age还是能访问,纯靠自觉
print(dir(cat)),可以看到cat的所有属性和方法
继承
基本概念
没写父类的默认继承object
定义子类时,要在构造函数中调用父类的构造函数
super().__init__( )
支持多继承
子类有多个父类
关于多继承的__mro__顺序
用类名.__mro__,这个魔术方法,可以查看这个类的继承顺序
用类名.__mro__,这个魔术方法,可以查看这个类的继承顺序
如果2个子类中都继承了同个父类,当在子类中通过父类名调用时,parent被执行了2次
子主题
如果2个子类中都继承了同个父类,当在子类中通过super调用时,parent被执行了1次
子主题
子主题
单继承
子类只有一个父类
子主题
子主题
1.super().__init__相对于类名.__init__,在单继承上用法基本无差
2.但在多继承上有区别,super方法能保证每个父类方法只会执行一次,而类名.方法()会导致方法可能被执行多次
3.多继承时,用super方法,对父类传参,由于super的算法,必须把参数全部传递,否则报错,所以就要加上*args和**kwargs
4.单继承时,用super方法,不用全部传参,只能传父类方法所需的参数,否则报错
注:在多继承时,尽量不用super,用父类名.方法()
用super虽然对于同个父类的调用可以避免重复执行,但代码阅读难度增加,不利于debug
2.但在多继承上有区别,super方法能保证每个父类方法只会执行一次,而类名.方法()会导致方法可能被执行多次
3.多继承时,用super方法,对父类传参,由于super的算法,必须把参数全部传递,否则报错,所以就要加上*args和**kwargs
4.单继承时,用super方法,不用全部传参,只能传父类方法所需的参数,否则报错
注:在多继承时,尽量不用super,用父类名.方法()
用super虽然对于同个父类的调用可以避免重复执行,但代码阅读难度增加,不利于debug
object类
所有类的父类
__str__()方法
返回对象的描述
https://blog.csdn.net/m0_57133702/article/details/120568504
方法重写
子类想输出自己独有的东西,父类没有
就是在子类中重新定义父类的方法
先加个super().xx()
这样可以继承父类的xx()方法
然后再加新的功能
先加个super().xx()
这样可以继承父类的xx()方法
然后再加新的功能
如果不加super(),就继承不了父类方法
多态
有别于如Java的静态语言,python这种动态语言的多态就相当灵活了
如果一个变量存储了某一个实例对象的引用,且通过这个变量调用指向的对象中的某个方法,
此时如果变量指向的对象是子类创建的那么就调用子类中的方法,如果是父类创建的对象那么就调用父类的方法
如果一个变量存储了某一个实例对象的引用,且通过这个变量调用指向的对象中的某个方法,
此时如果变量指向的对象是子类创建的那么就调用子类中的方法,如果是父类创建的对象那么就调用父类的方法
反正就是调用类的方法很方便
class Dog():
def bark(self):
print("普通狗汪汪叫")
class LangDog(Dog):
def bark(self):
print("狼狗狂吠")
class ZangAo(Dog):
pass
class Person():
def pk_dog(self, dog):
print('人向狗进行了攻击')
dog.bark()
Anna = Person()
dog1 = Dog()
dog2 = LangDog()
dog3 = ZangAo()
Anna.pk_dog(dog1)
Anna.pk_dog(dog2)
Anna.pk_dog(dog3)
def bark(self):
print("普通狗汪汪叫")
class LangDog(Dog):
def bark(self):
print("狼狗狂吠")
class ZangAo(Dog):
pass
class Person():
def pk_dog(self, dog):
print('人向狗进行了攻击')
dog.bark()
Anna = Person()
dog1 = Dog()
dog2 = LangDog()
dog3 = ZangAo()
Anna.pk_dog(dog1)
Anna.pk_dog(dog2)
Anna.pk_dog(dog3)
>>人向狗进行了攻击
>>普通狗汪汪叫
>>人向狗进行了攻击
>>狼狗狂吠
>>人向狗进行了攻击
>>普通狗汪汪叫
>>普通狗汪汪叫
>>人向狗进行了攻击
>>狼狗狂吠
>>人向狗进行了攻击
>>普通狗汪汪叫
内建属性
常用内建属性
__new__(cls)
帮助类在内存中只开辟一个空间
储存属性和方法
在__init__之前
储存属性和方法
在__init__之前
如果需要当前类做多个实例化,则只需要创建一个空间来存储实例对象
__init__
__class__
实例对象p是通过__class__找到Person这个类的,然后才能调用类中的方法
__getattribute__
实例对象要访问实例属性,要通过这个方法
方法中的item参数是实例属性的属性名称
能够完成属性访问时进行拦截
用户访问属性,传入一个参数,可以返回提前设定好的值
如果访问的是name1,会被拦截,传回指定值,如果访问name2,则可以返回传入的值
object.__getattribute__(self, item)是为了保证能返回属性的值,没有的话返回None
注意:不要在__getattribute__方法中调用self.xxxx,会进入死递归,用object.__getattribute__(self, item)
__doc__
类名.__doc__
输出类的说明描述。类的说明写在类名下一行,__doc__只调用那段注释。
__module__和__class__
module打印所在的模块(所在的py文件)
class打印所在类
class打印所在类
__del__
当对象在内存中被释放之前,自动触发执行
一般不去改
__call__
可以在__call__中添加一些功能,用Foo()()直接调用
把实例对象当成一个函数去使用
当成函数去用,就可以传参了
__dict__
返回类的属性和方法,以及对应的值
返回实例对象的属性,名称和值
返回实例对象的属性,名称和值
__str__
如果在类中定义了__str__方法,打印方法时,默认输出这个方法的返回值
返回值只接受string
__getitem__, __setitem__, __delitem__
对容器类型进行操作,获取,设置,删除
对于列表,元组,字符串。foo[index],索引
对于字典。foo[key],键
对于列表,元组,字符串。foo[index],索引
对于字典。foo[key],键
字典
一定要用foo['hahaha']操作才能调用这三个方法
一定要用foo['hahaha']操作才能调用这三个方法
动态绑定属性和方法
创建完对象后,为个别对象动态绑定一个属性(方法),该属性只有这个对象有,其他对象没有
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '在吃饭')
stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
stu1.gender = '女' # 这一步就是动态绑定新属性
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '在吃饭')
stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
stu1.gender = '女' # 这一步就是动态绑定新属性
gender属性只有stu1有
def show(self):
print('stu1专属方法', self.name)
import types
# MethodType给类动态绑定实例方法
stu1.show = types.MethodType(show, stu1) # 将show方法帮给stu1对象
stu1.show()
print('stu1专属方法', self.name)
import types
# MethodType给类动态绑定实例方法
stu1.show = types.MethodType(show, stu1) # 将show方法帮给stu1对象
stu1.show()
show()只有stu1能调用
@staticmethod
def static_func():
print('这是一个静态方法')
Student.address = '深圳' # 先创建一个类属性
@classmethod
def class_func(cls):
print(f'这是类方法,类属性值为:{cls.address}')
Student.static_func = static_func
Student.class_func = class_func
stu2.static_func()
stu1.class_func()
def static_func():
print('这是一个静态方法')
Student.address = '深圳' # 先创建一个类属性
@classmethod
def class_func(cls):
print(f'这是类方法,类属性值为:{cls.address}')
Student.static_func = static_func
Student.class_func = class_func
stu2.static_func()
stu1.class_func()
__slots__特殊属性
限制属性的创建
1.为了限制随意给对象添加属性或者方法
2.对子类不起作用,只限制当前类
3.不可以卸载__init__中
1.为了限制随意给对象添加属性或者方法
2.对子类不起作用,只限制当前类
3.不可以卸载__init__中
property属性
1.装饰器方式
当前类中,装饰在某个方法上,使得这个方法可以像属性那样被调用
用于拿到当前方法中计算的返回值
被property装饰的方法不能创建除了self之外的形参
用于拿到当前方法中计算的返回值
被property装饰的方法不能创建除了self之外的形参
@property
def func(self):
return '调用func'
foo = Foo()
res = foo.func
def func(self):
return '调用func'
foo = Foo()
res = foo.func
简单例子:
'''
对于京东商城中显示电脑主机的列表页面,
每次请求不可能把数据库中的所有内容都显示到页面上,
而是通过分页的功能局部显示,
所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:
1.根据用户请求的当前页和总数据条数,计算出m和n
2.根据m和n去数据库中请求数据
'''
对于京东商城中显示电脑主机的列表页面,
每次请求不可能把数据库中的所有内容都显示到页面上,
而是通过分页的功能局部显示,
所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:
1.根据用户请求的当前页和总数据条数,计算出m和n
2.根据m和n去数据库中请求数据
'''
>>第一页显示第0到第9条数据
>>第一页显示第10到第19条数据
>>第一页显示第10到第19条数据
用property进行商品价格控制
>>100
>>200
>>... AttributeError: 'Goods' object has no attribute 'price'. Did you mean: '_price'?
>>200
>>... AttributeError: 'Goods' object has no attribute 'price'. Did you mean: '_price'?
在商城开发中设置打折价格
>>80.0
>>setter被调用
>>160.0
>>deleter被调用
>>.... AttributeError: 'Goods' object has no attribute 'original_price'
>>setter被调用
>>160.0
>>deleter被调用
>>.... AttributeError: 'Goods' object has no attribute 'original_price'
2.类属性方式,创建值为property对象的类属性
类属性 = property(需要装饰的方法)
>>100
案例
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 类名.属性.__doc__ ,此参数是该属性的描述信息
注:property中的参数顺序一定要按照get set del排序
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 类名.属性.__doc__ ,此参数是该属性的描述信息
注:property中的参数顺序一定要按照get set del排序
>>当前get bar被执行
>>a
>>当前set bar被执行 d
>>当前del bar被执行
>>当前字符串是对property的一个解释说明
>>a
>>当前set bar被执行 d
>>当前del bar被执行
>>当前字符串是对property的一个解释说明
python2.7中常这么用,3之后很少用
if__name__=='__main__':
函数入口:写在入口下的内容只能在当前文件内运行,被引用时,入口下的内容引用不到
test_1
test_2
>>num1是可引用内容
>>100
>>AttributeError:不拉不拉,test_1没num2这个属性
>>100
>>AttributeError:不拉不拉,test_1没num2这个属性
用到再查
特殊属性
特殊方法
new和init的传参过程
三器一闭
迭代器
可以记住遍历的位置的对象
只能往前不能后退
只能往前不能后退
iter()和next()
for
while
# 一般写except Exception:当前python所有错误的基类
Iterable和Iterator
如果对象只有__iter__方法,是可迭代对象
如果对象有__iter__和__next__方法,则是迭代器
如果对象有__iter__和__next__方法,则是迭代器
自定义迭代器
例
1. 先定义主要类
2. 给这个类定义一个迭代器
3. MyList的实例对象my_list这时就可以用for循环遍历了
>>11
>>22
>>33
>>22
>>33
例:学生系统
1.初始化和add方法
2.iter和next
3.实例化,调用3次add,for循环遍历
请输入姓名: lucas
请输入年龄: 18
请输入地址: nanjing
请输入姓名: wayne
请输入年龄: 20
请输入地址: shenzhen
请输入姓名: bill
请输入年龄: 19
请输入地址: shanghai
>>{'name': 'lucas', 'age': 18, 'address': 'nanjing'}
>>{'name': 'wayne', 'age': 20, 'address': 'shenzhen'}
>>{'name': 'bill', 'age': 19, 'address': 'shanghai'}
请输入年龄: 18
请输入地址: nanjing
请输入姓名: wayne
请输入年龄: 20
请输入地址: shenzhen
请输入姓名: bill
请输入年龄: 19
请输入地址: shanghai
>>{'name': 'lucas', 'age': 18, 'address': 'nanjing'}
>>{'name': 'wayne', 'age': 20, 'address': 'shenzhen'}
>>{'name': 'bill', 'age': 19, 'address': 'shanghai'}
注释:
如果有4个类,分别在4个py文件中
这4个类的迭代的方法是一模一样的
写一个迭代器直接导入引用
如果有4个类,分别在4个py文件中
这4个类的迭代的方法是一模一样的
写一个迭代器直接导入引用
多继承也可以,但项目开发中,尽量少继承,继承的执行速度比对象关联慢
生成器
概念:含yield的函数
例
定义了一个生成器函数,函数返回一个生成器对象,然后就可以通过for语句进行迭代访问了。
生成器函数返回生成器的迭代器。 "生成器的迭代器"这个术语通常被称作"生成器"。
要注意的是生成器就是一类特殊的迭代器。
作为一个迭代器,生成器必须要定义一些方法,其中一个就是__next__()。如同迭代器一样,我们可以使用__next__()函数来获取下一个值。
要注意的是生成器就是一类特殊的迭代器。
作为一个迭代器,生成器必须要定义一些方法,其中一个就是__next__()。如同迭代器一样,我们可以使用__next__()函数来获取下一个值。
执行流程
会在yield处暂停
生成器表达式
创建长序列时使用
(x for x in range(100))
(x for x in range(100))
对比
列表解析(列表推导式)
>>列表推导式时间为3.2063777446746826
生成器表达式
>>生成器表达式时间为0.0
原因
列表解析:
1.开辟一个内存
2.开完内存创建所有值
生成器表达式:
1.返回的不是具体序列数据,是生成器对象
2.使用next()取生成器中的值,内存中只有一个值。调用一次,产生一个值
1.开辟一个内存
2.开完内存创建所有值
生成器表达式:
1.返回的不是具体序列数据,是生成器对象
2.使用next()取生成器中的值,内存中只有一个值。调用一次,产生一个值
例
>>True
>>True
>>25000000
>>[]
>>True
>>25000000
>>[]
内置方法
send()
1.send方法与next方法类似
2.可以向生成器传递一个参数,并在生成器中进行接受
3.一般不在第一次获取值时使用,第一次获取时必须传递None
print(my_iter.send(None))
4.可以在程序运行的过程中对当前的函数运行过程进行操作
2.可以向生成器传递一个参数,并在生成器中进行接受
3.一般不在第一次获取值时使用,第一次获取时必须传递None
print(my_iter.send(None))
4.可以在程序运行的过程中对当前的函数运行过程进行操作
>>0
>>接收到参数,将此时的i(即0)+10输出=10
>>1
>>接收到参数,将此时的i(即0)+10输出=10
>>1
注意 i 的值,第一次取值时在yield处暂停,第二次取值继续时,先读if判断,此时 i 还未 +1
close()
关闭当前生成器(相当于删除或销毁)
my_iter.close()
print(next(my_iter))
print(next(my_iter))
关闭之后再取值会抛出异常
总结
当调用生成器函数的时候,函数只是返回了一个生成器对象,并没有执行。
当next()方法第一次被调用的时候,生成器函数才开始执行,执行到yield处暂停
next()方法返回值就是yield处的参数
next()方法返回值就是yield处的参数
继续调用next()方法时,函数直接接着上一次暂停的yield处继续执行,到下一个yield出暂停
如果后面没有yield就抛出StopIteration异常
如果后面没有yield就抛出StopIteration异常
和return的区别
return:代表整个函数结束,结束前返回值,函数中只能有一个,生成器中不可以有return
yield:不代表函数结束(只是暂停),返回一个生成器对象(可用next取到其值),函数中可以写多个yield
yield:不代表函数结束(只是暂停),返回一个生成器对象(可用next取到其值),函数中可以写多个yield
生成器内部声明了迭代器协议:__iter__ __next__,不需要自己定义
闭包(优雅的编程技巧)
1.有函数嵌套,一般只嵌套一层
2.内部函数引用了外部函数的参数
就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。
可以这样理解,闭包就是能够读取其他函数内部变量的函数。
2.内部函数引用了外部函数的参数
就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。
可以这样理解,闭包就是能够读取其他函数内部变量的函数。
如果在一个函数中有内层函数
如果内层函数没有释放,则外层函数会永远占着内存
如果内层函数没有释放,则外层函数会永远占着内存
def person():
def info():
xxxxxx
p = person() # 这里只引用了info(),并没有调用,所以info没有运行,此时person()这个函数还是占着内存
p() # 这样就运行了info()这个函数,运行完就会释放内存
def info():
xxxxxx
p = person() # 这里只引用了info(),并没有调用,所以info没有运行,此时person()这个函数还是占着内存
p() # 这样就运行了info()这个函数,运行完就会释放内存
案例
>>内部函数的参数为: 10
>>30
>>30
函数引用
定义一个函数可以理解为:
定义了一个全部变量,变量名就是函数名(test)
这个test变量指向一个代码块,就是函数
就是说test保存了一个代码块的地址,即引用
定义了一个全部变量,变量名就是函数名(test)
这个test变量指向一个代码块,就是函数
就是说test保存了一个代码块的地址,即引用
>>1
>>2
>>True None None
>>True
>>2217856965072
>>140714178485464
>>2
>>True None None
>>True
>>2217856965072
>>140714178485464
None
使用闭包修改函数中的变量nonlocal
>>6
>>7
>>51
>>52
>>7
>>51
>>52
装饰器(依赖闭包)
概念
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
简单来讲:装饰器的作用就是为已经存在的函数或者对象添加额外的功能。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
简单来讲:装饰器的作用就是为已经存在的函数或者对象添加额外的功能。
例
初体验(现在不这么写)
>>[DEBUG]: enter say_hello()
>>hello
>>hello
这段代码的运行流程
1.将say_hello这个函数的引用,传递给debug函数(引用:给内存地址,不运行)
2.预读wrapper代码。预读开始
3.发现wrapper函数的返回值是say_hello函数的调用
4.返回wrapper函数的引用。预读结束
5.执行debug(),并传递一个say_hello的函数引用。开始运行
6.debug函数返回的是一个内部函数的引用
7.sayHello(),调用内部函数wrapper
print(f'********')
return func(),就是say_hello()
print(‘hello’)
上面的debug函数其实已经是一个装饰器了,它对原函数做了包装并返回了另外一个函数,额外添加了一些功能。
因为这样写实在不太优雅,在后面版本的Python中支持了@语法糖。
在不修改say_hello函数原代码的基础上,加一个debug功能。
因为这样写实在不太优雅,在后面版本的Python中支持了@语法糖。
在不修改say_hello函数原代码的基础上,加一个debug功能。
效果一样,这是最简单的装饰器,被装饰函数无法传参
流程
1.say_hello()处,@debug,运行debug
2.将@debug下的函数传给func
3.预读wrapper,返回wrapper的引用
4.say_hello加(),实际上就是调用wrapper函数。>>打印[DEBUG]这段话
5.wrapper返回func(),就是say_hello()。>>打印hello
被装饰函数可以传参
>>[DEBUG]: enter say()
>>hello! lucas
>>hello! lucas
万能装饰器(被装饰函数可以有多个参数)
终极装饰器(带参数的装饰器)
>>info: enter function say()
>>hello lucas
>>hello lucas
类装饰器
装饰器要求接收一个callable对象,并返回一个callable对象。
所以类装饰器中,__init__接收函数,重载__call__()并返回一个函数
一个装饰器可以装饰多个函数
一个函数可以有多个装饰器(很少用)
所以类装饰器中,__init__接收函数,重载__call__()并返回一个函数
一个装饰器可以装饰多个函数
一个函数可以有多个装饰器(很少用)
简单的类装饰器
带参数的类装饰器
>>INFO: enter function say()
>>say lucas
>>INFO: enter function say()
>>say lll
>>None
>>say lucas
>>INFO: enter function say()
>>say lll
>>None
元类
开发中用不到,用于阅读源代码
类的本质是个对象,
所以可以对它做一下操作
将它赋值给一个变量
拷贝它
为它增加属性
将它作为函数参数进行传递
代码解释
创建一个类
类是可以动态创建的
type
所有类都继承于object,所有类都是由type创建。
object也是由type创建的,type也是由type创建
object也是由type创建的,type也是由type创建
实例对象由类对象创建,所以type(实例对象),出来的是对应的类
而类对象是由type创建,所以type(类对象),出来的是type。
object也是类,所有类都继承于object,但其创建者是type
而类对象是由type创建,所以type(类对象),出来的是type。
object也是类,所有类都继承于object,但其创建者是type
使用type创建一个类
type函数的第二种用法(自己写函数不要让一个函数有两种完全不同的功能)
例
定义一个父类
定义一堆方法
将方法和父类放进子类中去
实例化后检查子类功能
>>住在深圳的lucas同学
>>lucas 深圳
>>这是一个静态方法
>>这是类方法 深圳
>>lucas 深圳
>>这是一个静态方法
>>这是类方法 深圳
元类本身的探究
元类创建类,类创建实例对象
函数type实际上是一个元类。type是python在背后用来创建所有类的元类。
str是用来创建字符串对象的类
int是用来创建整数对象的类
type是用来创建类对象的类
可以通过__class__属性来看到这一点
str是用来创建字符串对象的类
int是用来创建整数对象的类
type是用来创建类对象的类
可以通过__class__属性来看到这一点
__metaclass__
class Foo(object, metaclass=something):
# __metaclass__ = something, python2这么写
# 这个方法不用加def
# __metaclass__ = something, python2这么写
# 这个方法不用加def
自定义类
元类的主要目的是为了创建类时能够自动地改变类
例
异常处理
例,什么是异常
一个简单的登录系统
输入两个整数算商
try:
n1 = int(input('输入一个整数:'))
n2 = int(input('输入另一个整数:'))
res = n1/n2
# except ZeroDivisionError:
# print('除数不能为0哦')
# except ValueError:
# print('懂什么叫整数吗')
except BaseException as B:
print('出错了,请学会自己看报错:', B)
else:
print('结果为:', res)
finally:
print('-----------------')
print('感谢使用,本程序结束')
n1 = int(input('输入一个整数:'))
n2 = int(input('输入另一个整数:'))
res = n1/n2
# except ZeroDivisionError:
# print('除数不能为0哦')
# except ValueError:
# print('懂什么叫整数吗')
except BaseException as B:
print('出错了,请学会自己看报错:', B)
else:
print('结果为:', res)
finally:
print('-----------------')
print('感谢使用,本程序结束')
处理异常
try--except
try正常运行,出对应异常走except
多个异常
try--except--except(多个异常)
只执行一个分支
except(NameError, TypeError):
多个异常一般这么写
多个异常一般这么写
except后面跟一个元组
try--except--else
用的不多
用的不多
try内没有异常走else
try--except--else--finally
报不报错都要跑
捕获异常对象(异常本身信息)
as e
全捕捉
用Exception
不写默认Exception
自定义异常(用的不多)
例1
自定义的异常要继承Exception
例2
先定义一个异常类
在函数中主动抛出异常
调用函数
通过异常捕获获得以下字符串里面的字母字符
str_1='d52a733i2327ha244i982d23s553b245'
抛出异常
raise
不加as e
打印出自定义信息
一般不这么用,在except下面加raise
一般使用场景
网络请求
文件读写
常见异常类型
BaseException
所有异常的基类
https://docs.python.org/zh-cn/3.9/library/exceptions.html#exception-hierarchy
Exception
常见异常的基类(父类)
不知道会有什么异常就用这个
ZeroDivisionError
除(or取模)0,所有数据类型
IndexError
序列中没索引
KeyError
映射中没这个键
NameError
未声明/初始化对象(没有属性)
SyntaxError
语法错误
ValueError
传入无效参数
traceback模块
pycharm程序调试
debug shift+F9
文件操作
打开文件
内置函数open
open(file_name [, access_mode][, buffering])
file_name 变量:是一个包含要访问的文件名称的字符串值。
access_mode 变量:指打开文件的模式,对应有只读、写入、追加等。
access_mode变量值不是必需的(不带access_mode变量时,要求file_name存在,否则报异常),默认的文件访问模式为只读(r)。
access_mode变量值不是必需的(不带access_mode变量时,要求file_name存在,否则报异常),默认的文件访问模式为只读(r)。
'r'
- 读取 - 默认值。只能读取,如果文件不存在则报错。
'a'
- 追加 - 在原有内容基础上追加内容,在末尾写入,如果不存在则创建该文件。
'w'
- 写入 - 只能写入,如果文件不存在则创建该文件。
‘w+’
可读可写
'x'
- 创建 - 创建指定的文件,如果文件存在则返回错误。
't'
- 文本 - 默认值。文本模式。
'b'
- 二进制 - 二进制模式(例如图像)。
'rb'
二进制格式打开一个文件,只读
'wb'
同上,只写
'ab'
同上,追加
'wb+'
同上,读写
注意:尽量一次只用一种模式,+模式好像不太好用
buffering:(一般很少用)
如果buffering的值被设为0,就不会有寄存;
如果buffering的值取1,访问文件时就会寄存行;
如果将buffering的值设为大于1的整数,表示这就是寄存区的缓冲大小;
如果取负值,寄存区的缓冲大小就是系统默认的值。
如果buffering的值被设为0,就不会有寄存;
如果buffering的值取1,访问文件时就会寄存行;
如果将buffering的值设为大于1的整数,表示这就是寄存区的缓冲大小;
如果取负值,寄存区的缓冲大小就是系统默认的值。
路径
绝对路径
从根文件夹开始
E:/zoom/palegechong/图灵/基础语法/文件操作/文档/test.txt
相对路径
相对于当前工作目录的路径
./文档/test.txt
例
encoding='utf-8',设置编码
基本文件操作
read()
write()
readline()
读一行
readlines()
放进列表,每行一个元素
writelines()
文件流操作
如果对文件进行了读写之后,要关闭文件流(close())
因为文件读写需要使用计算机资源
如果不关容易程序异常,还占系统资源
因为文件读写需要使用计算机资源
如果不关容易程序异常,还占系统资源
with open as f:
with open可以自动调用close
重命名
os模块
os.rename('原文件名', '新文件名')
文件名这里写路径,不论是绝对路径还是相对路径
删除
os模块
也是填路径
迭代读取
普通版
fileinput模块
fileinput读完一行释放一行内存
StringIO函数
序列化/反序列化
JSON
前端的字典
json模块
0 条评论
下一页