python 深入记录入门基础

本篇文章主要记录python 3所有基础入门知识点,从注释、运算符到函数迭代及异常处理

文章中的各项知识点都是在学习过程中通过查阅资料、借鉴、理解所归纳的

一来作为自己学习python 3基础的笔记汇总,二来也方便刚接触python的朋友作为借鉴参考

目录

数据类型

Number(数字)

数学函数

随机数函数

三角函数

数学常量

String(字符串)

格式化

语法一

语法二

语法三

格式化符号

list(列表)

创建列表

访问元素

添加元素

删除元素

list计算

列表去重

Tuple(元组)

创建元组

访问元组

添加删除元组

元组计算

元素与列表的对比

dictionary(字典)

创建字典

访问字典​​​​​​​

修改字典

删除字典

字典去重

字典内置函数和方法

set(集合)

访问集合

添加集合

删除集合

集合函数和方法

数据类型创建对比

数据类型修改对比

注释

运算符

算术运算符

比较运算符

逻辑运算符

赋值运算符

成员运算符

位运算符

运算符优先级

变量和赋值

语法

标识符命名规则

命名规则

条件控制

if 语句

if - else 语句

if - elif - else 语句

嵌套if 语句

assert 关键词

循环语句

for语句

while语句

pass关键词

推导式

列表推导式

元组推导式

字典推导式

集合推导式

错误和异常

try-except语句

捕获指定异常类型

捕获多个指定异常

捕获所有异常

异常的捕获信息

try-except-else语句

try-except-finally语句

raise语句

自定义异常

python标准异常总结

python标准警告总结

函数

函数的定义

函数的调用

参数传递

参数类型

形参和实参

必需参数

关键字参数

默认参数

不定长参数

参数定义顺序

变量作用域

修改作用域

作用域函数

匿名函数

迭代器

创建迭代器

Stoplteraion

生成器

闭包

装饰器

装饰器原理

functools.wraps

带参数的装饰器

面向对象

类的定义

构造方法

self(类的实例)

类变量与实例变量

继承

多态

私有属性

私有方法

静态方法

类方法

普通方法、静态方法和类方法的区别

相关内置函数

魔法方法

__new__(cls,[...])

__init__()

__del__()

类的表示

属性访问

比较运算符

算术运算符

反算术运算符

增量赋值运算符

一元运算符

描述符

容器类操作

可调用对象

序列化

下划线分类

模块

模块的定义

包的定义

import语句

from xxx import xxx语句

from xxx import*语句

from xxx.xxx import xxx

别名

模块搜索路径

文件

文件打开

​编辑

文件读取

文件写入

文件关闭

with...as...

文件相关函数

OS

PEP8规范

缩进

行的最大长度

空行

导入

注释

字符串

命名约定

结语​​​​​​​


数据类型

python内置的数据类型分为可变类型和不可变类型

可变类型:List(列表)、Set(集合)、Dictionary(字典);

不可变类型:Number(数字)、String(字符串)、Tuple(元组)


Number(数字)

数字又可以分为四种数字类型,分别是:

int(整数)                在python 3 中,只有一种整数类型int,表示为长整型;

float(浮点数)         浮点数则是带有小数点的整数;

bool(布尔值)         而布尔值只有Ture(真、是)和Flase(假、否)两个值;

complex(复数)      复数则以 j或J 作为符号代表

具体展示如下:

a = 3
b = 6.6
c = True
d = 4+3j
print(type(a),type(b),type(c),type(d))    # 这行意思是返回a b c d四个对象的数据类型

# 只需要输入上面代码即可,下面是输入代码后,系统返回的提示
<class 'int'> <class 'float'> <class 'bool'> <class 'complex'>

可以看到系统返回a b c d 四个对象所对应的数据类型,自己也可以通过修改值来尝试一下

在python 3 中,bool(布尔值)是int的子类,True和False可以和数字作加减运算,True等于1,False等于0,

#!/usr/bin/python3

# python 的等于用双等于号表示: ==
print(True == 1)        # 判断条件是否成立,若为真,则返回True
print(False == 0)       # 判断条件是否成立,若为真,则返回True
print(True + 1)         # 计算True是否代表数字1
print(False + 0)        # 计算False是否代表数字0


# 返回结果
True
True
2
0

数学函数

import math

# 返回数字的绝对值
abs()
# 返回给定参数的最大值
max()
# 返回给定参数的最小值
min()
# x**y 运算后的值
pow()
# 四舍五入
round()

# 返回数字的平方根
math.sqrt()
# 返回数字的上入整数
math.ceil()
# 返回 e 的 x 次幂 (ex)
math.exp()
# 返回数字的绝对值
math.fabs()
# 返回数字的下舍整数
math.floor()
# 返回对数的值
math.log()
# 以10为底数,返回对数的值
math.log10()
# 返回 x 的整数部分与小数部分
math.modf()	

随机数函数

import random

# 从序列的元素中随机挑选一个元素
random.choice()
# 从指定范围内,按指定基数递增的集合中获取一个随机数,基数默认值为 1
random.randrange()
# 随机生成下一个实数,它在 [0,1) 范围内。
random.random()	
# 随机生成下一个实数,它在 [x,y] 范围内
random.uniform()
# 改变随机数生成器的种子
random.seed()	
# 将序列的所有元素随机排序
random.shuffle()	

三角函数

import math

# 返回变量的反余弦弧度值
math.acos()	
# 返回变量的反正弦弧度值
math.asin()
# 返回变量的反正切弧度值
math.atan()	
# 返回给定的变量及 Y 坐标值的反正切值
math.atan2()
# 返回变量的弧度的余弦值
math.cos()	
# 返回欧几里德范数 sqrt (x*x + y*y)
math.hypot()
# 返回的变量弧度的正弦值
math.sin()	
# 返回变量弧度的正切值
math.tan()	
# 将弧度转换为角度
math.degrees()	
# 将角度转换为弧度
math.radians()	

数学常量

常量描述
pi数学常量 pi(圆周率,一般以 π 来表示)
e数学常量 e,e 即自然常数(自然常数)
空值空值是Python里一个特殊的值,用None表示,None不能理解为0,因为0是有意义的,而None是一个特殊的空值。


String(字符串)

在python 3 中,字符串用单引号 ' ' 或者双引号 " " 括起来

#!/usr/bin/python3

str = 'inganxu'
print(str)

str = "CSDN-2021.11.16"
print(str)

str = "\\"
print(str,r'str')


# 返回结果
inganxu
CSDN-2021.11.16
\ str
转义字符
表达式描述
换行\n
制表符\t
结束符print("内容",end="\n")
不转义r""
空值\000

格式化

python支持格式化字符串的输出

语法一

%(格式化符号)%(变量)

# 语法一
f = 'Hello,%s Hello,%s'%('python','world')
f1 = 'Hello,%(var1)s Hello,%(var2)s'%{'var1':'python','var2':'world'}

print(f)
print(f1)

语法二

format()函数

# 语法二
f2 = 'Hello,{} Hello,{}'.format('python','world')

print(f2)

语法三

f"{var1}{var2}"

# 语法三
a = 'python'
b = 'world'
f3 = f'Hello,{a} Hello,{b}'

print(f3)

格式化符号

符号描述
%c格式化字符及其 ASCII 码
%s格式化字符串
%d格式化整数
%u格式化无符号整型
%b格式化无符号二进制数
%o格式化无符号八进制数
%i格式化无符号十进制数
%x格式化无符号十六进制数
%X格式化无符号十六进制数(大写)
%f格式化浮点数字,可指定小数点后的精度
%e用科学计数法格式化浮点数
%E作用同 % e,用科学计数法格式化浮点数
%g% f 和 % e 的简写
%G% F 和 % E 的简写

参考文章:python字符串格式化深入详解(四种方法)


list(列表)

列表是一种可变的数据类型,其元素内容和列表的长度均可动态修改

语法:列表名 = [元素1,元素2,元素3]

创建列表

列表中的元素可同时存在多种数据类型,并可以嵌套的形式存在

# 创建空列表,变量名 = []
a = []

# 创建特定元素的列表
a = ['A','B','C']
print(a)                # ['A', 'B', 'C']

# 列表元素可同时存在多种数据类型
a = ['A',999,[1,2,3],(1,2,3),{'A':123}]     #['A', 999, [1, 2, 3], (1, 2, 3), {'A': 123}]
print(a)

访问元素

列表访问元素主要以两种形式:索引和切片

序列中的每个元素都有对应的位置值,称之为索引,正向索引从0开始递增算起,逆向索引从-1开始递减算起

str = 'abc'             # 获取字符串中的第一个元素
list = [1,2,3,4,]       # 获取列表中的第一个元素
set = (1,2,3,4)         # 获取集合中的第一个元素
dict = {'a':[1,2,3]}    # 获取字典中的第一个元素

print(str[0])           # a
print(list[0])          # 1
print(set[0])           # 1
print(dict['a'][0])     # 1
以list = [“a”,“b”,“c”,“d”,“e”,“f”,“g”,“h”]为例
列表中的元素其索引值备注
a0第一个元素
b1第二个元素
.........
g6,-2第六个元素,倒数第二个元素
h7,-1第七个元素,倒数第一个元素

区域索引则以“:”表示,称之为切片 、

切片表达式 [开始,结束,步长]

list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']

# 列表第一项
print(list[0])                  # a

# 第一项到第八项
print(list[0:9])                # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

# 第一项到第十一项,间隔三项
print(list[0:12:3])             # ['a', 'd', 'g', 'j']

# 第三项到最后一项
print(list[3:])                 # ['d', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']

# 第三项到最后一项,间隔四项
print(list[3::4])               # ['d', 'h', 'l']

# 最后一项
print(list[-1])                 # l

# 第一项到倒数第二项
print(list[:-1])                # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']

# 倒序
print(list[::-1])               # ['l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']

注意:

列表元素可以等于列表自身,但会陷入无限循环中

a = [1,2,3]
a[1] = a
print(a)        # [1, [...], 3]

首先生成列表对象[1,2,3]和变量a,变量a指向列表

再将列表对象的第二个元素指向变量a所引用的列表对象本身,形成无限引用自己

参考文章:Python中[-1]、[:-1]、[::-1]、[n::-1]、[:,:,0]、[…,0]、[…,::-1] 的理解_Dunkle.T的博客-CSDN博客

添加元素

列表可自由修改长度,无需预先声明定义其长度

append:一次添加1个元素

insert:在指定位置添加元素

extend:一次添加多个元素(等同于 加法运算符)

注意:

extend 方法实现批量添加元素时未创建一个新的列表,而是直接添加在原列表中。

而 b=a+list对象实际是创建一个新的列表对象。

但是,a+=一个列表对象,+= 操作符则就会自动调用 extend 方法进行合并运算。

删除元素

remove:直接删除元素,若被删除元素在列表中重复出现多次,则只删除一次,并返回列表

pop:删除指定位置的元素(默认最后一个),并返回删除值

del:删除指定位置的元素,并不再使用(默认最后一个),不返回删除值

注意:

del为python语句,不是列表方法,无法通过list来调用

for循环删除时,需注意索引的变动,列表的长度变化的同时,其索引值也会跟着变化

a = [1, 2, 3, 4]
for index, x in enumerate(a):
    print("索引是{},去删除的值是{},列表的长度是{}".format(index, x, len(a)))
    a.remove(x)
    print("=" * 20)
print(a)

结果如下:
 
索引是0,去删除的值是1,列表的长度是4
====================
索引是1,去删除的值是3,列表的长度是3
====================
[2, 4]

list计算

列表无法直接参与加减运算,但可使用 * 进行元素复制

print([1,2,3,4]*2)      # [1, 2, 3, 4, 1, 2, 3, 4]

列表元素使用切片的方式可参与运算

a = [1,2,[3,4]]
print(a[0] + 1)     # 2
print(a[1] - 2)     # 0
print(a[2] * 2)     # [3, 4, 3, 4]

注意:嵌套列表乘法得到的每个项都是引用

a = [['1','2'] for i in range(2)]
b = [['1','2']]*2
a[0][1] = '3'
b[0][0] = '4'

print(id(a[0]) == id(a[1]))     # False
print(id(b[0]) == id(b[1]))     # True
print(a)                        # [['1', '3'], ['1', '2']]
print(b)                        # [['4', '2'], ['4', '2']]

列表去重

a = [1,2,3,1,2,4,6]
b = list(set(a))
print(b)            # [1, 2, 3, 4, 6]

参考文章:4300 字Python列表使用总结,用心!


Tuple(元组)

元组是一个不可修改元素的数据类型,但引用对象内容可修改,可存储任意类型数据

语法:元组名 = (元素1,元素2,元素3)

创建元组

# 创建空元组
t = ()
print(t)

a = [4,5,6]
t = (123,[1,2,3],1.23,{'T':123},a)
print(t)                            # (123, [1, 2, 3], 1.23, {'T': 123}, [4, 5, 6])

a = [7,8,9]
t = (123,[1,2,3],1.23,{'T':123},a)
print(t)                            # (123, [1, 2, 3], 1.23, {'T': 123}, [7, 8, 9])

注意:

当元组元素只有一个的时候,需增加逗号区分,否则会默认为字符串

t = ('str')
print(type(t))      # <class 'str'>

t = ('tuple',)
print(type(t))      # <class 'tuple'>

访问元组

元组和列表一样可以通过索引和切片的方式访问

t = (123,[1,2,3],1.23,{'T':123})

print(t[1:])            # ([1, 2, 3], 1.23, {'T': 123})
print(t[::-1])          # ({'T': 123}, 1.23, [1, 2, 3], 123)

添加删除元组

因为元组中的元素是不可变的,因此当需要添加或删除元组中的元素时,需使用切片的方式进行

t = (123,[1,2,3])

# 添加元素
t = t[0:1] + ('123',) + t[1:]
print(t)        # (123, '123', [1, 2, 3])

# 删除元素
t = t[:2]
print(t)        # (123, '123')

注意:所谓元组的不可变指的是元组所指向的内存中的内容不可变

参考文章:python 元组(tuple)和列表(list)区别_一起学习-CSDN博客_tuple

元组计算

 元组无法直接参与加减运算,但可使用 * 进行元素复制

t2 = t * 2              # (1, 2, 3, 1, 2, 3)
print(t2)

元组元素使用切片的方式可参与运算

t = (1,2,3)
print(t[1] + 1)         # 3
print(t + (4,5,6))      # (1, 2, 3, 4, 5, 6)

元素与列表的对比

元组使用小括号(),列表使用方括号[]

元组元素无法直接修改,列表元素可直接修改

列表转换为元组使用tuple()函数

元组转换为列表使用list()函数

参考文章:python:元组【全用法】_dddxxy的博客-CSDN博客_python元组


dictionary(字典)

字典是一种可变的数据结构,可存储任意类型的对象,如:字符串、数字、列表、元组等

字典由“键”和“值”两部分组成,也就是key和value,中间用冒号分隔

语法:字典名 = {键1:值1,键2:值2}

创建字典

# 创建空字典
d = {}
print(type(d))          # <class 'dict'>

# 创建指定内容字典
d1 = {'a':1,'b':[1,2],'c':(1,2)}
print(d1)               # {'a': 1, 'b': [1, 2], 'c': (1, 2)}

注意:

字典中的键可以用数字、字符串、元组充当,但不能用列表,而值可以是任何python对象

字典中的键是唯一的,在字典中创建两个相同的键,前一个键会被覆盖掉

访问字典

字典无法使用切片的方式访问

d1 = {'a':1,'b':[1,2],'c':(1,2)}
print(d1['a'])                      # 1
print(d1[-1])                       # 报错

注意:

访问的键不存在时,会直接报错

修改字典

d1 = {'a':1,'b':[1,2],'c':(1,2)}
d1['a'] = 1.2
d1['b'] = [2,3]

# 修改字典中的值
print(d1['a'])                  # 1.2
print(d1['b'])                  # [2, 3]

# 添加新的键和值
d1['d'] = 'python'
print(d1['d'])                  # python
print(d1)                       # {'a': 1.2, 'b': [2, 3], 'c': (1, 2), 'd': 'python'}

删除字典

del 字典名[键名]

d = {'a':1,'b':[1,2],'c':(1,2)}

del d['a']
print(d)            # {'b': [1, 2], 'c': (1, 2)}

字典名.clear()

d = {'a':1,'b':[1,2],'c':(1,2)}

d.clear()
print(d)            # {}

del 字典名

d = {'a':1,'b':[1,2],'c':(1,2)}

del d
print(d)            # 报错,字典d已不存在

字典去重

a = [1,2,3,1,2,4,6]
b = {}
b = list(b.fromkeys(a))
print(b)            # [1,2,3,4,6]

字典内置函数和方法

# 字典内置函数

# 计算字典元素个数
len(dict)

# 输出字典,可以打印的字符串表示
str(dict)

# 返回判定变量的类型
type(dict)

# 字典内置方法

# 清除字典中所有的元素,得到的是空的字典,返回None
dict.clear()

# 返回一个字典的浅拷贝副本
dict.copy()

# 创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值
dict.fromkeys()

# 返回指定键的值,如果键不在字典中返回 default 设置的默认值
dict.get()

# 以列表返回一个视图对象
dict.items()

# 以列表返回一个字典所有的键
dict.keys()

# 以列表返回一个字典所有的值
dict.values()

# 删除特定的键
dict.pop()

# 删除指定键值对,默认删除最后一对键和值
dict.popitem()

# 键不存在则返回默认值
dict.setdefault()

# 将参数更新到dict中,无返回值
dict.update()

参考文章:Python字典的11个方法超级详解


set(集合)

集合是一种可变的数据结构,存储元素不可重复,是无序的数据类型

集合用大括号表示,中间用逗号分隔

语法:集合名 = {元素1,元素2,元素3}

访问集合

# 创建空集合
set = {}

# 集合是无序的
set = {'i','love','python','and','world'}
print(set)        # {'i', 'world', 'python', 'love', 'and'}

注意:

集合中的元素只能是不可变的值,如字符串、元组、数字等

若试图添加列表(list)字典(dict)会报错

set = {[1,2,3]}
print(set)          # TypeError: unhashable type: 'list'

添加集合

add():添加一个元素

update():添加多个元素

set = {'i','love','python','and','world'}
# 添加一个元素
set.add(1)

# 添加多个元素
set.update([2,3,4])
print(set)

删除集合

remove():删除指定一个元素,若元素不存在,则报错

discard():删除指定一个元素,若元素不存在,则返回集合

pop():随机删除一个元素

set = {'i','love','python','and','world'}

# 随机删除一个元素
set.pop()
print(set)      # {'world', 'and', 'i', 'love'}

# 删除指定一个元素,若元素不存在,则返回集合
set.discard('python')
print(set)      # {'world', 'and', 'i', 'love'}

# 删除指定一个元素,若元素不存在,则报错
set.remove('python')
print(set)      # KeyError: 'python'

集合函数和方法

# 集合内置函数

# 计算集合元素个数
len(set)

# 输出集合,可以打印的字符串表示
str(set)

# 返回判定变量的类型
type(set)
# 集合内置方法

# 为集合添加元素
set.add()	

# 移除集合中的所有元素
set.clear()	

# 拷贝一个集合
set.copy()	

# 返回多个集合的差集
set.difference()	

# 移除集合中的元素,该元素在指定的集合也存在
set.difference_update()	

# 删除集合中指定的元素
set.discard()	

# 返回集合的交集
set.intersection()	

# 返回集合的交集
set.intersection_update()	

# 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False
set.isdisjoint()	

# 判断指定集合是否为该方法参数集合的子集
set.issubset()	

# 判断该方法的参数集合是否为指定集合的子集
set.issuperset()	

# 随机移除元素
set.pop()	

# 移除指定元素
set.remove()	

# 返回两个集合中不重复的元素集合
set.symmetric_difference()	

# 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中
set.symmetric_difference_update()	

# 返回两个集合的并集
set.union()	

# 给集合添加元素
set.update()	

参考文章:

Python 集合与集合运算_李玺-CSDN博客_python 集合运算


数据类型创建对比

数据类型语法
列表列表名 = [元素1元素2元素3]
元组元组名 = (元素1元素2元素3)
字典字典名 = {键1值1键2值2}
集合集合名 = {元素1元素2元素3}


数据类型修改对比

数据类型创建描述删除描述
列表list.append()一次添加1个元素list.remove()直接删除元素,若被删除元素在列表中重复出现多次,则只删除一次,并返回列表
list.inser()在指定位置添加元素list.pop()删除指定位置的元素(默认最后一个),并返回删除值
list.extend()一次添加多个元素(等同于 加法运算符)list.del()删除指定位置的元素,并不再使用(默认最后一个),不返回删除值
元组tuple[:n] + ('t',) + tuple[n:]切片方式添加元素tutple[:n+1] + tutple[n+1:]切片方式删除元素
字典dict['key'] = value赋值方式添加元素del dict['key']删除字典中的键
del dict删除字典
集合set.add()添加一个元素set.remove()删除指定一个元素,若元素不存在,则报错
set.update()添加多个元素set.discard()删除指定一个元素,若元素不存在,则返回集合
set.pop()随机删除一个元素


注释

注释格式汇总
分类格式格式说明示例
整行注释#在注释内容前增加#即可注释整行内容# i love python
区域注释

""

"""

6个双引号,在三引号之间的所有内容都被注释

"""

i

love

python

"""

区域注释

'''

'''

6个单引号,在三引号之间的所有内容都被注释

'''

i

love

python

'''


运算符

算术运算符

操作符名称示例
+3+4
-3-4
*3*4
/3/4
//地板除3//4
%取余3%4
**3**4
print(3 + 4)  # 7
print(3 - 4)  # -1
print(3 * 4)  # 12
print(3 / 4)  # 0.75
print(3 // 4)  # 0
print(3 % 4)  # 3
print(3 ** 4)  # 81

注意:解决python中float进行算术运算时,精度丢失问题

使用python中的Decimal模块解决

导入Decimal模块 from decimal import Decimal

使用 变量 = Decimal("float") ,float值必须使用双引号

比较运算符

操作符名称示例
>大于2 > 1
>=大于等于2 >= 4
<小于1 < 2
<=小于等于5 <= 2
==等于3 == 4
!=不等于3 != 5
print(2 > 1)  # True
print(2 >= 4)  # False
print(1 < 2)  # True
print(5 <= 2)  # False
print(3 == 4)  # False
print(3 != 5)  # True

注意: “=” 在python中是赋值的意思,而“==”才是等于的意思

逻辑运算符

操作符名称示例
and(3 > 2)and(3 < 5)
or(1 > 3)or(9 < 2)
notnot(2 >1)
print((3 > 2) and (3 < 5))  # True
print((1 > 3) or (9 < 2))  # False
print(not (2 > 1))  # False

a = 0 or 1 and True

print(a)        # True

赋值运算符

操作符名称示例
=赋值运算符a = b
+=加法赋值运算符a += b
-=减法赋值运算符a -= b
*=乘法赋值运算符a *= b
/=除法赋值运算符a /= b
%=取模赋值运算符a %= b
**=幂赋值运算符a **= b
//=地板除赋值运算符a //= b
:=海象运算法

while if(n:=len(a))  != 0

        print(n)

多个变量同时赋值

a,b,c = 1,2,3
print(a,b,c)        # 1 2 3

多个变量赋相同值

a=b=c=3
print(a,b,c)        # 3 3 3

成员运算符

操作符名称示例
in存在5 in [1,2,3]
not in不存在5 not in [1,2,3]
is'a' is 'ab'
is not不是'a' is not 'ab'
print(5 in [1,2,3])         # False
print(5 not in [1,2,3])     # True
print('a' is 'ab')          # False
print('a' is not 'ab')      # True

位运算符

暂空

运算符优先级

运算符描述
**指数 (最高优先级)
~ + -按位翻转,一元加号和减号 (最后两个的方法名为 +@ 和 -@)
* / % //乘,除,求余数和取整除
+ -加法减法
>> <<右移,左移运算符
&位 'AND'
^ |位运算符
<= < > >=比较运算符
== !=等于运算符
= %= /= //= -= += *= **=赋值运算符
is is not身份运算符
in not in成员运算符
not and or逻辑运算符

注意:

and 比 or 有更高的优先级

==判断两个对象的值是否相等

is判断两个变量引用的对象是否相同


变量和赋值

语法

变量名 = 变量值

变量名要符合标识符命名规则

标识符命名规则

由数字、字母、下划线组成

不能以数字开头

严格区分大小写

不能使用内置关键字

(Flase  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)

命名规则

驼峰命名法

大驼峰(模块和常量):既每个单词的首字母都大写,并用下划线分割单词

小驼峰(类):第二个(含)以后的单词首字母大写

下划线命名法

表达式含义备注
_用于临时变量

单下划线在REPL中关联的是上一次计算的非None结果

for循环中_可作为没意义的变量

元组拆包中的_表示略过该内容

可用于数字的分割,这在数字比较长的时候常用

var_用于解决命名冲突问题代码中遇到python的关键字时,可在变量名后增加一个下划线
_var内部变量(函数、方法、属性)

解释器不作访问控制

导入时,不导入带类变量

__var私有变量
__var__魔法方法

普遍共识:

  • 用于循环的 i/j/k
  • 用于计数的 count
  • 表示指针的 p/ptr
  • 表示缓冲区的 buf/buffer
  • 表示总和的 sum

参考文章:Python对下划线有多偏爱

条件控制

if 语句

if 条件判断 :

        若条件满足,则执行该内容(注意缩进)

age = 0
if age < 18:
    print('已成年')                          # 已成年

if - else 语句

if 条件判断 :

        若条件满足,则执行该内容(注意缩进)

否则:

        执行该内容

age = 0
if age > 18:
    print('已成年')                          # 未成年
else:
    print('未成年')

rep = '已成年' if age > 18 else '未成年'
print(rep)                                  # 未成年

if - elif - else 语句

if 条件判断 :

        若条件满足,则执行该内容(注意缩进)

elif 条件判断:

        若不满足if条件,但满足elif条件,则执行该内容

else:

        若都不满足,则执行该内容

age = 24
if age > 30:
    print('中年人')
elif age > 18:
    print('青年人')            # 青年人
else:
    print('未成年')

嵌套if 语句

if 条件判断 :

        if 条件判断 :

                若条件满足,则执行该内容(注意缩进)

age = 25
if age >24:
    if age >60:
        print('中年人')
    elif age >30:
        print('中年人')
    else:
        print('青年人')
elif age >18:
    print('成年人')
else:
    print('未成年')

assert 关键词

这个关键词称之为“断言”,当关键字的条件不成立时,程序自动崩溃并抛出AssertionError的异常

list = [1]
list.pop(0)
assert len(list) > 0

# AssertionError

注意:

编写条件控制语句时,需注意语句格式,尤其是缩进和冒号的使用


循环语句

python中的循环语句有for和while

for语句

python的for循环除了具备控制循环次数外,还能直接迭代容器中的元素

a = [1,[2,3],[4,5]]
for item in a:
    print(item)

while语句

while:若满足条件则会一直循环,直到不满足条件时退出

break:条件满足,依然退出循环

continue:跳过该次循环

a, b = 0, 0
for i in range(6):  # 循环6次
    b += 1
    print('i=',i, 'b=',b, 'a=',a)
    if i < 3:
        while b % 2 >0:  # 满足条件b为奇数时
            b += 1
            if b > 1 and b < 5:
                a += 1
                print('本次跳过')
                continue
            if b < 10:
                a += 1
                print('条件满足,但退出循环')
                break
        else:
            print('while条件不满足')
    elif i < 5:
        print('触发elif语句')
    elif i < 6:
        assert i > 6
    else:
        print('程序出错!')
  • 该例子用for循环嵌套if语句,if语句下面再嵌套while语句
  • 使用for循环,遍历6次
  • 条件控制引用了if-elif-else语句和断言关键词,在i处于不同范围时,触发不同条件
  • while循环则是利用条件判断来触发break和continue

pass关键词

pass关键词的意思是“不做任何事”,当语句不完整时,可使用pass关键词不执行该项代码块

for i in range(4):
    pass

while True :
    pass

推导式

列表推导式

[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]]

# 普通列表表达式
list1 = [x**2 for x in range(10)]

# if判断列表表达式
list2 = [x**2 for x in range(10) if x*2>3]

# 嵌套列表表达式
list3 = [(x,y) for x in [1,2] for y in [2,3] if x!=y]

print(list1)        # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(list2)        # [4, 9, 16, 25, 36, 49, 64, 81]
print(list3)        # [(1, 2), (1, 3), (2, 3)]

元组推导式

a = (x for x in range(10))
print(tuple(a))             # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

字典推导式

b = {i:i%2 == 0 for i in range(10) if i%3 == 0}
print(b)            # {0: True, 3: False, 6: True, 9: False}

集合推导式

c = {i for i in [1,2,3,4,5,5,6,4,3,2,1]}
print(c)                # {1, 2, 3, 4, 5, 6}

注意:推导式无法使用debug进行排错


错误和异常

异常就是运行期检测到的错误。计算机语言针对可能出现的错误定义了异常类型,某种错误引发对应的异常时,异常处理程序将被启动,从而恢复程序的正常运行。

try-except语句

捕获指定异常类型

try:

        可能发生错误的代码
except 异常类型:

        如果出现异常执行的代码

try:
    f = open('text.text')
    print(f.read())
    f.close()
except OSError:
    print('打开文件出错')

捕获多个指定异常

try:

        可能发生错误的代码
except 异常类型1:

        如果出现异常执行的代码

except 异常类型2:

        如果出现异常执行的代码

try:
    int("abc")
    s = 1 + '1'
    f = open('test.txt')
    print(f.read())
    f.close()
except OSError as error:
    print('打开文件出错\n原因是:' + str(error))
except TypeError as error:
    print('类型出错\n原因是:' + str(error))
except ValueError as error:
    print('数值出错\n原因是:' + str(error))

捕获所有异常

try:

        可能发生错误的代码
except Exception:

        如果出现异常执行的代码

a = 18
b = 0
try:
    c = a / b
    print(c)
except Exception as error:
    print('除数不能为0:' + str(error))

异常的捕获信息

try:

        可能发生错误的代码
except 异常类型 as error:

        如果出现异常执行的代码#error为异常的信息

try:
    f = open('test.txt')
    print(f.read())
    f.close()
except OSError as error:
    print('打开文件出错\n原因是:' + str(error))

try-except-else语句

try:

        可能发生错误的代码

except Exception [as reason]:

        如果出现异常执行的代码

else 

        如果无出现异常执行的代码

a = 18
b = 6
try:
    c = a / b
    print(c)
except Exception as error:
    print('除数不能为0:' + str(error))
else:
    print('程序执行成功')

try-except-finally语句

try:

        可能发生错误的代码

except :

        如果出现异常执行的代码

else :

        如果无出现异常执行的代码

finally:

        无论有无异常都会执行的代码

a = 18
b = 6
try:
    c = a / b
    print(c)
except Exception as error:
    print('除数不能为0:' + str(error))
else:
    print('程序执行成功')
finally:
    print('无论异常是否发生都会执行!!!')

raise语句

raise关键词的意思是抛出一个指定的异常

raise [exceptionName [(reason)]]

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')

参考文章:Python raise用法(超级详细,无师自通)_曾可爱harris的博客-CSDN博客_python中raise语句的作用

自定义异常

class DatabaseException(Exception):
    def __init__(self,err='数据库错误'):
        Exception.__init__(self,err)

class PreconditionsException(DatabaseException):
    def __init__(self,err='PreconditionsErr'):
        DatabaseException.__init__(self,err)

def testRaise():
    raise PreconditionsException()

try:
    testRaise()
except PreconditionsException as e:
    print (e)

注意:PreconditonsException 又是 DatabaseException 的子类。
所以如果,raise PreconditionException 的话,用两个异常类都可以捕捉。
但是,如果是 raise DatabaseException, 用 PreconditonsException 是捕捉不到的。
参考文章:python 自定义异常和异常捕捉_flyingshuai的专栏-CSDN博客_python自定义异常


python标准异常总结

  • BaseException:所有异常的 基类
  • Exception:常规异常的 基类
  • StandardError:所有的内建标准异常的基类
  • ArithmeticError:所有数值计算异常的基类
  • FloatingPointError:浮点计算异常
  • OverflowError:数值运算超出最大限制
  • ZeroDivisionError:除数为零
  • AssertionError:断言语句(assert)失败
  • AttributeError:尝试访问未知的对象属性
  • EOFError:没有内建输入,到达EOF标记
  • EnvironmentError:操作系统异常的基类
  • IOError:输入/输出操作失败
  • OSError:操作系统产生的异常(例如打开一个不存在的文件)
  • WindowsError:系统调用失败
  • ImportError:导入模块失败的时候
  • KeyboardInterrupt:用户中断执行
  • LookupError:无效数据查询的基类
  • IndexError:索引超出序列的范围
  • KeyError:字典中查找一个不存在的关键字
  • MemoryError:内存溢出(可通过删除对象释放内存)
  • NameError:尝试访问一个不存在的变量
  • UnboundLocalError:访问未初始化的本地变量
  • ReferenceError:弱引用试图访问已经垃圾回收了的对象
  • RuntimeError:一般的运行时异常
  • NotImplementedError:尚未实现的方法
  • SyntaxError:语法错误导致的异常
  • IndentationError:缩进错误导致的异常
  • TabError:Tab和空格混用
  • SystemError:一般的解释器系统异常
  • TypeError:不同类型间的无效操作
  • ValueError:传入无效的参数
  • UnicodeError:Unicode相关的异常
  • UnicodeDecodeError:Unicode解码时的异常
  • UnicodeEncodeError:Unicode编码错误导致的异常
  • UnicodeTranslateError:Unicode转换错误导致的异常

异常体系内部有层次关系,Python异常体系中的部分关系如下所示:

python标准警告总结

  • Warning:警告的基类
  • DeprecationWarning:关于被弃用的特征的警告
  • FutureWarning:关于构造将来语义会有改变的警告
  • UserWarning:用户代码生成的警告
  • PendingDeprecationWarning:关于特性将会被废弃的警告
  • RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
  • SyntaxWarning:可疑语法的警告
  • ImportWarning:用于在导入模块过程中触发的警告
  • UnicodeWarning:与Unicode相关的警告
  • BytesWarning:与字节或字节码相关的警告
  • ResourceWarning:与资源使用相关的警告

参考文章:Python1-天池实验室-实时在线的数据分析协作工具,享受免费计算资源


函数

函数的定义

def 函数名(参数):

        函数内容

        return [expression]

def f ():
    print('Hello,world!!!')


f()
# Hello,world!!!
  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串 — 用于存放函数说明。
  • 函数内容以冒号 : 起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。

函数的调用

函数可用过其他函数调用执行或直接从pyrthon命令提示符执行

# 定义函数
def f(str):
    print(str)
    return

# 调用函数
str = 'Hello,world!!!'
f(str)

参数传递

不可变类型:如整数、字符串、元组。传递的只是a的值,没有影响a对象本身,如果在函数内部修改a的值,则是新生产一个a的对象

def change(a):
    print(id(a))
    a = 10
    print(id(a))

a = 1
print(id(a))
change(a)

# 1986970806576
# 1986970806576
# 1986970806864

可更改类型:如列表、字典、集合。则是将a真正的传过去,修改后函数外部的a也会受影响

def changeme(a):
    print(id(a))
    a.add(10)
    print(id(a))

a = {1,}
print(id(a))
changeme(a)

# 1160702477472
# 1160702477472
# 1160702477472

参数类型

形参和实参

函数定义过程中,参数仅分为“形参”和“实参”

def MyFirstFunction(name):
    "函数定义过程中name是形参"
    # 因为Ta只是一个形式,表示占据一个参数位置
    print('传递进来的{0}叫做实参,因为Ta是具体的参数值!'.format(name))


MyFirstFunction('老马的程序人生')  
# 传递进来的老马的程序人生叫做实参,因为Ta是具体的参数值!

print(MyFirstFunction.__doc__)  
# 函数定义过程中name是形参

help(MyFirstFunction)
# Help on function MyFirstFunction in module __main__:
# MyFirstFunction(name)
#    函数定义过程中name是形参

而在函数调用过程中,参数可分为必需参数、关键字参数、默认参数、不定长参数

必需参数

必需参数须以正确的顺序传入函数,调用时的数量必须和声明时的一样

# 定义函数
def f(str):
    print(str)
    return

# 调用函数时,不加参数会报错
f()

# TypeError: f() missing 1 required positional argument: 'str'

关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值

# 定义函数
def f(str):
    print(str)
    return


# 关键词参数
f(str='Hello,world!!!')

# TypeError: f() missing 1 required positional argument: 'str'

默认参数

调用函数时,如果没有传递参数,则会使用函数定义的默认参数

默认参数一定要放在必需参数后面,否则会报错

# 定义函数
def f(a, b='python!!!'):
    print(a, b)
    return


# 使用关键词参数
f(a='Hello,', b='world!!!')  # Hello, world!!!
# 调用默认参数
f(a='Hello,')  # Hello, python!!!

不定长参数

调用时,不适用关键词参数的形式传参,但要注意按照函数定义时参数的顺序来

*args:接收所有按照必需参数方式传递进来的参数,是一个元组类型

**kw:接收所有按照关键字参数方式传递进来的参数,是一个字典类型

# 定义函数
def f(*args,**kw):
    print(args)
    print(kw)

# 调用不定长参数
f(10,20,c=10,d=20)

# (10, 20)
# {'c': 10, 'd': 20}

注意:

定义函数时,参数中星号*可以单独出现,但后面的参数必需用关键字参数的形式传入

# 定义函数
def f(a, b, *, c):
    print(a, b, c)


# 调用不定长参数
f(1, 2, c=3)  # 1 2 3

参数定义顺序

必需参数、默认参数、不定长参数、关键词参数

# 定义函数
def f(a,b=0,*c,d):
    print(a,b,c,d)
    
    
f(1,2,3,4,d=5)      # 1 2 (3, 4) 5

注意:

函数参数传递的是实际对象的内存地址。如果参数是引用类型的数据类型(列表、字典等),在函数内部修改后,就算没有把修改后的值返回回去,外面的值其实也已经发生了变化

def f(a):
    list.append(a)


list = [0, 2]
f(1)
print(list)  # [0, 2, 1]

参考文章:11个案例讲透 Python 函数参数


变量作用域

Python中,程序的变量并不是在哪个位置都可以访问,访问权限决定于这个变量是在哪里赋值的

local():定义在函数内部的变量拥有局部作用域,该变量称为局部变量

Enclosing():包含了非局部也非全局的变量,例如嵌套函数中的外层函数作用域

global():定义在函数外部的变量拥有全局作用域,该变量称为全局变量

Built-in():定义在python内置中的变量/关键字等

规则顺序:local->enclosing->global->built-in

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问

g_count = 0         # global作用域
def outer():
    o_count = 1     # enclosing作用域
    def inner():
        i_count = 2 # local作用域

python中只有模块(module)、类(class)以及函数(def、lambda)才会引入新的作用域

其他的代码块(如if/elif/else、try/except、for/while等)是不会引入新的作用域,也就是说这些代码块内定义的变量,外部也可以访问

if True:
    a = 'python'
print(a)        # python

修改作用域

global

当内部作用域想修改外部作用域的变量时

num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
     print(num) 
    num = 123
    print(num)
fun1()
print(num)

nonlocal

当内部作用域想修改enclosing作用域时

def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal 关键字声明
         num = 100
        print(num)
    inner()
    print(num)
outer()

# 100
# 100

作用域函数

globals():以字典类型返回当前位置的全部全局变量

locals():以字典类型返回当前位置的全部局部变量

vars([object]):打印当前调用位置或对象object的属性和属性值字典对象

dir([object]):返回当前范围内或对象object的变量、方法和定义的类型列表


匿名函数

lambda表达式也成匿名函数,所谓匿名,就是不再使用def语句来定义一个函数(没有函数名)

lambda的主体是一个表达式,而不是一个代码块,仅仅能在lambda表达式中封装有限的逻辑进去

lambda函数拥有自己的作用域,且不能访问自己参数列表之外或全局作用域里的参数

lambda的目的是调用小函数时不占用栈内存从而增加运行效率

lambda没有return语句,因为lambda不需要它来返回,表达式本身就是返回值

语法:lambda 函数参数:表达式

sum = lambda x, y: x + y
print('相加后的值为:', sum(10, 20))       # 相加后的值为: 30
print('相加后的值为:', sum(20, 20))       # 相加后的值为: 40

f = lambda x:x%2 == 1
l = filter(f,[1,2,3,4,5,6,7,8,9])        # 过滤函数
print(list(l))                          # [1, 3, 5, 7, 9]

迭代器

迭代器是一个可以记住遍历的位置的对象

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问结束,迭代器只能往前不会后退

迭代器有两个基本方法:iter()next()

字符串、列表、元组对象都可用于创建迭代器

迭代器对象可以使用for语句进行遍历

s = 'python'  # 字符串
l = [1, 2, 3, 4, 5, 6]  # 列表
t = (1, 2, 3, 4, 5, 6)  # 元组

# iter() 和 next()
print([next(iter(s[i])) for i in range(5)])
print([i for i in iter(l)])
print([i for i in iter(t)])
print('='*20)

# for语句遍历
print([i for i in s])  # ['p', 'y', 't', 'h', 'o', 'n']
print([i for i in l])  # [1, 2, 3, 4, 5, 6]
print([i for i in t])  # [1, 2, 3, 4, 5, 6]

创建迭代器

把一个类作为一个迭代器使用,需要在类中实现两个方法__iter__()和__next__()

__iter__():返回一个特殊的迭代器对象,这个迭代器对象实现了__next__()方法并通过Stoplteraion异常标识迭代的完成

__next__():会返回下一个迭代器对象

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

# 1
# 2
# 3
# 4
# 5

Stoplteraion

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)

生成器

在python中,使用了yield的函数被称为生成器

 生成器是一个返回迭代器的函数,只能用于迭代操作

在调用生成器运行的过程中,每次遇到yield时,函数会暂停并保存当前所有的运行信息,返回yield值,并在下一次执行next()方法时,从当前位置继续运行

调用一个生成器函数,返回的是一个迭代器对象

# python实现斐波那契数列

def finonacci(n):
    a, b = 0, 1
    while n > 0:
        a, b = b, a + b
        n -= 1
        yield a


n = 10
f = finonacci(n)
print([next(f) for i in range(n)])

闭包

是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数。

如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包。

通过闭包可以访问外层非全局作用域的变量,这个作用域称为 enclosing作用域

def outer(x):
    num = x             # enclosing作用域

    def inner(y):       # 闭包
        n = num + y
        return n

    return inner


o = outer(100)

print(o(50))        # 150

当闭包外的作用域变量需要在闭包内修改时,需增加nonlocal关键字

def outer(x):
    num = x             # enclosing变量

    def inner(y):       # 闭包
        nonlocal num    # 允许修改闭包外的enclosing变量
        num += 100      # 修改其变量值
        n = num + y
        return n

    return inner


o = outer(100)

print(o(50))        # 250

装饰器

装饰器用来增强一个现有函数的功能,并且不改变函数的调用方式

语法:@装饰器名称

装饰器原理

在python中,函数可以进行嵌套使用,并且函数可以作为另一个函数的返回参数

def f(a):
    print('这是一个功能')
    a += 1

    def f1(a):  # 嵌套
        print('这是被嵌套的函数')
        return a

    return f1(a)  # 返回函数 f1


a = 1
p = f(a)
print(p)

上述例子中,如果只有f1()函数,那么a=a

但是如果每次输入a都想增加两个功能,a += 1和print("这是一个功能"),条件是不改变f1()自身的内容,就可以使用嵌套的方式来实现在f1()函数外面套上两个功能

但实际应用中,并不是每次都需要在f1()函数外面嵌套一层f()函数

为了方便可根据需求随时嵌套一层f()函数的功能,因此使用装饰器的方式来为函数嵌套另一个函数的功能

def f(a):
    def new_f(a):
        print('这是一个功能')
        a += 1
        return a

    return new_f


@f
def f1(a):
    return a        # 装了装饰器,结果等于2


def f2(a):
    return a        # 没装装饰器,结果等于1


print(f1(1))
print(f2(1))

实际执行逻辑是:

  1. 执行print(f1(1))前,装饰器已经被执行了
  2. 执行f1(1)时,f1(()将参数 1 传递给f()函数,f()函数打印文字并返回结果
  3. f1()将f()函数返回的结果传入自身的功能中,并返回结果

例子中,f1()函数和f2()函数是一样的,只是为了区分带装饰器的效果而已

注意:多个装饰器执行的顺序就是从最后一个装饰器开始,执行到第一个装饰器,再执行函数本身


functools.wraps

当一个函数不被装饰器装饰时,其函数名称就是自己

而当被装饰器装饰后,名称就变成装饰器的了

def f(a):
    def new_f(a):
        print('这是一个功能')
        a += 1
        return a

    return new_f


@f
def f1(a):
    return a


def f2(a):
    return a


print(f1)  # <function f.<locals>.new_f at 0x000001F87591B5E0>
print(f2)  # <function f2 at 0x000001F87591B1F0>
print(f1.__name__)  # new_f
print(f2.__name__)  # f2

尤其装饰器本质上使用一个新的函数来替换被装饰的函数,所以函数的原信息会被覆盖

为了不影响,python的functools包中提供了一个叫wraps的decorator来消除这样的副作用

import functools


def f(a):
    @functools.wraps(a)
    def new_f(a):
        print('这是一个功能')
        a += 1
        return a

    return new_f


@f
def f1(a):
    return a


def f2(a):
    return a


print(f1)  # <function f1 at 0x0000012249AFB5E0>
print(f2)  # <function f2 at 0x000001F87591B1F0>
print(f1.__name__)  # f1
print(f2.__name__)  # f2

带参数的装饰器

带参数的装饰器需要写三层内嵌函数

当装饰器不带参数时,等效于在原函数上嵌套一层函数

@pre_str(pre=a)
def f1(a):
    return a

等效于:

def f1(a):
    return a

f1 = f(f1(a))

装饰器本质上也是一个函数,当装饰器内部执行时需要额外增加函数,那么就需要在装饰器外层再嵌套一层函数

import functools

a = 1


def pre_str(pre=a):
    if a == 1:
        print('a = 1')
    else:
        print('a = {}'.format(a))
    def f(a):
        @functools.wraps(a)  # 不修改原函数的名称
        def new_f(a):
            print('原来的a = {}'.format(pre))
            a += 1
            print('现在的a = {}'.format(a))
            return a

        return new_f

    return f


@pre_str(pre=a)
def f1(a):
    return a


def f2(a):
    return a


print(f1(1))

参考文章:

聊一聊:Python中的装饰器

Python进阶干货速递!【超详细迭代器、生成器、装饰器使用教程】_灰小猿的博客-CSDN博客


面向对象

类的定义

对象是类的实例(类主要定义对象的结构,类必须在被定义后才能使用,定义类也就是以类为模版创建对象)

类不但包含方法定义,还包含所有实例共享的数据

在python中,使用关键字class来定义python的类,关键字后面紧跟类的名称分号代码块

class Name:  # python中的类名约定以大写字母开头
    # 属性
    a = 0
    b = 1

    # 方法
    def name(self):
        return 'Hello,world!'


# 实例化类
x = Name()

# 访问类的属性和方法
print('类的属性为:', 'a={} b={}'.format(x.a, x.b))  # 类的属性为: a=0 b=1
print('类的方法为:{}'.format(x.name()))  # 类的方法为:Hello,world!

构造方法

类有一个名为__init__()的特殊方法(构造方法),该方法在类实例化时会自动调用

__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上

class Name:
    def __init__(self, a, b):  # 构造方法
        self.a = a  # 新建参数
        self.b = b


# 实例化
n = Name(1, 2)
print(n.a, n.b)  # 1 2

self(类的实例)

类的方法和普通的函数只有一个区别,那就是类的方法必须有一个额外的第一个参数名称,按照惯例它的名称是self

class Test:
    def prt(self):
        print(self)
        print(self.__class__)


t = Test()
t.prt()

# <__main__.Test object at 0x000001836E481BE0>
# <class '__main__.Test'>

从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。

类变量与实例变量

类变量:不需要实例化就能直接使用,绑定在类上,而不是绑定在实例上

类变量在实例中也能被调用,在类中作为所有实例共享的值

类变量也就是类属性

class Variable:
    name = 'inganxu'        # 类变量(类属性)

v = Variable()
print(v.name)       # inganxu

实例变量

class Variable:
    def __init__(self):
        self.name = 'inganxu'       # 实例变量(实例属性)

v = Variable()
print(v.name)           # inganxu

注意:

类体中,所有函数之外:类变量(类属性)

类体中,所有函数内部,以“self.变量名”的方式定义的变量:实例变量(实例属性)

类体中,所有函数内部,以“变量名=变量值”的方式定义的变量:局部变量

class Variable:
    class_name = 0              # 类变量(类属性)

    def __init__(self):
        self.name = 'inganxu'   # 实例变量(实例属性)

    def run(self):
        a = 0                   # 局部变量
        return a


v = Variable()
print(v.name)  # inganxu

继承

子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法

# 类定义
class Father():
    # 定义属性
    name1 = 'father'
    age = 30

    # 定义方法
    def __init__(self, n, a):
        self.name = n
        self.age = a

    def speak(self):
        print('{}说:我{}岁啦!'.format(self.name, self.age))


# 单继承
class Son(Father):
    grade = 0

    def __init__(self, n, a, grade):
        self.g = grade
        # 调用父类的构造函数
        Father.__init__(self, n, a)

    # 覆盖父类的方法
    def speak(self):
        print('{}说:我{}岁啦!我在读{}年纪喔!'.format(self.name, self.age, self.g))


# 实例化类
f = Father('爸爸', 40)
s = Son('儿子', 10, 1)
f.speak()
s.speak()

# 爸爸说:我40岁啦!
# 儿子说:我10岁啦!我在读1年纪喔!

多态

python同样有限的支持多继承形式

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python会从左到右查找父类中是否包含方法

# 类定义
class GrandFather():
    name = 'grandfather'
    a = 60
    grade = 0

    def __init__(self, n, a, g):
        self.n = n
        self.a = a
        self.g = g

    def speak(self):
        print('{}说:我{}岁啦!'.format(self.n, self.a))


class Father():
    # 定义属性
    name = 'father'  # 与GrandFather的属性同名
    age = 30

    # 定义方法
    def __init__(self, n, a):
        self.n = n
        self.age = a

    def speak(self):
        print('{}说:我{}岁啦!'.format(self.n, self.age))


# 单继承
class Son(GrandFather, Father):
    grade = 0

    def __init__(self, n, a, g):
        self.g = g
        # 调用父类的构造函数
        Father.__init__(self, n, a)

    # 覆盖父类的方法
    def speak(self):
        print('{}说:我{}岁啦!我在读{}年纪喔!'.format(self.n, self.age, self.g))


# 实例化类
g = GrandFather('爷爷', 60)
f = Father('爸爸', 40)
s = Son('儿子', 10, 1)
g.speak()
f.speak()
s.speak()

# 爷爷说:我60岁啦!
# 爸爸说:我40岁啦!
# 儿子说:我10岁啦!我在读1年纪喔!

注意:

GrandFather()类和Father()类并没有继承关系,两者的speak方法用的都是自己的方法

Son()类继承了GrandFather()类和Father()类两个父类

Son()类在调用名字时,self.n用的是GrandFather()类的方法,因为GrandFather()类在父类顺序中靠左

Son()类在调用年龄时,self.age用的是Father()类的方法,因为GrandFather()类的年龄方法是self.a

Son()类在调用年级时,self.g用的类是自己的方法,因为GrandFather()类的年级方法被覆盖了

私有属性

在python中定义私有变量只需要在变量名或函数名前加“__”两个下划线

不能在类的外部被使用或直接访问

class Private():
    __private = 0       # 私有属性
    publicity = 0       # 公有属性

    def count(self):
        self.__private += 1
        self.publicity += 1
        print(self.__private)

p = Private()
p.count()       # 1
p.count()       # 2

# python 的私有是伪私有
print(p._Private__private)      # 2
print(p.publicity)              # 2
print(p.__private)              # 报错,实例不能访问私有变量
# AttributeError: 'Private' object has no attribute '__private'

注意:私有变量可以通过公有函数调用,但不能直接访问私有变量

私有方法

class Private():
    __private = 0       # 私有属性
    publicity = 0       # 公有属性

    def count(self):
        self.__private += 1
        self.publicity += 1
        print(self.__private)
        print(self.publicity)

    def __p(self):
        print('这是私有方法')

    def p(self):
        print('这是公有方法')

p = Private()
p.count()
p.p()           # 公有方法

p.__P()         # 私有方法
# AttributeError: 'Private' object has no attribute '__P'

注意:私有方法无法直接访问

静态方法

静态方法在定义类时就已经被分配好了,并不绑定类也不绑定实例

定义静态方法需要加上装饰器语法“@staticmethod”

静态方法不需要“self”,调用时,也不需要实例化

class Staticmethod:
    name = 'inganxu'

    @staticmethod
    def run(cls):
        print(cls.name,'这是静态方法')


Staticmethod.run()  # 这是静态方法

类方法

类方法需要绑定在定义的类上,而不是绑定在实例上(类才需要绑定在实例上)

定义类方法需要加上装饰器语法“@classmethod”

类方法需要加入一个初始的参数“cls”,这个参数指向的是定义的类的本身,所有类方法可以读取和修改类变量

class Staticmethod:
    name = 'inganxu'

    @classmethod
    def run(cls):
        print(cls.name,'这是类方法')


Staticmethod.run()  # 这是类方法

普通方法、静态方法和类方法的区别

方法区别
普通方法不需要加任何东西
静态方法加“@staticmethod”
类方法加“@classmethod”,cls参数

相关内置函数

issubclass(class,classinfo):用于判断参数class是否是类型参数classinfo的子类

type():不会认为子类是一种父类类型,不考虑继承关系

isinstance():会认为子类是一种父类类型,考虑继承关系

hasattr(object,name):用于判断对象是否包含对应的属性

getattr(object,name[,default]):用于返回一个对象属性值

setattr():用于设置属性值,该属性不一定是存在的

delattr():用于删除属性


魔法方法

在python中,使用双下划线来定义魔法方法,例如“__init__”

魔法方法的第一个参数应为cls(类方法)或者self(实例方法)

魔法方法在某些类或对象执行中会自动执行

如果需要将python内置的魔法方法定制特殊功能,则需要对这些方法进行重写

__new__(cls,[...])

  • 定义的类被实例化时,如x = SomeClass(),__init__并不是第一个被调用的方法
  • 实际上,python调用了__new__方法来实例化这个对象,再将定义时创建的初始化函数作为参数传递给__init__
  • 若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用
  • 如果__new__没有返回实例对象,则__init__不会被调用
  • __new__主要是用于继承一个不可变的类型,比如tuple或string
class Person(object):

    def __new__(cls, *args, **kwargs):
        print("__new__()方法被调用了")
        print('这个是*agrs', *args)
        print('这个是kwagrs', **kwargs)
        
        # cls表示这个类,剩余所有的参数传给__init__()方法,
        # 若不返回,则__init__()不会被调用
        return object.__new__(cls)

    def __init__(self, name, age):
        print("__init__()方法被调用了")
        self.name = name
        self.age = age
        print(self.name, self.age)

p = Person("张三", 20)

# __new__()方法被调用了
# 这个是*agrs 张三 20
# 这个是kwagrs
# __init__()方法被调用了
# 张三 20

注意:

当我们需要继承内置类时,例如:int、str、tuple,就无法使用__init__来初始化,只能通过__new__来初始化数据

__init__()

类有一个名为__init__()的特殊方法(构造方法),该方法在类实例化时会自动调用

__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上

class Name:
    def __init__(self, a, b):  # 构造方法
        self.a = a  # 新建参数
        self.b = b


# 实例化
n = Name(1, 2)
print(n.a, n.b)  # 1 2

__del__()

当一个对象被系统回收时,python自动调用的方法

class Washer:
    def __del__(self):
        """
        当删除对象时,解释器会自动调用del方法
        """
        print('对象已删除!')

haier = Washer() 
# output:
# 对象已删除!

Python 采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。

大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。

类的表示

__str__():打印、转换

当你打印一个对象的时候,触发__str__

当你使用%s格式化的时候,触发__str__

str强转数据类型的时候,触发__str__

__repr__()打印、转换

repr是str的备胎

有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__

repr(obj)内置函数对应的结果是__repr__的返回值

当你使用%r格式化的时候 触发__repr__

class Washer:
    def __int__(self):
        pass

    def __repr__(self):
        return '我是__repr__()魔法方法!'

    def __str__(self):
        """
        这个str的作用就是:类的说明或对象状态的说明
        :return:
        """
        return '我是__str__魔法方法!'

haier = Washer()
# 不定义str方法,直接打印,结果是对象的内存地址
# 定义了str方法,显示的就是str方法返回的内容
print(haier)  # 我是__str__魔法方法

__bool__()

当调用 bool(obj) 时,会调用 __bool__() 方法,返回 True 或 False:

class Person(object):
    def __init__(self, uid):
        self.uid = uid

    def __bool__(self):
        return self.uid > 10

p1 = Person(4)
p2 = Person(14)
print(bool(p1))  # False
print(bool(p2))  # True

属性访问

__getattr__(self, name): 定义当用户试图获取一个不存在的属性时的行为

__getattribute__(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)

__setattr__(self, name, value):定义当一个属性被设置时的行为

__delattr__(self, name):定义当一个属性被删除时的行为

class C:
    def __getattribute__(self, item):
        print('__getattribute__')
        return super().__getattribute__(item)

    def __getattr__(self, item):
        print('__getattr__')

    def __setattr__(self, key, value):
        print('__setattr__')
        super().__setattr__(key, value)

    def __delattr__(self, item):
        print('__delattr__')
        super().__delattr__(item)


c = C()
c.x
# __getattribute__
# __getattr__

c.x = 1
# __setattr__

del c.x
# __delattr__

比较运算符

__eq__():判断两个对象是否相等

__ne__():判断两个对象是否不相等

class C(object):
    def __init__(self, uid):
        self.uid = uid

    def __eq__(self, other):
        return self.uid == other.uid

    def __ne__(self, other):
        """对象 != 判断"""
        return self.uid != other.uid


c1 = C(1)
c2 = C(1)
c3 = C(2)

print(c1 == c2)  # True
print(c2 == c3)  # False
print(c1 != c2)  # False
print(c2 != c3)  # True

__lt__():比较前一个对象是否小于后一个对象

__gt__():比较前一个对象是否大于后一个对象

class C(object):
    def __init__(self, uid):
        self.uid = uid

    def __lt__(self, other):
        return self.uid < other

    def __gt__(self, other):
        return self.uid > other


c1 = C(1)
c2 = C(1)
c3 = C(2)

print(c1 < c2)  # False
print(c2 < c3)  # True

print(c1 > c2)  # False
print(c2 > c3)  # False

算术运算符

__add__(self, other):定义加法的行为:+

__sub__(self, other):定义减法的行为:-

__mul__(self, other)定义乘法的行为:*

__truediv__(self, other)定义真除法的行为:/

__floordiv__(self, other)定义整数除法的行为://

__mod__(self, other) 定义取模算法的行为:%

__divmod__(self, other)定义当被 divmod() 调用时的行为 divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。

__pow__(self, other[, module])定义当被 power() 调用或 ** 运算时的行为

__lshift__(self, other)定义按位左移位的行为:<<

__rshift__(self, other)定义按位右移位的行为:>>

__and__(self, other)定义按位与操作的行为:&

__xor__(self, other)定义按位异或操作的行为:^

__or__(self, other)定义按位或操作的行为:|

反算术运算符

__radd__(self, other)定义加法的行为:+

__rsub__(self, other)定义减法的行为:-

__rmul__(self, other)定义乘法的行为:*

__rtruediv__(self, other)定义真除法的行为:/

__rfloordiv__(self, other)定义整数除法的行为://

__rmod__(self, other) 定义取模算法的行为:%

__rdivmod__(self, other)定义当被 divmod() 调用时的行为

__rpow__(self, other[, module])定义当被 power() 调用或 ** 运算时的行为

__rlshift__(self, other)定义按位左移位的行为:<<

__rrshift__(self, other)定义按位右移位的行为:>>

__rand__(self, other)定义按位与操作的行为:&

__rxor__(self, other)定义按位异或操作的行为:^

__ror__(self, other)定义按位或操作的行为:|

增量赋值运算符

__iadd__(self, other)定义赋值加法的行为:+=

__isub__(self, other)定义赋值减法的行为:-=

__imul__(self, other)定义赋值乘法的行为:*=

__itruediv__(self, other)定义赋值真除法的行为:/=

__ifloordiv__(self, other)定义赋值整数除法的行为://=

__imod__(self, other)定义赋值取模算法的行为:%=

__ipow__(self, other[, modulo])定义赋值幂运算的行为:**=

__ilshift__(self, other)定义赋值按位左移位的行为:<<=

__irshift__(self, other)定义赋值按位右移位的行为:>>=

__iand__(self, other)定义赋值按位与操作的行为:&=

__ixor__(self, other)定义赋值按位异或操作的行为:^=

__ior__(self, other)定义赋值按位或操作的行为:|=

一元运算符

__neg__(self)定义正号的行为:+x

__pos__(self)定义负号的行为:-x

__abs__(self)定义当被abs()调用时的行为

__invert__(self)定义按位求反的行为:~x

描述符

__get__(self, instance, owner)用于访问属性,它返回属性的值。

__set__(self, instance, value)将在属性分配操作中调用,不返回任何内容。

__del__(self, instance)控制删除操作,不返回任何内容

容器类操作

__setitem__(self, key, value):定义设置容器中指定元素的行为,相当于 self[key] = value;

__getitem__(self, key): 定义获取容器中指定元素的行为,相当于 self[key];

__delitem__(self, key):定义删除容器中指定元素的行为,相当于 del self[key];

__len__(self):定义当被 len() 调用时的行为(返回容器中元素的个数);

__iter__(self):定义当迭代容器中的元素的行为;

__contains__(self, item):定义当使用成员测试运算符(in 或 not in)时的行为;

__reversed__(self):定义当被 reversed() 调用时的行为

class MyList(object):
    """自己实现一个list"""

    def __init__(self, values=None):
        # 初始化自定义list
        self.values = values or []
        self._index = 0

    def __setitem__(self, key, value):
        # 添加元素
        self.values[key] = value

    def __getitem__(self, key):
        # 获取元素
        return self.values[key]

    def __delitem__(self, key):
        # 删除元素
        del self.values[key]

    def __len__(self):
        # 自定义list的元素个数
        return len(self.values)

    def __iter__(self):
        # 可迭代
        return self

    def __next__(self):
        # 迭代的具体细节
        # 如果__iter__返回self 则必须实现此方法
        if self._index >= len(self.values):
            raise StopIteration()
        value = self.values[self._index]
        self._index += 1
        return value

    def __contains__(self, key):
        # 元素是否在自定义list中
        return key in self.values

    def __reversed__(self):
        # 反转
        return list(reversed(self.values))


# 初始化自定义list
my_list = MyList([1, 2, 3, 4, 5])

print(my_list[0])  # __getitem__
my_list[1] = 20  # __setitem__

print(1 in my_list)  # __contains__
print(len(my_list))  # __len__

print([i for i in my_list])  # __iter__
del my_list[0]  # __del__

reversed_list = reversed(my_list)  # __reversed__
print([i for i in reversed_list])  # __iter__

可调用对象

__call__(self,[args...]):将一个函数当做一个参数传到另一个函数中

class Circle(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, x, y):
        self.x = x
        self.y = y

a = Circle(10, 20)	 # __init__
print(a.x, a.y)	# 10 20

a(100, 200)	# 此时a这个对象可以当做一个方法来执行,这是__call__魔法方法的功劳
print(a.x, a.y)	 # 100 200

注意:

这个例子首先初始化一个 Circle 实例 a,此时会调用 __init__ 方法,这个很好理解。

但是,我们对于实例 a 又做了调用 a(100, 200),注意,此时的 a 是一个实例对象,当我们这样执行时,其实它调用的就是 __call__。

这样一来,我们就可以把实例当做一个方法来执行。 也就是说,Python 中的实例,也是可以被调用的,通过定义 __call__ 方法,就可以传入自定义参数实现自己的逻辑。

这个魔法方法通常会用在类实现一个装饰器、元类等场景中,当遇到这个魔法方法时,能理解其中的原理就可以了。

序列化

__getstate__()

__setstate__()

import pickle

class Person(object):

    def __init__(self, name, age, birthday):
        self.name = name
        self.age = age
        self.birthday = birthday

    def __getstate__(self):
        # 执行 pick.dumps 时 忽略 age 属性
        return {
            'name': self.name,
            'birthday': self.birthday
        }

    def __setstate__(self, state):
        # 执行 pick.loads 时 忽略 age 属性
        self.name = state['name']
        self.birthday = state['birthday']

person = Person('李四', 20, (2017, 2, 23))
pickled_person = pickle.dumps(person) # 自动执行 __getstate__ 方法

p = pickle.loads(pickled_person) # 自动执行 __setstate__ 方法
print(p.name, p.birthday)  # 李四 (2017, 2, 23)
# 由于执行 pick.loads 时 忽略 age 属性,所以下面执行回报错
print(p.age)  # AttributeError: 'Person' object has no attribute 'age'

注意:

__getstate__():

这个例子首先初始了 Person 对象,其中包括 3 个属性:name、age、birthday。

当调用 pickle.dumps(person) 时,__getstate__ 方法就会被调用,在这里忽略了 Person 对象的 age 属性,那么 person 在序列化时,就只会对其他两个属性进行保存。

__setstate__():

同样地,当调用 pickle.loads(pickled_person) 时,__setstate__ 会被调用,其中传入的参数就是 __getstate__ 返回的结果。

在 __setstate__ 方法,我们从入参中取得了被序列化的 dict,然后从 dict 中取出对应的属性,就达到了反序列化的效果。

下划线分类

分类描述
_vars临时变量
__vars私有变量
vars_解决命名冲突
__vars__魔法方法

参考文章:

系统介绍python魔法方法_Ma Sizhou-CSDN博客_python魔法方法

Python 魔术方法指南 — PyCoder's Weelky CN

Python 类的魔术方法 - Dahlhin - 博客园

Python对下划线有多偏爱


模块

模块的定义

在python解释器上编程的方法和变量并不会保留,如果从python解释器退出再进入,那么之前定义的所有方法和变量都会消失

为此,python提供了一个办法,把这些定义存放在文件中,作为一些降本或者解释器实例使用,这个文件被称为模块

模块是一个包含你所有定义的函数和变量的文件,其后缀名为.py

模块可以被别的程序引入,以使用该模块中的函数等功能,python为此也提供了一些标准模块

参考文章:Python汇总篇,200+个Python标准库介绍(超全)


包的定义

包是一种管理 Python 模块命名空间的形式,采用 "点模块名称"

比如一个模块的名称是 A.B, 那么他表示一个包 A 中的子模块 B 

在使用模块过程中,不用担心不同模块之间的全局变量相互影响,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况

在实际应用中,一个功能完整的程序包含多个包,一个包包含一个或多个功能,而包中的模块包含一个或多个小功能

注意:包的目录仲只有包含一个叫做__init__.py的文件才会被认作是一个包


import语句

导入一个模块到当前命名空间中

import time

print(time.time())

注意:一个模块只会被导入一次,不管执行了多少次import


from xxx import xxx语句

从模块中导入一个指定的部分到当前命名空间中

from functools import wraps

from xxx import*语句

导入模块中的所有内容到当前命名空间中

from functools import *

from xxx.xxx import xxx

导入指定包中的指定模块中的指定部分到当前命名空间中

from sound.effects import echo

别名

在python中,可以给导入的模块起别名来加快编程效率

语法:import 模块名 as 别名

import time as t
from functools import wraps as w

模块搜索路径

python会在以下路径中搜索它想要寻找的模块:

  1. 程序所在的文件夹
  2. 标准库的安装路径
  3. 操作系统环境变量PYTHONPATH所包含的路径

如果有自定义的模块或者下载得到模块,可以根据情况放在相应的路径,以便python可以找到


文件

文件打开

python内置的函数open()用于打开指定文件或创建一个新文件

语法:open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

file: 必需,文件路径(相对或者绝对路径)。

mode: 可选,文件打开模式

buffering: 设置缓冲

encoding: 一般使用 utf8

errors: 报错级别

newline: 区分换行符

closefd: 传入的 file 参数类型

opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符

模式描述备注
t文本模式(默认))
x新建文件,已存在则报错
b二进制模式
+打开一个文件进行更新
r只读方式打开文件(指针放在文件的开头)
rb以二进制打开一个文件用于只读(指针放在文件的开头,一般用于图片)
r+打开一个文件用于读写(指针放在文件的开头)
rb+以二进制打开一个文件用于读写(指针放在文件的开头,一般用于图片)
w打开一个文件只用于写入

文件存在,则清空原内容

文件不存在,则新建文件

wb以二进制打开一个文件只用于写入

文件存在,则清空原内容

文件不存在,则新建文件

w+打开一个文件用于读写

文件存在,则清空原内容

文件不存在,则新建文件

wb+以二进制打开一个文件用于读写

文件存在,则清空原内容

文件不存在,则新建文件

a打开一个文件用于追加

文件存在,指针放在文件结尾

文件不存在,则新建文件用于写入

ab以二进制打开一个文件用于追加

文件存在,指针放在文件结尾

文件不存在,则新建文件用于写入

a+打开一个文件用于读写

文件存在,指针放在文件结尾

文件不存在,则新建文件用于读写

ab+以二进制打开一个文件用于读写

文件存在,指针放在文件结尾

文件不存在,则新建文件用于读写

模式rr+ww+aa+
++++
+++++
创建++++
覆盖++
指针在开始++++
指针在结尾++
# 打开或新建一个文件夹
f = open('d:/text.txt','w')

注意,当以‘r’的模式打开一个不存在的文件时,会报FileNotFoundError错误

参考文章:Python3 输入和输出 | 菜鸟教程


文件读取

read(num):num表示从文件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据

readine():一次只读取一行即遇到“\n”返回

readlines():读取整个文件,并返回列表,一行为一个元素

# 打开或新建一个文件夹
f = open('d:/text.txt', 'w')

# 文件读取
r = f.read()
print(r)

文件写入

python使用write()来将文本写入文件中

# 打开或新建一个文件夹
f = open('d:/text.txt', 'w')

# 文件写入
text = f.write("Python 是一个非常好的语言。\n 是的,的确非常好!!\n")
print(text)

# 文件读取
r = f.read()
print(r)

文件关闭

close()

# 打开或新建一个文件夹
f = open('d:/text.txt', 'w')

# 文件写入
text = f.write("Python 是一个非常好的语言。\n 是的,的确非常好!!\n")
print(text)

# 文件读取
r = f.read()
print(r)

# 关闭文件
f.close()

with...as...

上文提到,打开一个文件并操作之后需要关闭文件,以防出现问题

为了避免这种情况,可以使用with语句来打开文件,无论是否产生异常都能保证在with语句执行完成及时关闭文件

with open('d:/text.txt', 'w') as f:
    pass

之所以文件会自动关闭,是基于f对象的__exit__()方法

python在执行代码块之前调用对象的__enter__()方法,在介绍代码块的时候调用__exit__()方法

而在f的__exit__()方法中,有self.close()语句,所以在使用with...as...语句时,就不用明文关闭文件了


文件相关函数

file.seek():移动文件读取指针到指定位置

file.tell():返回文件当前位置

file.truncate([size]):从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除


OS

OS模块提供了非常丰富的方法用来处理文件和目录

参考文章:Python3 OS 文件/目录方法 | 菜鸟教程


PEP8规范

缩进

每一级缩进使用4个空格

换行没有使用垂直对齐时,禁止把参数放在第一行

当缩进没有与其他行区分时,要增加缩进


行的最大长度

所有行限制的最大字符数为79

没有结构化限制的大块文本(文档字符或者注释),每行的最大字符数限制在72


空行

顶层函数和类的定义,前后用两个空行隔开

类里的方法定义用一个空行隔开


导入

导入的库之间分开一行

导入总是位于文件的顶部,在模块注释和文档字符串之后,在模块的全局变量和常量之前

导入应该按照以下顺序分组

        标准库导入

        相关第三方库导入

        本地应用/库特定导入


注释

注释应该是完整的句子,如果注释很短,结尾的句号可以省略

块注释内部的段落通过只有一个#的空行分隔

行内注释由#和一个空格开始


字符串

要为所有的公共模块,函数,类以及方法编写文档说明

多行文档说明使用的结尾三引号应该自成一行

对于单行的文档说明,尾部的三引号应该和文档在同一行


命名约定

永远不要使用字母‘l’(小写的L),‘O’(大写的O),或者‘I’(大写的I)作为单字符变量名

在有些字体里,这些字符无法和数字0和1区分,如果想用‘l’,用‘L’代替

始终要将 self 作为实例方法的的第一个参数

始终要将 cls 作为类静态方法的第一个参数


结语

这是作者在学习python过程中,借鉴网上资料以及自己对知识点的理解并记录下来,后续对知识点有新的理解会逐步更新修改

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inganxu

感谢您的支持!!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值