Python基础语法笔记
文章目录
- 前言
- 1、变量、运算符与数据类型
- 1.1 注释
- 1.2 运算符
- 1.3 变量与赋值
- 1.4 数据类型与转换
- 1.5 print()函数
- 2、位运算
- 2.1 原码、反码和补码
- 2.2 利用位运算实现快速计算
- 2.3 利用位运算实现整数集合
- 3、条件语句
- 3.1 if语句
- 3.2 if-else语句
- 3.3 if-elif-else语句
- 3.4 assert关键词
- 4、循环语句
- 4.1 while循环
- 4.2 while-else循环
- 4.3 for循环
- 4.4 for-else循环
- 4.5 range()函数
- 4.6 enumerate()函数
- 4.7 break语句
- 4.8 continue语句
- 4.9 pass语句
- 4.10 推导式
- 5、异常处理
- 5.1 Python 标准异常总结
- 5.2Python标准警告总结
- 5.3 try-except 语句
- 5.4 try-except-finally语句
- 5.5 try-except-else语句
- 5.6 raise语句
- 6、列表
- 6.1 列表的定义
- 6.2 列表的创建
- 6.3 向列表添加元素
- 6.4删除列表中的元素
- 6.5 获取列表中的元素
- 6.6 列表常见操作符
- 6.7 列表的其它方法
- 7、元组
- 7.1 元组的定义
- 7.2 元组的创建
- 7.3 更新和删除一个元组
- 7.4 元组相关的操作符
- 7.5 内置方法
- 7.6 解压元组
- 8、字符串
- 8.1 字符串的定义
- 8.2 字符串的切片与拼接
- 8.3 字符串的常用内置方法
- 8.4 字符串格式化
- 9、字典
- 9.1 可变类型与不可变类型
- 9.2 字典的定义
- 9.3 字典的创建
- 9.4 字典的内置方法
- 10、集合
- 10.1 集合的创建
- 10.2 访问集合中的值
- 10.3 集合的内置方法
- 10.4 集合的转换
- 10.5 不可变集合
- 11、序列
- 11.1针对序列的内置函数
- 12、函数与Lambda表达式
- 12.1 函数
- 12.1.1 函数的定义
- 12.1.2 函数的调用
- 12.1.3 函数文档
- 12.1.4 函数参数
- 12.1.5 函数的返回值
- 12.1.6 变量作用域
- 12.2 Lambda表达式
- 12.2.1 匿名函数的定义
- 12.2.2 匿名函数的应用
- 13、类与对象
- 13.1 对象 = 属性 + 方法
- 13.2 self是什么?
- 13.3 Python的魔法方法
- 13.4 共有和私有
- 13.5 继承
- 13.6 组合
- 13.7 类、类对象和实例对象
- 13.8 什么是绑定?
- 13.9 一些相关的内置函数(BIF)
- 14、魔法方法
- 14.1 基本的魔法方法
- 14.2 算术运算符
- 14.3 反算术运算符
- 14.4 增量赋值运算符
- 14.5 一元运算符
- 14.6 属性访问
- 14.7 描述符
- 14.8 定制序列
- 14.9 迭代器
- 14.9.1 迭代器介绍
- 14.9.2 迭代器的基本方法
- 14.9.3 迭代器的魔法方法
- 14.10 生成器
- 15、模块
- 15.1 什么是模块
- 15.2 命名空间
- 15.3 导入模块
- 15.4 if __ name __ == '__ main __'
- 15.5 搜索路径
- 15.6 包
- 16、datetime模块
- 16.1 datetime类
- 16.2 date类
- 16.3 time类
- 16.4 timedelta类
- 17、文件与文件系统
- 17.1 打开文件
- 17.2 文件对象方法
- 17.3 简洁的with语句
- 18、os模块中关于文件/目录常用的函数
- 19、序列化和反序列化
- 总结
前言
本文章是为了Python入门笔记,方便后续学习中建议查看相应的知识点
1、变量、运算符与数据类型
1.1 注释
- 在Python 中, # 表示注释,作用于整行。
- ‘’’ ‘’’ 或者 “”" “”" 表示区间注释,在三引号之间的所有内容被注释
1.2 运算符
算术运算符
操作符 | 名称 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
// | 整除 |
% | 取余 |
** | 幂 |
比较运算符
操作符 | 名称 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
逻辑运算符
操作符 | 名称 |
---|---|
and | 与 |
or | 或 |
not | 非 |
位运算符
操作符 | 名称 |
---|---|
~ | 按位非 |
& | 按位与 |
丨 | 按位或 |
^ | 按位异或 |
<< | 左移 |
>> | 右移 |
口诀:非是取反,与是一假即假,或是一真即真,异或则有真有假为真,同真同假为假 |
其他运算符
操作符 | 名称 |
---|---|
is | 是 |
not is | 不是 |
in | 在 |
not in | 不在 |
注意:
- is, is not 对比的是两个变量的内存地址
- ==, != 对比的是两个变量的值
即:
- 假如比较的两个变量,指向的都是地址不可变的类型(str等),那么is,is not 和 ==,!= 是完全等价的。
- 假如对比的两个变量,指向的是地址可变的类型(list,dict,tuple等),则两者是有区别的。
运算符的优先级
- 一元运算符优于二元运算符。如正负号。
- 先算术运算,后移位运算,最后位运算。例如 1 << 3 + 2 & 7等价于 (1 << (3 + 2)) & 7
- 逻辑运算最后结合
1.3 变量与赋值
- 在使用变量之前,需要对其先赋值。
- 变量名可以包括字母、数字、下划线、但变量名不能以数字开头。
- Python 变量名是大小写敏感的,foo != Foo。
1.4 数据类型与转换
类型信息
类型 | 名称 |
---|---|
int | 整型 |
float | 浮点型 |
bool | 布尔型 |
注意: | |
确定 bool(X) 的值是 True 还是 False ,就看 X 是不是空,空的话就是 False ,不空的话就是 True 。 |
- 对于数值变量(整型、浮点型、布尔型), 0 , 0.0 都可认为是空的。
- 对于容器变量(字符、元组、列表、字典和集合),里面没元素就是空的。
获取类型信息
- type(object)
- isinstance(object, classinfo)
注:
- type() 不会认为子类是一种父类类型,不考虑继承关系。
- isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance() 。
类型转换
- 转换为整型 int(x, base=10)
- 转换为字符串 str(object=‘’)
- 转换为浮点型 float(x)
1.5 print()函数
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
- 将对象以字符串表示的方式格式化输出到流文件对象file里。其中所有非关键字参数都按 str() 方式进行转换为字符
串输出; - 关键字参数 sep 是实现分隔符,比如多个参数输出时想要输出中间的分隔字符;
- 关键字参数 end 是输出结束时的字符,默认是换行符 \n ;
- 关键字参数 file 是定义流输出的文件,可以是标准的系统输出 sys.stdout ,也可以重定义为别的文件;
- 关键字参数 flush 是立即把内容输出到流文件,不作缓存。
2、位运算
2.1 原码、反码和补码
- 原码:就是其二进制表示(注意,有一位符号位)。
- 反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反(对应正数按位取反)。
- 补码:正数的补码就是原码,负数的补码是反码+1。
注意:
符号位:最高位为符号位,0表示正数,1表示负数。在位运算中符号位也参与运算。
2.2 利用位运算实现快速计算
- 通过 << , >> 快速计算2的倍数问题,左乘右除
- 通过 ^ 快速交换两个整数。
- 通过 a & (-a) 快速获取 a 的最后为 1 位置的整数。
00 00 01 01 -> 5
&
11 11 10 11 -> -5
---
00 00 00 01 -> 100 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2
2.3 利用位运算实现整数集合
一个数的二进制表示可以看作是一个集合(0 表示不在集合中,1 表示在集合中)。
比如集合 {1, 3, 4, 8} ,可以表示成 01 00 01 10 10 而对应的位运算也就可以看作是对集合进行的操作。
元素与集合的操作:
a | (1<<i) -> 把 i 插入到集合中
a & ~(1<<i) -> 把 i 从集合中删除
a & (1<<i) -> 判断 i 是否属于该集合(零不属于,非零属于)
集合之间的操作:
a 补 -> ~a
a 交 b -> a & b
a 并 b -> a | b
a 差 b -> a & (~b)
3、条件语句
3.1 if语句
if expression:expr_true_suite
- if 语句的 expr_true_suite 代码块只有当条件表达式 expression 结果为真时才执行,否则将继续执行紧跟在该代码块后面的语句。
- 单个 if 语句中的 expression 条件表达式可以通过布尔操作符 and , or 和 not 实现多重条件判断。
3.2 if-else语句
if expression:expr_true_suite
else:expr_false_suite
Python 提供与 if 搭配使用的 else,如果 if 语句的条件表达式结果布尔值为假,那么程序将执行 else 语句后的代码。
3.3 if-elif-else语句
if expression1:expr1_true_suite
elif expression2:expr2_true_suite..
elif expressionN:exprN_true_suite
else:expr_false_suite
elif 语句即为 else if,用来检查多个表达式是否为真,并在为真时执行特定代码块中的代码。
3.4 assert关键词
assert 3 > 7
# AssertionError
- assert 这个关键词我们称之为“断言”,当这个关键词后边的条件为 False 时,程序自动崩溃并抛出 AssertionError 的异常。
- 在进行单元测试时,可以用来在程序中置入检查点,只有条件为 True 才能让程序正常工作。
- 注意:
if 语句支持嵌套,即在一个 if 语句中嵌入另一个 if 语句,从而构成不同层次的选择结构。Python 使用缩进而不是大括号来标记代码块边界,因此要特别注意 else 的悬挂问题。
4、循环语句
4.1 while循环
while 语句最基本的形式包括一个位于顶部的布尔表达式,一个或多个属于 while 代码块的缩进语句。
while 布尔表达式:代码块
while 循环的代码块会一直循环执行,直到布尔表达式的值为布尔假。
如果布尔表达式不带有 <、>、==、!=、in、not in 等运算符,仅仅给出数值之类的条件,也是可以的。当 while 后写入一个非零整数时,视为真值,执行循环体;写入 0 时,视为假值,不执行循环体。也可以写入 str、list 或任何序列,长度非零则视为真值,执行循环体;否则视为假值,不执行循环体。
4.2 while-else循环
while 布尔表达式:代码块
else:代码块
当 while 循环正常执行完的情况下,执行 else 输出,如果 while 循环中执行了跳出循环的语句,比如 break ,将不执行 else 代码块的内容。
4.3 for循环
for 循环是迭代循环,在Python中相当于一个通用的序列迭代器,可以遍历任何有序序列,如 str、list、tuple 等,也可以遍历任何可迭代对象,如 dict 。
for 迭代变量 in 可迭代对象:代码块
每次循环,迭代变量被设置为可迭代对象的当前元素,提供给代码块使用。
4.4 for-else循环
for 迭代变量 in 可迭代对象:代码块
else:代码块
当 for 循环正常执行完的情况下,执行 else 输出,如果 for 循环中执行了跳出循环的语句,比如 break ,将不执行 else 代码块的内容,与 while - else 语句一样。
4.5 range()函数
range([start,] stop[, step=1])
- 这个BIF(Built-in functions)有三个参数,其中用中括号括起来的两个表示这两个参数是可选的。
- step=1 表示第三个参数的默认值是1。
- range 这个BIF的作用是生成一个从 start 参数的值开始到stop 参数的值结束的数字序列,该序列包含 start 的值但不包含 stop 的值。
4.6 enumerate()函数
enumerate(sequence, [start=0])
- sequence – 一个序列、迭代器或其他支持迭代对象。
- start – 下标起始位置。
- 返回 enumerate(枚举) 对象
4.7 break语句
break 语句可以跳出当前所在层的循环。
4.8 continue语句
continue 终止本轮循环并开始下一轮循环。
4.9 pass语句
pass 语句的意思是“不做任何事”,如果你在需要有语句的地方不写任何语句,那么解释器会提示出错,而 pass 语句就是用来解决这些问题的。
pass 是空语句,不做任何操作,只起到占位的作用,其作用是为了保持程序结构的完整性。尽管 pass 语句不做任何操作,但如果暂时不确定要在一个位置放上什么样的代码,可以先放置一个 pass 语句,让代码可以正常运行。
4.10 推导式
- 列表推导式
[ expr for value in collection [if condition] ]
例子:
x = [(i, i ** 2) for i in range(6)]
print(x)
# [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
x = [i for i in range(100) if (i % 2) != 0 and (i % 3) == 0]
print(x)
# [3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93, 99]
- 元组推导式
( expr for value in collection [if condition] )
例子:
a = (x for x in range(10))
print(a)
# <generator object <genexpr> at 0x0000025BE511CC48>print(tuple(a))
# (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
- 字典推导式
{ key_expr: value_expr for value in collection [if condition] }
例子:
b = {i: i % 2 == 0 for i in range(10) if i % 3 == 0}
print(b)
# {0: True, 3: False, 6: True, 9: False}
- 集合推导式
{ expr for value in collection [if condition] }
例子:
c = {i for i in [1, 2, 3, 4, 5, 5, 6, 4, 3, 2, 1]}
print(c)
# {1, 2, 3, 4, 5, 6}
- 其它
d = 'i for i in "I Love Lsgogroup"'
print(d)
# i for i in "I Love Lsgogroup"e = (i for i in range(10))
print(e)
# <generator object <genexpr> at 0x0000007A0B8D01B0>
print(next(e)) # 0
print(next(e)) # 1
for each in e:
print(each, end=' ')
# 2 3 4 5 6 7 8 9s = sum([i for i in range(101)])
print(s) # 5050
s = sum((i for i in range(101)))
print(s) # 5050
5、异常处理
异常就是运行期检测到的错误。计算机语言针对可能出现的错误定义了异常类型,某种错误引发对应的异常时,异常处理程序将被启动,从而恢复程序的正常运行。
5.1 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异常体系中的部分关系如下所示:
5.2Python标准警告总结
- Warning:警告的基类
- DeprecationWarning:关于被弃用的特征的警告
- FutureWarning:关于构造将来语义会有改变的警告
- UserWarning:用户代码生成的警告
- PendingDeprecationWarning:关于特性将会被废弃的警告
- RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
- SyntaxWarning:可疑语法的警告
- ImportWarning:用于在导入模块过程中触发的警告
- UnicodeWarning:与Unicode相关的警告
- BytesWarning:与字节或字节码相关的警告
- ResourceWarning:与资源使用相关的警告
5.3 try-except 语句
try:检测范围
except Exception[as reason]:出现异常后的处理代码
try 语句按照如下方式工作:
- 首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)
- 如果没有异常发生,忽略 except 子句, try 子句执行后结束。
- 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。最后执行 try 语句之后的代码。
- 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
一个 try 语句可能包含多个 except 子句,分别来处理不同的特定的异常。最多只有一个分支会被执行。
一个 except 子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。
5.4 try-except-finally语句
try:检测范围
except Exception[as reason]:出现异常后的处理代码
finally:无论如何都会被执行的代码
不管 try 子句里面有没有发生异常, finally 子句都会执行。如果一个异常在 try 子句里被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后被抛出。
5.5 try-except-else语句
try:检测范围
except(Exception1[, Exception2[,...ExceptionN]]]):发生以上多个异常中的一个,执行这块代码
else:如果没有异常执行这块代码
如果在 try 子句执行时没有发生异常,Python将执行 else 语句后的语句。
例子:
dict1 = {'a': 1, 'b': 2, 'v': 22}
try:x = dict1['y']
except LookupError:print('查询错误')
except KeyError:print('键错误')
else:print(x)# 查询错误
try-except-else 语句尝试查询不在 dict 中的键值对,从而引发了异常。这一异常准确地说应属于 KeyError ,但由于 KeyError 是 LookupError 的子类,且将 LookupError 置于 KeyError 之前,因此程序优先执行该 except 代码块。
所以,使用多个 except 代码块时,必须坚持对其规范排序,要从最具针对性的异常到最通用的异常。
5.6 raise语句
Python 使用 raise 语句抛出一个指定的异常。
try:raise NameError('HiThere')
except NameError:print('An exception flew by!')# An exception flew by!
6、列表
简单数据类型
- 整型 <class ‘int’>
- 浮点型 <class ‘float’>
- 布尔型 <class ‘bool’>
容器数据类型
- 列表 <class ‘list’>
- 元组 <class ‘tuple’>
- 字典 <class ‘dict’>
- 集合 <class ‘set’>
- 字符串 <class ‘str’>
6.1 列表的定义
列表是有序集合,没有固定大小,能够保存任意数量任意类型的 Python 对象,语法为 [元素1, 元素2, …, 元素n] 。
- 关键点是「中括号 []」和「逗号 ,」
- 中括号 把所有元素绑在一起
- 逗号 将每个元素一一分开
6.2 列表的创建
1. 创建一个普通列表
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
print(x, type(x))
# ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] <class 'list'>2. 利用 range() 创建列表
x = list(range(1, 11, 2))
print(x, type(x))
# [1, 3, 5, 7, 9] <class 'list'>3. 利用推导式创建列表
x = [i for i in range(1, 10, 2)]
print(x, type(x))
# [1, 3, 5, 7, 9] <class 'list'>4. 创建一个混合列表
mix = [1, 'lsgo', 3.14, [1, 2, 3]]
print(mix)
# [1, 'lsgo', 3.14, [1, 2, 3]]5. 创建一个空列表
empty = []
print(empty)
# []
注意:
由于list的元素可以是任何对象,因此列表中所保存的是对象的指针。即使保存一个简单的 [1,2,3] ,也有3个指针和3个整数对象。
如x = [a] * 4 操作中,只是创建4个指向list的引用,所以一旦 a 改变, x 中4个 a 也会随之改变。
6.3 向列表添加元素
- list.append(obj) 在列表末尾添加新的对象,只接受一个参数,参数可以是任何数据类型,被追加的元素在 list中保持着原结构类型。
- list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。
append() 和 extend() 的区别:
- 严格来说 append() 是追加,把一个东西整体添加在列表后,而 extend() 是扩展,把一个东西里的所有元素添加在列表后。
- list.insert(index, obj) 在编号 index 位置前插入 obj 。
6.4删除列表中的元素
- list.remove(obj) 移除列表中某个值的第一个匹配项
- list.pop([index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
remove() 和 pop() 的区别:
- remove() 和 pop() 都可以删除元素,前者是指定具体要删除的元素,后者是指定一个索引。
- del var1[, var2 ……] 删除单个或多个对象。
- 如果知道要删除的元素在列表中的位置,可使用 del 语句。
- 如果你要从列表中删除一个元素,且不再以任何方式使用它,就使用 del 语句;如果你要在删除元素后还能继续使用它,就使用方法 pop() 。
6.5 获取列表中的元素
- 通过元素的索引值,从列表获取单个元素,注意,列表索引值是从0开始的。
- 通过将索引指定为-1,可让Python返回最后一个列表元素,索引 -2 返回倒数第二个列表元素,以此类推。
切片的通用写法是 start : stop : step
- 情况 1 - “start :”
以 step 为 1 (默认) 从编号 start 往列表尾部切片。 - 情况 2 - “: stop”
以 step 为 1 (默认) 从列表头部往编号 stop 切片。 - 情况 3 - “start : stop”
以 step 为 1 (默认) 从编号 start 往编号 stop 切片。 - 情况 4 - “start : stop : step”
以具体的 step 从编号 start 往编号 stop 切片。注意最后把 step 设为 -1,相当于将列表反向排列。 - 情况 5 - " : "
复制列表中的所有元素(浅拷贝)。
6.6 列表常见操作符
- 等号操作符: ==
- 连接操作符: +
- 重复操作符 :*
- 成员关系操作符: in 、 not in
「等号 ==」,只有成员、成员位置都相同时才返回True。
和元组拼接一样, 列表拼接也有两种方式,用「加号 +」和「乘号 *」,前者首尾拼接,后者复制拼接。
注意:
append() , extend() , insert() 可对列表增加元素,它们没有返回值,是直接修改了原数据对象。
连接操作符将两个list相加,需要创建新的 list 对象,从而需要消耗额外的内存,特别是当 list 较大时,尽量不要使用 “+” 来添加list。
6.7 列表的其它方法
- list.count(obj) 统计某个元素在列表中出现的次数
- list.index(x[, start[, end]]) 从列表中找出某个值第一个匹配项的索引位置
- list.reverse() 反向列表中元素
- list.sort(key=None, reverse=False) 对原列表进行排序。
key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象 中的一个元素来进行排序。
reverse – 排序规则, reverse = True 降序, reverse = False 升序(默认)。
该方法没有返回值,但是会对列表的对象进行排序。
7、元组
7.1 元组的定义
「元组」定义语法为: (元素1, 元素2, …, 元素n)
- 小括号把所有元素绑在一起
- 逗号将每个元素一一分开
7.2 元组的创建
- Python 的元组与列表类似,不同之处在于tuple被创建后就不能对其进行修改,类似字符串。
- 元组使用小括号,列表使用方括号。
- 创建元组可以用小括号 (),也可以什么都不用,为了可读性,建议还是用 ()。
- 元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用
7.3 更新和删除一个元组
元组有不可更改 (immutable) 的性质,因此不能直接给元组的元素赋值,但是只要元组中的元素可更改 (mutable),那么我
们可以直接更改其元素,注意这跟赋值其元素不同。
7.4 元组相关的操作符
- 比较操作符
- 逻辑操作符
- 连接操作符 +
- 重复操作符 *****
- 成员关系操作符 in 、 not in
元组拼接 (concatenate) 有两种方式,用「加号 +」和「乘号 *」,前者首尾拼接,后者复制拼接。
7.5 内置方法
元组大小和内容都不可更改,因此只有 count 和 index 两种方法。
7.6 解压元组
- 解压(unpack)一维元组(有几个元素左边括号定义几个变量)
t = (1, 10.31, 'python')
(a, b, c) = t
print(a, b, c)
# 1 10.31 python
- 解压二维元组(按照元组里的元组结构来定义变量)
t = (1, 10.31, ('OK', 'python'))
(a, b, (c, d)) = t
print(a, b, c, d)
# 1 10.31 OK python
- 如果你只想要元组其中几个元素,用通配符「*」,英文叫 wildcard,在计算机语言中代表一个或多个元素。下例就是把多个元素丢给了 rest 变量。
t = 1, 2, 3, 4, 5
a, b, *rest, c = t
print(a, b, c) # 1 2 5
print(rest) # [3, 4]
- 如果你根本不在乎 rest 变量,那么就用通配符「*」加上下划线「_」。
a, b, *_ = t
print(a, b) # 1 2
8、字符串
8.1 字符串的定义
- Python 中字符串被定义为引号之间的字符集合。
- Python 支持使用成对的 单引号 或 双引号。
- 如果字符串中需要出现单引号或双引号,可以使用转义符号 ** 对字符串中的符号进行转义。
Python的常用转义字符
转义字符 | 描述 |
---|---|
\ \ | 反斜杠符号 |
\ ’ | 单引号 |
\ " | 双引号 |
\ n | 换行 |
\ t | 横向制表符(TAB) |
\ r | 回车 |
- 原始字符串只需要在字符串前边加一个英文字母 r 即可。
- python三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。
8.2 字符串的切片与拼接
- 类似于元组具有不可修改性
- 从 0 开始 (和 C 一样)
- 切片通常写成 start:end 这种形式,包括「 start 索引」对应的元素,不包括「 end 索引」对应的元素。
- 索引值可正可负,正索引从 0 开始,从左往右;负索引从 -1 开始,从右往左。使用负数索引时,会从最后一个元素开始计数。最后一个元素的位置编号是 -1。
8.3 字符串的常用内置方法
- capitalize() 将字符串的第一个字符转换为大写。
str2 = 'xiaoxie'
print(str2.capitalize()) # Xiaoxie
- lower() 转换字符串中所有大写字符为小写。
- upper() 转换字符串中的小写字母为大写。
- swapcase() 将字符串中大写转换为小写,小写转换为大写。
str2 = "DAXIExiaoxie"
print(str2.lower()) # daxiexiaoxie
print(str2.upper()) # DAXIEXIAOXIE
print(str2.swapcase()) # daxieXIAOXIE
- count(str, beg= 0,end=len(string)) 返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数。
str2 = "DAXIExiaoxie"
print(str2.count('xi')) # 2
- endswith(suffix, beg=0, end=len(string)) 检查字符串是否以指定子字符串 suffix 结束,如果是,返回True,否则返回 False。如果 beg 和 end 指定值,则在指定范围内检查。
- startswith(substr, beg=0,end=len(string)) 检查字符串是否以指定子字符串 substr 开头,如果是,返回True,否则返回 False。如果 beg 和 end 指定值,则在指定范围内检查。
str2 = "DAXIExiaoxie"
print(str2.endswith('ie')) # True
print(str2.endswith('xi')) # False
print(str2.startswith('Da')) # False
print(str2.startswith('DA')) # True
- find(str, beg=0, end=len(string)) 检测 str 是否包含在字符串中,如果指定范围 beg 和 end ,则检查是否包含在指定范围内,如果包含,返回开始的索引值,否则返回 -1。
- rfind(str, beg=0,end=len(string)) 类似于 find() 函数,不过是从右边开始查找。
str2 = "DAXIExiaoxie"
print(str2.find('xi')) # 5
print(str2.find('ix')) # -1
print(str2.rfind('xi')) # 9
- isnumeric() 如果字符串中只包含数字字符,则返回 True,否则返回 False
str3 = '12345'
print(str3.isnumeric()) # True
str3 += 'a'
print(str3.isnumeric()) # False
- ljust(width[, fillchar]) 返回一个原字符串左对齐,并使用 fillchar (默认空格)填充至长度 width 的新字符串。
- rjust(width[, fillchar]) 返回一个原字符串右对齐,并使用 fillchar (默认空格)填充至长度 width 的新字符串。
str4 = '1101'
print(str4.ljust(8, '0')) # 11010000
print(str4.rjust(8, '0')) # 00001101
- lstrip([chars]) 截掉字符串左边的空格或指定字符。
- rstrip([chars]) 删除字符串末尾的空格或指定字符。
- strip([chars]) 在字符串上执行 lstrip() 和 rstrip() 。
str5 = ' I Love LsgoGroup '
print(str5.lstrip()) # 'I Love LsgoGroup '
print(str5.lstrip().strip('I')) # ' Love LsgoGroup '
print(str5.rstrip()) # ' I Love LsgoGroup'
print(str5.strip()) # 'I Love LsgoGroup'
print(str5.strip().strip('p')) # 'I Love LsgoGrou'
- partition(sub) 找到子字符串sub,把字符串分为一个三元组 (pre_sub,sub,fol_sub) ,如果字符串中不包含sub则返回 (‘原字符串’,‘’,‘’) 。
- rpartition(sub) 类似于 partition() 方法,不过是从右边开始查找。
str5 = ' I Love LsgoGroup '
print(str5.strip().partition('o')) # ('I L', 'o', 've LsgoGroup')
print(str5.strip().partition('m')) # ('I Love LsgoGroup', '', '')
print(str5.strip().rpartition('o')) # ('I Love LsgoGr', 'o', 'up')
- replace(old, new [, max]) 把 将字符串中的 old 替换成 new ,如果 max 指定,则替换不超过 max 次。
str5 = ' I Love LsgoGroup '
print(str5.strip().replace('I', 'We')) # We Love LsgoGroup
- split(str=“”, num) 不带参数默认是以空格为分隔符切片字符串,如果 num 参数有设置,则仅分隔 num 个子字符串,返回切片后的子字符串拼接的列表。
str5 = ' I Love LsgoGroup '
print(str5.strip().split()) # ['I', 'Love', 'LsgoGroup']
print(str5.strip().split('o')) # ['I L', 've Lsg', 'Gr', 'up']
- splitlines([keepends]) 按照行(‘\r’, ‘\r\n’, \n’)分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为False,不包含换行符,如果为 True,则保留换行符。
str6 = 'I \n Love \n LsgoGroup'
print(str6.splitlines()) # ['I ', ' Love ', ' LsgoGroup']
print(str6.splitlines(True)) # ['I \n', ' Love \n', ' LsgoGroup']
- maketrans(intab, outtab) 创建字符映射的转换表,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
- translate(table, deletechars=“”) 根据参数 table 给出的表,转换字符串的字符,要过滤掉的字符放到 deletechars 参数中。
str = 'this is string example....wow!!!'
intab = 'aeiou'
outtab = '12345'
trantab = str.maketrans(intab, outtab)
print(trantab) # {97: 49, 111: 52, 117: 53, 101: 50, 105: 51}
print(str.translate(trantab)) # th3s 3s str3ng 2x1mpl2....w4w!!!
8.4 字符串格式化
- Python format 格式化函数
str = "{0} Love {b}".format('I', b='Lsgogroup') # 位置参数要在关键字参数之前
print(str) # I Love Lsgogroup
- Python 字符串格式化符号
符号 | 描述 |
---|---|
%c | 格式化字符及其ASCII码 |
%s | 格式化字符串,用str()方法处理对象 |
%r | 格式化字符串,用rper()方法处理对象 |
%d | 格式化整数 |
%o | 格式化无符号八进制数 |
%x | 格式化无符号十六进制数 |
%X | 格式化无符号十六进制数(大写) |
%f | 格式化浮点数字,可指定小数点后的精度 |
%e | 用科学计数法格式化浮点数 |
%E | 作用同%e,用科学计数法格式化浮点数 |
%g | 根据值的大小决定使用%f或%e |
%G | 作用同%g,根据值的大小决定使用%f或%E |
print('%c' % 97) # a
print('%c %c %c' % (97, 98, 99)) # a b c
print('%d + %d = %d' % (4, 5, 9)) # 4 + 5 = 9
print("我叫 %s 今年 %d 岁!" % ('小明', 10)) # 我叫 小明 今年 10 岁!
print('%o' % 10) # 12
print('%x' % 10) # a
print('%X' % 10) # A
print('%f' % 27.658) # 27.658000
print('%e' % 27.658) # 2.765800e+01
print('%E' % 27.658) # 2.765800E+01
print('%g' % 27.658) # 27.658
text = "I am %d years old." % 22
print("I said: %s." % text) # I said: I am 22 years old..
print("I said: %r." % text) # I said: 'I am 22 years old.'
- 格式化操作符辅助指令
符号 | 功能 |
---|---|
m.n | m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话) |
- | 用做左对齐 |
+ | 在正数前面显示加号( + ) |
# | 在八进制数前面显示零(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’) |
0 | 显示的数字前面填充’0’而不是默认的空格 |
print('%5.1f' % 27.658) # ' 27.7'
print('%.2e' % 27.658) # 2.77e+01
print('%10d' % 10) # ' 10'
print('%-10d' % 10) # '10 '
print('%+d' % 10) # +10
print('%#o' % 10) # 0o12
print('%#x' % 108) # 0x6c
print('%010d' % 5) # 0000000005
9、字典
9.1 可变类型与不可变类型
那么如何快速判断一个数据类型 X 是不是可变类型的呢?两种方法:
- 麻烦方法:用 id(X) 函数,对 X 进行某种操作,比较操作前后的 id ,如果不一样,则 X 不可变,如果一样,则X 可变。
- 便捷方法:用 hash(X) ,只要不报错,证明 X 可被哈希,即不可变,反过来不可被哈希,即可变。
总结:
- 数值、字符和元组 都能被哈希,因此它们是不可变类型。
- 列表、集合、字典不能被哈希,因此它是可变类型。
9.2 字典的定义
字典 是无序的 键:值( key:value )对集合,键必须是互不相同的(在同一个字典之内)。
- dict 内部存放的顺序和 key 放入的顺序是没有关系的。
- dict 查找和插入的速度极快,不会随着 key 的增加而增加,但是需要占用大量的内存。
字典 定义语法为 {元素1, 元素2, …, 元素n}
- 其中每一个元素是一个「键值对」-- 键:值 ( key:value )
- 关键点是「大括号 {}」,「逗号 ,」和「冒号 :」
- 大括号 – 把所有元素绑在一起
- 逗号 – 将每个键值对分开
- 冒号 – 将键和值分开
9.3 字典的创建
- 通过字符串或数值作为 key 来创建字典。
注意:如果我们取的键在字典中不存在,会直接报错 KeyError 。
dic = {'李宁': '一切皆有可能', '耐克': 'Just do it', '阿迪达斯': 'Impossible is nothing'}
print('耐克的口号是:', dic['耐克'])
# 耐克的口号是: Just do it
- 通过元组作为 key 来创建字典,但一般不这样使用。
dic = {(1, 2, 3): "Tom", "Age": 12, 3: [3, 5, 7]}
print(dic) # {(1, 2, 3): 'Tom', 'Age': 12, 3: [3, 5, 7]}
print(type(dic)) # <class 'dict'>
- 通过元组作为 key 来创建字典,但一般不这样使用。通过构造函数 dict 来创建字典。
- dict() -> 创建一个空的字典。
dic = dict()
dic['a'] = 1
dic['b'] = 2
dic['c'] = 3
print(dic)
# {'a': 1, 'b': 2, 'c': 3}
- dict(mapping) -> 从映射对象的(键、值)对初始化的新字典。
dic1 = dict([('apple', 4139), ('peach', 4127), ('cherry', 4098)])
print(dic1) # {'cherry': 4098, 'apple': 4139, 'peach': 4127}dic2 = dict((('apple', 4139), ('peach', 4127), ('cherry', 4098)))
print(dic2) # {'peach': 4127, 'cherry': 4098, 'apple': 4139}
- **dict(kwargs) -> 使用关键字参数列表中的名称=值对初始化新字典。
这种情况下,键只能为字符串类型,并且创建的时候字符串不能加引号,加上就会直接报语法错误。
dic = dict(name='Tom', age=10)
print(dic) # {'name': 'Tom', 'age': 10}
print(type(dic)) # <class 'dict'>
9.4 字典的内置方法
- dict.fromkeys(seq[, value]) 用于创建一个新字典,以序列 seq 中元素做字典的键, value 为字典所有键对应的初始值。
seq = ('name', 'age', 'sex')
dic1 = dict.fromkeys(seq)
print("新的字典为 : %s" % str(dic1))
# 新的字典为 : {'name': None, 'age': None, 'sex': None}dic2 = dict.fromkeys(seq, 10)
print("新的字典为 : %s" % str(dic2))
# 新的字典为 : {'name': 10, 'age': 10, 'sex': 10}dic3 = dict.fromkeys(seq, ('小马', '8', '男'))
print("新的字典为 : %s" % str(dic3))
# 新的字典为 : {'name': ('小马', '8', '男'), 'age': ('小马', '8', '男'), 'sex': ('小马', '8', '男')}
- dict.keys() 返回一个可迭代对象,可以使用 list() 来转换为列表,列表为字典中的所有键。
dic = {'Name': 'lsgogroup', 'Age': 7}
print(dic.keys()) # dict_keys(['Name', 'Age'])
lst = list(dic.keys()) # 转换为列表
print(lst) # ['Name', 'Age']
- dict.values() 返回一个迭代器,可以使用 list() 来转换为列表,列表为字典中的所有值。
dic = {'Sex': 'female', 'Age': 7, 'Name': 'Zara'}
print("字典所有值为 : ", list(dic.values()))
# 字典所有值为 : [7, 'female', 'Zara']
- dict.items() 以列表返回可遍历的 (键, 值) 元组数组。
dic = {'Name': 'Lsgogroup', 'Age': 7}
print("Value : %s" % dic.items())
# Value : dict_items([('Name', 'Lsgogroup'), ('Age', 7)])
print(tuple(dic.items()))
# (('Name', 'Lsgogroup'), ('Age', 7))
- dict.get(key, default=None) 返回指定键的值,如果值不在字典中返回默认值。
dic = {'Name': 'Lsgogroup', 'Age': 27}
print("Age 值为 : %s" % dic.get('Age')) # Age 值为 : 27
print("Sex 值为 : %s" % dic.get('Sex', "NA")) # Sex 值为 : NA
- dict.setdefault(key, default=None) 和 get() 方法 类似, 如果键不存在于字典中,将会添加键并将值设为默认值。
dic = {'Name': 'Lsgogroup', 'Age': 7}
print("Age 键的值为 : %s" % dic.setdefault('Age', None)) # Age 键的值为 : 7
print("Sex 键的值为 : %s" % dic.setdefault('Sex', None)) # Sex 键的值为 : None
print("新字典为:", dic)
# 新字典为: {'Age': 7, 'Name': 'Lsgogroup', 'Sex': None}
- dict.pop(key[,default]) 删除字典给定键 key 所对应的值,返回值为被删除的值。 key 值必须给出。若 key不存在,则返回 default 值。
- del dict[key] 删除字典给定键 key 所对应的值。
dic1 = {1: "a", 2: [1, 2]}
print(dic1.pop(1), dic1) # a {2: [1, 2]}# 设置默认值,必须添加,否则报错
print(dic1.pop(3, "nokey"), dic1) # nokey {2: [1, 2]}del dic1[2]
print(dic1) # {}
- dict.popitem() 随机返回并删除字典中的一对键和值,如果字典已经为空,却调用了此方法,就报出KeyError异常。
dic1 = {1: "a", 2: [1, 2]}
print(dic1.popitem()) # (1, 'a')
print(dic1) # {2: [1, 2]}
- dict.clear() 用于删除字典内所有元素。
ic = {'Name': 'Zara', 'Age': 7}
print("字典长度 : %d" % len(dic)) # 字典长度 : 2
dict.clear()
print("字典删除后长度 : %d" % len(dic)) # 字典删除后长度 : 0
- dict.copy() 返回一个字典的浅复制。
dic1 = {'Name': 'Lsgogroup', 'Age': 7, 'Class': 'First'}
dic2 = dic1.copy()
print("新复制的字典为 : ", dic2)
# 新复制的字典为 : {'Age': 7, 'Name': 'Lsgogroup', 'Class': 'First'}
- dict.update(dict2) 把字典参数 dict2 的 key:value 对 更新到字典 dict 里。
dic = {'Name': 'Lsgogroup', 'Age': 7}
dic2 = {'Sex': 'female', 'Age': 8}
dic.update(dic2)
print("更新字典 dict : ", dic)
# 更新字典 dict : {'Sex': 'female', 'Age': 8, 'Name': 'Lsgogroup'}
10、集合
python 中 set 与 dict 类似,也是一组 key 的集合,但不存储 value 。由于 key 不能重复,所以,在 set 中,没有重复的 key 。
注意, key 为不可变类型,即可哈希的值。
num = {}
print(type(num)) # <class 'dict'>
num = {1, 2, 3, 4}
print(type(num)) # <class 'set'>
10.1 集合的创建
- 先创建对象再加入元素。在创建空集合的时候只能使用 s = set() ,因为 s = {} 创建的是空字典。
- 直接把一堆元素用花括号括起来 {元素1, 元素2, …, 元素n} ,重复元素在 set 中会被自动被过滤。
- 使用 set(value) 工厂函数,把列表或元组转换成集合。
由于 set 存储的是无序集合,所以我们不可以为集合创建索引或执行切片(slice)操作,也没有键(keys)可用来获取集合中
元素的值,但是可以判断一个元素是否在集合中。
10.2 访问集合中的值
- 可以使用 len() 內建函数得到集合的大小。
- 可以使用 for 循环把集合中的数据一个个读取出来
- 可以通过 in 或 not in 判断一个元素是否在集合中已经存在
10.3 集合的内置方法
- set.add(elmnt) 用于给集合添加元素,如果添加的元素在集合中已存在,则不执行任何操作。
- set.update(set) 用于修改当前集合,可以添加新的元素或集合到当前集合中,如果添加的元素在集合中已存在,则该元素只会出现一次,重复的会忽略。
- set.remove(item) 用于移除集合中的指定元素。如果元素不存在,则会发生错误。
- set.discard(value) 用于移除指定的集合元素。 remove() 方法在移除一个不存在的元素时会发生错误,而discard() 方法不会。
- set.pop() 用于随机移除一个元素。
- 由于 set 是无序和无重复元素的集合,所以两个或多个 set 可以做数学意义上的集合操作。
- set.intersection(set1, set2 …) 返回两个集合的交集。
- set1 & set2 返回两个集合的交集。
- set.intersection_update(set1, set2 …) 交集,在原始的集合上移除不重叠的元素。
- set.union(set1, set2…) 返回两个集合的并集。
- set1 | set2 返回两个集合的并集。
- set.difference(set) 返回集合的差集。
- set1 - set2 返回集合的差集。
- set.difference_update(set) 集合的差集,直接在原来的集合中移除元素,没有返回值。
- set.symmetric_difference(set) 返回集合的异或。
- set1 ^ set2 返回集合的异或。
- set.symmetric_difference_update(set) 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。
- set.issuperset(set) 用于判断集合是不是包含其他集合,如果是则返回 True,否则返回 False。
- set1 >= set2 判断集合是不是包含其他集合,如果是则返回 True,否则返回 False。
- set.isdisjoint(set) 用于判断两个集合是不是不相交,如果是返回 True,否则返回 False。
10.4 集合的转换
se = set(range(4))
li = list(se)
tu = tuple(se)
print(se, type(se)) # {0, 1, 2, 3} <class 'set'>
print(li, type(li)) # [0, 1, 2, 3] <class 'list'>
print(tu, type(tu)) # (0, 1, 2, 3) <class 'tuple'>
10.5 不可变集合
Python 提供了不能改变元素的集合的实现版本,即不能增加或删除元素,类型名叫 frozenset 。需要注意的是 frozenset 仍然可以进行集合操作,只是不能用带有 update 的方法。
- frozenset([iterable]) 返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
11、序列
- 序列是以连续的整数为索引,与此不同的是,字典以"关键字"为索引,关键字可以是任意不可变类型,通常用字符串或数值。
- 字典是 Python 唯一的一个 映射类型,字符串、元组、列表属于序列类型。
11.1针对序列的内置函数
- list(sub) 把一个可迭代对象转换为列表。
- tuple(sub) 把一个可迭代对象转换为元组。
- str(obj) 把obj对象转换为字符串。
- len(s) 返回对象(字符、列表、元组等)长度或元素个数。
- max(sub) 返回序列或者参数集合中的最大值
- min(sub) 返回序列或参数集合中的最小值
- sum(iterable[, start=0]) 返回序列 iterable 与可选参数 start 的总和。
- sorted(iterable, key=None, reverse=False) 对所有可迭代的对象进行排序操作。
a. iterable – 可迭代对象。
b. key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
c. reverse – 排序规则, reverse = True 降序 , reverse = False 升序(默认)。
d. 返回重新排序的列表。 - reversed(seq) 函数返回一个反转的迭代器。
a. seq – 要转换的序列,可以是 tuple, string, list 或 range。 - enumerate(sequence, [start=0]) 用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
a = list(enumerate(seasons))
print(a)
# [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]b = list(enumerate(seasons, 1))
print(b)
# [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
- zip(iter1 [,iter2 […]])
a. 用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样
做的好处是节约了不少的内存。
b. 我们可以使用 list() 转换来输出列表。
c. 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 ***** 号操作符,可以将元组解压为列表
a = [1, 2, 3]
b = [4, 5, 6]
c = [4, 5, 6, 7, 8]zipped = zip(a, b)
print(zipped) # <zip object at 0x000000C5D89EDD88>
print(list(zipped)) # [(1, 4), (2, 5), (3, 6)]
zipped = zip(a, c)
print(list(zipped)) # [(1, 4), (2, 5), (3, 6)]a1, a2 = zip(*zip(a, b))
print(list(a1)) # [1, 2, 3]
print(list(a2)) # [4, 5, 6]
12、函数与Lambda表达式
12.1 函数
还记得 Python 里面“万物皆对象”么?Python 把函数也当成对象,可以从另一个函数中返回出来而去构建高阶函数,比如:
- 参数是函数
- 返回值是函数
12.1.1 函数的定义
- 函数以 def 关键词开头,后接函数名和圆括号()。
- 函数执行的代码以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None 。
def functionname(parameters):"函数_文档字符串"function_suitereturn [expression]
12.1.2 函数的调用
def add(a, b):print(a + b)
add(1, 2) # 3
add([1, 2, 3], [4, 5, 6]) # [1, 2, 3, 4, 5, 6]
12.1.3 函数文档
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是形参
12.1.4 函数参数
Python 的函数具有非常灵活多样的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。从简到繁的参数形态
如下:
- 位置参数 (positional argument)
def functionname(arg1):"函数_文档字符串"function_suitereturn [expression]
- arg1 - 位置参数 ,这些参数在调用函数 (call function) 时位置要固定。
- 默认参数 (default argument)
def functionname(arg1, arg2=v):"函数_文档字符串"function_suitereturn [expression]
- arg2 = v - 默认参数 = 默认值,调用函数时,默认参数的值如果没有传入,则被认为是默认值。
- 默认参数一定要放在位置参数 后面,不然程序会报错。
- 可变参数 (variable argument)
顾名思义,可变参数就是传入的参数个数是可变的,可以是 0, 1, 2 到任意个,是不定长的参数。
def functionname(arg1, arg2=v, *args):"函数_文档字符串"function_suitereturn [expression]
- *args - 可变参数,可以是从零个到任意个,自动组装成元组。
- 加了星号(*)的变量名会存放所有未命名的变量参数。
- 关键字参数 (keyword argument)
def functionname(arg1, arg2=v, *args, **kw):"函数_文档字符串"function_suitereturn [expression]
**kw - 关键字参数,可以是从零个到任意个,自动组装成字典。
「可变参数」和「关键字参数」的同异总结如下:
- 可变参数允许传入零个到任意个参数,它们在函数调用时自动组装为一个元组 (tuple)。
- 关键字参数允许传入零个到任意个参数,它们在函数内部自动组装为一个字典 (dict)。
- 命名关键字参数 (name keyword argument)
def functionname(arg1, arg2=v, *args, *, nkw, **kw):"函数_文档字符串"function_suitereturn [expression]
- *, nkw - 命名关键字参数,用户想要输入的关键字参数,定义方式是在nkw 前面加个分隔符 *。
- 如果要限制关键字参数的名字,就可以用「命名关键字参数」
- 使用命名关键字参数时,要特别注意不能缺少参数名。
def printinfo(arg1, *, nkw, **kwargs):print(arg1)print(nkw)print(kwargs)printinfo(70, nkw=10, a=1, b=2)
# 70
# 10
# {'a': 1, 'b': 2}printinfo(70, 10, a=1, b=2)
# TypeError: printinfo() takes 1 positional argument but 2 were given
- 参数组合
在 Python 中定义函数,可以用位置参数、默认参数、可变参数、命名关键字参数和关键字参数,这 5 种参数中的 4 个都可以一起使用,但是注意,参数定义的顺序必须是:
- 位置参数、默认参数、可变参数和关键字参数。
- 位置参数、默认参数、命名关键字参数和关键字参数。
要注意定义可变参数和关键字参数的语法:
- *args 是可变参数, args 接收的是一个 tuple
- **kw 是关键字参数, kw 接收的是一个 dict
命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。定义命名关键字参数不要忘了写分隔符*,否则定义的是位置参数。
警告:虽然可以组合多达 5 种参数,但不要同时使用太多的组合,否则函数很难懂。
12.1.5 函数的返回值
def printme(str):print(str)temp = printme('hello') # hello
print(temp) # None
print(type(temp)) # <class 'NoneType'>
12.1.6 变量作用域
- Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
- 定义在函数内部的变量拥有局部作用域,该变量称为局部变量。
- 定义在函数外部的变量拥有全局作用域,该变量称为全局变量。
- 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。
num = 1def fun1():global num # 需要使用 global 关键字声明print(num) # 1num = 123print(num) # 123fun1()
print(num) # 123
- 内嵌函数
def outer():print('outer函数在这被调用')def inner():print('inner函数在这被调用')inner() # 该函数只能在outer函数内部被调用outer()
# outer函数在这被调用
# inner函数在这被调用
- 闭包
a.是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数。
b.如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包。
c.通过闭包可以访问外层非全局作用域的变量,这个作用域称为 闭包作用域。
d.如果要修改闭包作用域中的变量则需要 nonlocal 关键字
def funX(x):def funY(y):return x * yreturn funYi = funX(8)
print(type(i)) # <class 'function'>
print(i(5)) # 40
def outer():num = 10def inner():nonlocal num # nonlocal关键字声明num = 100print(num)inner()print(num)outer()
# 100
# 100
- 递归
如果一个函数在内部调用自身本身,这个函数就是递归函数。
例子:
斐波那契数列 f(n)=f(n-1)+f(n-2), f(0)=0 f(1)=1
def recur_fibo(n):if n <= 1:return nreturn recur_fibo(n - 1) + recur_fibo(n - 2)lst = list()
for k in range(11):lst.append(recur_fibo(k))
print(lst)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
注意:Python默认递归层数为 100
#设置递归的层数
import sys
sys.setrecursionlimit(1000)
12.2 Lambda表达式
12.2.1 匿名函数的定义
在 Python 里有两类函数:
- 第一类:用 def 关键词定义的正规函数
- 第二类:用 lambda 关键词定义的匿名函数
python 使用 lambda 关键词来创建匿名函数,而非 def 关键词,它没有函数名,其语法结构如下:
lambda argument_list: expression
- lambda - 定义匿名函数的关键词。
- argument_list - 函数参数,它们可以是位置参数、默认参数、关键字参数,和正规函数里的参数类型一样。
- : - 冒号,在函数参数和表达式中间要加个冒号。
- expression - 只是一个表达式,输入函数参数,输出一些值。
注意:
- expression 中没有 return 语句,因为 lambda 不需要它来返回,表达式本身结果就是返回值。
- 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
lbd_sqr = lambda x: x ** 2
print(lbd_sqr)
# <function <lambda> at 0x000000BABB6AC1E0>func = lambda *args: sum(args)
print(func(1, 2, 3, 4, 5)) # 15
12.2.2 匿名函数的应用
函数式编程 是指代码中每一块都是不可变的,都由纯函数的形式组成。这里的纯函数,是指函数本身相互独立、互不影响,对于相同的输入,总会有相同的输出,没有任何副作用。
例子:非函数式编程
def f(x):for i in range(0, len(x)):x[i] += 10return xx = [1, 2, 3]
f(x)
print(x)
# [11, 12, 13]
例子:函数式编程
def f(x):y = []for item in x:y.append(item + 10)return yx = [1, 2, 3]
f(x)
print(x)
# [1, 2, 3]
匿名函数 常常应用于函数式编程的高阶函数 (high-order function)中,主要有两种形式:
- 参数是函数 (filter, map)
- 返回值是函数 (closure)
如,在 filter 和 map 函数中的应用:
- filter(function, iterable) 过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
odd = lambda x: x % 2 == 1
templist = filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(templist)) # [1, 3, 5, 7, 9]
- map(function, *iterables) 根据提供的函数对指定序列做映射。
m1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(list(m1))
# [1, 4, 9, 16, 25]m2 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(list(m2))
# [3, 7, 11, 15, 19]
除了 Python 这些内置函数,我们也可以自己定义高阶函数。
def apply_to_list(fun, some_list):return fun(some_list)lst = [1, 2, 3, 4, 5]
print(apply_to_list(sum, lst))
# 15print(apply_to_list(len, lst))
# 5print(apply_to_list(lambda x: sum(x) / len(x), lst))
# 3.0
13、类与对象
13.1 对象 = 属性 + 方法
对象是类的实例。换句话说,类主要定义对象的结构,然后我们以类为模板创建对象。类不但包含方法定义,而且还包含所有实例共享的数据。
- 封装:信息隐蔽技术
我们可以使用关键字 class 定义 Python 类,关键字后面紧跟类的名称、分号和类的实现。
class Turtle: # Python中的类名约定以大写字母开头"""关于类的一个简单例子"""# 属性name = "熙光"# 方法def climb(self):print('我正在很努力的向前爬...')tt = Turtle()
print(tt)
# <__main__.Turtle object at 0x0000007C32D67F98>
print(type(tt))
# <class '__main__.Turtle'>
print(tt.__class__)
# <class '__main__.Turtle'>
print(tt.__class__.__name__)
# Turtle
tt.climb()
# 我正在很努力的向前爬...# Python类也是对象。它们是type的实例
print(type(Turtle))
# <class 'type'>
- 继承:子类自动共享父类之间数据和方法的机制
class MyList(list):passlst = MyList([1, 5, 2, 7, 8])
lst.append(9)
lst.sort()
print(lst)# [1, 2, 5, 7, 8, 9]
- 多态:不同对象对同一方法响应不同的行动
class Animal:def run(self):raise AttributeError('子类必须实现这个方法')class People(Animal):def run(self):print('人正在走') class Pig(Animal):def run(self):print('pig is walking')class Dog(Animal):def run(self):print('dog is running')def func(animal):animal.run()func(Pig())
# pig is walking
13.2 self是什么?
Python 的 self 相当于 C++ 的 this 指针。
class Test:def prt(self):print(self)print(self.__class__)t = Test()
t.prt()
# <__main__.Test object at 0x000000BC5A351208>
# <class '__main__.Test'>
类的方法与普通的函数只有一个特别的区别 —— 它们必须有一个额外的第一个参数名称(对应于该实例,即该对象本身),按照惯例它的名称是 self 。在调用方法时,我们无需明确提供与参数 self 相对应的参数。
class Ball:def setName(self, name):self.name = namedef kick(self):print("我叫%s,该死的,谁踢我..." % self.name)a = Ball()
a.setName("球A")
b = Ball()
b.setName("球B")
c = Ball()
c.setName("球C")
a.kick()
# 我叫球A,该死的,谁踢我...
b.kick()
# 我叫球B,该死的,谁踢我...
13.3 Python的魔法方法
据说,Python 的对象天生拥有一些神奇的方法,它们是面向对象的 Python 的一切…
它们是可以给你的类增加魔力的特殊方法…
如果你的对象实现了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,而这一切都是自动发生的…
类有一个名为 init(self[, param1, param2…]) 的魔法方法,该方法在类实例化时会自动调用。
class Ball:def __init__(self, name):self.name = namedef kick(self):print("我叫%s,该死的,谁踢我..." % self.name)a = Ball("球A")
b = Ball("球B")
c = Ball("球C")
a.kick()
# 我叫球A,该死的,谁踢我...
b.kick()
# 我叫球B,该死的,谁踢我...
13.4 共有和私有
在 Python 中定义私有变量只需要在变量名或函数名前加上“__”两个下划线,那么这个函数或变量就会为私有的了。
- 类的私有属性实例
class JustCounter:__secretCount = 0 # 私有变量publicCount = 0 # 公开变量def count(self):self.__secretCount += 1self.publicCount += 1print(self.__secretCount)counter = JustCounter()
counter.count() # 1
counter.count() # 2
print(counter.publicCount) # 2
print(counter._JustCounter__secretCount) # 2 Python的私有为伪私有
print(counter.__secretCount)
# AttributeError: 'JustCounter' object has no attribute '__secretCount'
- 类的私有方法实例
class Site:def __init__(self, name, url):self.name = name # publicself.__url = url # privatedef who(self):print('name : ', self.name)print('url : ', self.__url)def __foo(self): # 私有方法print('这是私有方法')def foo(self): # 公共方法print('这是公共方法')self.__foo()x = Site('熙光', 'http://www.xiguang.com')
x.who()
# name : 熙光
# url : http://www.xiguang.comx.foo()
# 这是公共方法
# 这是私有方法x.__foo()
# AttributeError: 'Site' object has no attribute '__foo
13.5 继承
Python 同样支持类的继承,派生类的定义如下所示:
class DerivedClassName(BaseClassName):<statement-1>...<statement-N>
BaseClassName (示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):<statement-1>...<statement-N>
例子:如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。
# 类定义
class people:# 定义基本属性name = ''age = 0# 定义私有属性,私有属性在类外部无法直接进行访问__weight = 0# 定义构造方法def __init__(self, n, a, w):self.name = nself.age = aself.__weight = wdef speak(self):print("%s 说: 我 %d 岁。" % (self.name, self.age))# 单继承示例
class student(people):grade = ''def __init__(self, n, a, w, g):# 调用父类的构函people.__init__(self, n, a, w)self.grade = g# 覆写父类的方法def speak(self):print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))s = student('熙光', 10, 60, 3)
s.speak()
# 熙光 说: 我 10 岁了,我在读 3 年级
注意:如果上面的程序去掉: people.__ init __(self, n, a, w) ,则输出: 说: 我 0 岁了,我在读 3 年级 ,因为子类的构造方法把父类的构造方法覆盖了。
例子:
class Fish:def __init__(self):self.x = r.randint(0, 10)self.y = r.randint(0, 10)def move(self):self.x -= 1print("我的位置", self.x, self.y)class GoldFish(Fish): # 金鱼passclass Shark(Fish): # 鲨鱼def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print("吃货的梦想就是天天有得吃!")self.hungry = Falseelse:print("太撑了,吃不下了!")self.hungry = Trueg = GoldFish()
g.move() # 我的位置 9 4
s = Shark()
s.eat() # 吃货的梦想就是天天有得吃!
s.move()
# AttributeError: 'Shark' object has no attribute 'x'
解决该问题可用以下两种方式:
- 调用未绑定的父类方法 Fish.__ init __(self)
class Shark(Fish): # 鲨鱼def __init__(self):Fish.__init__(self)self.hungry = Truedef eat(self):if self.hungry:print("吃货的梦想就是天天有得吃!")self.hungry = Falseelse:print("太撑了,吃不下了!")self.hungry = True
- 使用super函数 super().__ init __()
class Shark(Fish): # 鲨鱼def __init__(self):super().__init__()self.hungry = Truedef eat(self):if self.hungry:print("吃货的梦想就是天天有得吃!")self.hungry = Falseelse:print("太撑了,吃不下了!")self.hungry = True
Python 虽然支持多继承的形式,但我们一般不使用多继承,因为容易引起混乱。
class DerivedClassName(Base1, Base2, Base3):<statement-1>...<statement-N>
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,Python 从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法。
# 类定义
class People:# 定义基本属性name = ''age = 0# 定义私有属性,私有属性在类外部无法直接进行访问__weight = 0# 定义构造方法def __init__(self, n, a, w):self.name = nself.age = aself.__weight = wdef speak(self):print("%s 说: 我 %d 岁。" % (self.name, self.age))# 单继承示例
class Student(People):grade = ''def __init__(self, n, a, w, g):# 调用父类的构函People.__init__(self, n, a, w)self.grade = g# 覆写父类的方法def speak(self):print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))# 另一个类,多重继承之前的准备
class Speaker:topic = ''name = ''def __init__(self, n, t):self.name = nself.topic = tdef speak(self):print("我叫 %s,我是一个演说家,我演讲的主题是 %s" % (self.name, self.topic))# 多重继承
class Sample01(Speaker, Student):a = ''def __init__(self, n, a, w, g, t):Student.__init__(self, n, a, w, g)Speaker.__init__(self, n, t)test = Sample01("Tim", 25, 80, 4, "Python")
test.speak() # 方法名同,默认调用的是在括号中排前地父类的方法# 我叫 Tim,我是一个演说家,我演讲的主题是 Pythonclass Sample02(Student, Speaker):a = ''def __init__(self, n, a, w, g, t):Student.__init__(self, n, a, w, g)Speaker.__init__(self, n, t)test = Sample02("Tim", 25, 80, 4, "Python")
test.speak() # 方法名同,默认调用的是在括号中排前地父类的方法# Tim 说: 我 25 岁了,我在读 4 年级
13.6 组合
class Turtle:def __init__(self, x):self.num = xclass Fish:def __init__(self, x):self.num = xclass Pool:def __init__(self, x, y):self.turtle = Turtle(x)self.fish = Fish(y)def print_num(self):print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))p = Pool(2, 3)
p.print_num()
# 水池里面有乌龟2只,小鱼3条
13.7 类、类对象和实例对象
- 类对象:创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个。
- 实例对象:就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个。
- 类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享。
- 实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为 self 是谁调用,它的值就属于该对象。
- 类属性和实例属性区别
- 类属性:类外面,可以通过 实例对象.类属性 和 类名.类属性 进行调用。类里面,通过 self.类属性和 类名.类属性 进行调用。
- 实例属性 :类外面,可以通过 实例对象.实例属性 调用。类里面,通过 self.实例属性 调用。
- 实例属性就相当于局部变量。出了这个类或者这个类的实例对象,就没有作用了。
- 类属性就相当于类里面的全局变量,可以和这个类的所有实例对象共享。
# 创建类对象
class Test(object):class_attr = 100 # 类属性def __init__(self):self.sl_attr = 100 # 实例属性def func(self):print('类对象.类属性的值:', Test.class_attr) # 调用类属性print('self.类属性的值', self.class_attr) # 相当于把 类属性 变成 实例属性print('self.实例属性的值', self.sl_attr) # 调用实例属性a = Test()
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100b = Test()
b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100a.class_attr = 200
a.sl_attr = 200
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 200
# self.实例属性的值 200b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100Test.class_attr = 300
a.func()
# 类对象.类属性的值: 300
# self.类属性的值 200
# self.实例属性的值 200b.func()
# 类对象.类属性的值: 300
# self.类属性的值 300
# self.实例属性的值 100
注意:属性与方法名相同,属性会覆盖方法。
class A:def x(self):print('x_man')aa = A()
aa.x() # x_man
aa.x = 1
print(aa.x) # 1
aa.x()
# TypeError: 'int' object is not callable
13.8 什么是绑定?
Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念。
Python 对象的数据属性通常存储在名为 .__ dict __ 的字典中,我们可以直接访问 __ dict __ ,或利用 Python 的内置函数 vars() 获取 .__ dict __ 。
class CC:def setXY(self, x, y):self.x = xself.y = ydef printXY(self):print(self.x, self.y)dd = CC()
print(dd.__dict__)
# {}print(vars(dd))
# {}print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY':<function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>,'__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}dd.setXY(4, 5)
print(dd.__dict__)
# {'x': 4, 'y': 5}print(vars(CC))
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY':<function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>,'__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY':<function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>,'__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
13.9 一些相关的内置函数(BIF)
issubclass(class, classinfo) 方法用于判断参数 class 是否是类型参数 classinfo 的子类。
a.一个类被认为是其自身的子类。
b.classinfo 可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回 True 。isinstance(object, classinfo) 方法用于判断一个对象是否是一个已知的类型,类似 type() 。
a.type() 不会认为子类是一种父类类型,不考虑继承关系。
b.isinstance() 会认为子类是一种父类类型,考虑继承关系。
c.如果第一个参数不是对象,则永远返回 False 。
d.如果第二个参数不是类或者由类对象组成的元组,会抛出一个 TypeError 异常。hasattr(object, name) 用于判断对象是否包含对应的属性。
getattr(object, name[, default]) 用于返回一个对象属性值。
setattr(object, name, value) 对应函数 getattr() ,用于设置属性值,该属性不一定是存在的。
delattr(object, name) 用于删除属性。
class property([fget[, fset[, fdel[, doc]]]]) 用于在新式类中返回属性值。
a. fget – 获取属性值的函数
b. fset – 设置属性值的函数
c. fdel – 删除属性值函数
d. doc – 属性描述信息
14、魔法方法
魔法方法总是被双下划线包围,例如 __ init __ 。
魔法方法是面向对象的 Python 的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的 Python 的强大。
魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。
魔法方法的第一个参数应为 cls (类方法) 或者 self (实例方法)。
- cls :代表一个类的名称
- self :代表一个实例对象的名称
14.1 基本的魔法方法
- __ init __(self[, …])
a.构造器,当一个实例被创建的时候调用的初始化方法
class Rectangle:def __init__(self, x, y):self.x = xself.y = ydef getPeri(self):return (self.x + self.y) * 2def getArea(self):return self.x * self.yrect = Rectangle(4, 5)
print(rect.getPeri()) # 18
print(rect.getArea()) # 20
- __ new __(cls[, …])
a. __ new __ 是在一个对象实例化的时候所调用的第一个方法,在调用 __ init __ 初始化前,先调用 __ new __ 。
b. __ new __ 至少要有一个参数 cls ,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给 __ init __ 。
c. __ new __ 对当前类进行了实例化,并将实例返回,传给 __ init __ 的 self 。但是,执行了 __ new __ ,并不一定会进入 __ init __ ,只有 __ new __ 返回了,当前类 cls 的实例,当前类的 __ init __ 才会进入。
d. 若 __ new __ 没有正确返回当前类 cls 的实例,那 __ init __ 是不会被调用的,即使是父类的实例也不行,将没有 __ init __ 被调用。
e. 可利用 __ new __ 实现单例模式。
f. __ new __ 方法主要是当你继承一些不可变的 class 时(比如 int, str, tuple ), 提供给你一个自定义这些类的实例化过程的途径。
#a-c
class A(object):def __init__(self, value):print("into A __init__")self.value = valuedef __new__(cls, *args, **kwargs):print("into A __new__")print(cls)return object.__new__(cls)class B(A):def __init__(self, value):print("into B __init__")self.value = valuedef __new__(cls, *args, **kwargs):print("into B __new__")print(cls)return super().__new__(cls, *args, **kwargs)b = B(10)
# 结果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.B'>
# into B __init__class A(object):def __init__(self, value):print("into A __init__")self.value = valuedef __new__(cls, *args, **kwargs):print("into A __new__")print(cls)return object.__new__(cls)class B(A):def __init__(self, value):print("into B __init__")self.value = valuedef __new__(cls, *args, **kwargs):print("into B __new__")print(cls)return super().__new__(A, *args, **kwargs) # 改动了cls变为Ab = B(10)
# 结果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.A'>#d-e
class Earth:passa = Earth()
print(id(a)) # 260728291456
b = Earth()
print(id(b)) # 260728291624class Earth:__instance = None # 定义一个类属性做判断def __new__(cls):if cls.__instance is None:cls.__instance = object.__new__(cls)return cls.__instanceelse:return cls.__instancea = Earth()
print(id(a)) # 512320401648
b = Earth()
print(id(b)) # 512320401648#f
class CapStr(str):def __new__(cls, string):string = string.upper()return str.__new__(cls, string)a = CapStr("i love lsgogroup")
print(a) # I LOVE LSGOGROUP
- __ del __(self)
析构器,当一个对象将要被系统回收之时调用的方法。
class C(object):def __init__(self):print('into C __init__')def __del__(self):print('into C __del__')c1 = C()
# into C __init__
c2 = c1
c3 = c2
del c3
del c2
del c1
# into C __del__
__ str __ 和 __ repr __
__ str __(self) :
a. 当你打印一个对象的时候,触发 __ str __
b. 当你使用 %s 格式化的时候,触发 __ str __
c. str 强转数据类型的时候,触发 __ str ____ repr __(self):
a. repr 是 str 的备胎
b. 有 __ str __ 的时候执行 __ str __ ,没有实现 __ str __ 的时候,执行 __ repr __
c. repr(obj) 内置函数对应的结果是 __ repr __ 的返回值
d. 当你使用 %r 格式化的时候 触发 __ repr ____ str __(self) 的返回结果可读性强。也就是说, __ str __ 的意义是得到便于人们阅读的信息。
__ repr __(self) 的返回结果应更准确。怎么说, __ repr __ 存在的目的在于调试,便于开发者使用。
import datetime
today = datetime.date.today()print(str(today)) # 2022-03-20
print(repr(today)) # datetime.date(2022, 03, 20)print('%s' %today) # 2022-03-20
print('%r' %today) # datetime.date(2022, 03, 20)
14.2 算术运算符
类型工厂函数,指的是不通过类而是通过函数来创建对象
# 这个例子中list工厂函数把一个元祖对象加工成了一个列表对象。
print(list((1, 2, 3))) # [1, 2, 3]
- __ 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) 定义按位或操作的行为: |
14.3 反算术运算符
反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。
- __ 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) 定义按位或操作的行为: |
例如:a + b
这里加数是 a ,被加数是 b ,因此是 a 主动,反运算就是如果 a 对象的 __ add __() 方法没有实现或者不支持相应的操作,那么 Python 就会调用 b 的 __ radd __() 方法。
class Nint(int):def __radd__(self, other):return int.__sub__(other, self) # 注意 self 在后面a = Nint(5)
b = Nint(3)
print(a + b) # 8
print(1 + b) # -2
14.4 增量赋值运算符
- __ 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) 定义赋值按位或操作的行为: |=
14.5 一元运算符
- __ neg __(self) 定义正号的行为: +x
- __ pos __(self) 定义负号的行为: -x
- __ abs __(self) 定义当被 abs() 调用时的行为
- __ invert __(self) 定义按位求反的行为: ~x
14.6 属性访问
- __ getattr __(self, name) : 定义当用户试图获取一个不存在的属性时的行为。
- __ getattribute __(self, name) :定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用 __ getattr __ )。
- __ setattr __(self, name, value) :定义当一个属性被设置时的行为。
- __ delattr __(self, name) :定义当一个属性被删除时的行为。
14.7 描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
- __ get __(self, instance, owner) 用于访问属性,它返回属性的值。
- __ set __(self, instance, value) 将在属性分配操作中调用,不返回任何内容。
- __ del __(self, instance) 控制删除操作,不返回任何内容。
class MyDecriptor:def __get__(self, instance, owner):print('__get__', self, instance, owner)def __set__(self, instance, value):print('__set__', self, instance, value)def __delete__(self, instance):print('__delete__', self, instance)class Test:x = MyDecriptor()t = Test()
t.x
# __get__ <__main__.MyDecriptor object at 0x000000CEAAEB6B00> <__main__.Test object at0x000000CEABDC0898> <class '__main__.Test'>t.x = 'x-man'
# __set__ <__main__.MyDecriptor object at 0x00000023687C6B00> <__main__.Test object at0x00000023696B0940> x-mandel t.x
# __delete__ <__main__.MyDecriptor object at 0x000000EC9B160A90> <__main__.Test object at0x000000EC9B160B38>
14.8 定制序列
协议(Protocols)与其它编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在 Python 中的协议就显得不那么正式。事实上,在 Python 中,协议更像是一种指南。
容器类型的协议
- 如果说你希望定制的容器是不可变的话,你只需要定义 __ len __() 和 __ getitem __() 方法。
- 如果你希望定制的容器是可变的话,除了 __ len __() 和 __ getitem __() 方法,你还需要定义 __ setitem __()
和 __ delitem __() 两个方法。
- __ len __(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)。
- __ getitem __(self, key) 定义获取容器中元素的行为,相当于 self[key] 。
- __ setitem __(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value 。
- __ delitem __(self, key) 定义删除容器中指定元素的行为,相当于 del self[key] 。
例子:编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。
class CountList:def __init__(self, *args):self.values = [x for x in args]self.count = {}.fromkeys(range(len(self.values)), 0)def __len__(self):return len(self.values)def __getitem__(self, item):self.count[item] += 1return self.values[item]c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1]) # 3
print(c2[2]) # 6
print(c1[1] + c2[1]) # 7print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}
例子:编写一个可改变的自定义列表,要求记录列表中每个元素被访问的次数。
class CountList:def __init__(self, *args):self.values = [x for x in args]self.count = {}.fromkeys(range(len(self.values)), 0)def __len__(self):return len(self.values)def __getitem__(self, item):self.count[item] += 1return self.values[item]def __setitem__(self, key, value):self.values[key] = valuedef __delitem__(self, key):del self.values[key]for i in range(0, len(self.values)):if i >= key:self.count[i] = self.count[i + 1]self.count.pop(len(self.values))c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1]) # 3
print(c2[2]) # 6
c2[2] = 12
print(c1[1] + c2[2]) # 15print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}
del c1[1]
print(c1.count)
# {0: 0, 1: 0, 2: 0, 3: 0}
14.9 迭代器
14.9.1 迭代器介绍
- 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 字符串,列表或元组对象都可用于创建迭代器:
14.9.2 迭代器的基本方法
- iter(object) 函数用来生成迭代器。
- next(iterator[, default]) 返回迭代器的下一个项目。
iterator – 可迭代对象
default – 可选,用于设置在没有下一个元素时返回该默认值,如果不设置,又没有下一个元素则会触发 StopIteration 异常。
links = {'B': '百度', 'A': '阿里', 'T': '腾讯'}
it = iter(links)
print(next(it)) # B
print(next(it)) # A
print(next(it)) # T
print(next(it)) # StopIterationit = iter(links)
while True:try:each = next(it)except StopIteration:breakprint(each)# B
# A
# T
14.9.3 迭代器的魔法方法
- __ iter __(self) 定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了**__ next __()** 方法并通过 StopIteration 异常标识迭代的完成。
- __ next __() 返回下一个迭代器对象。
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __ next __() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
class Fibs:def __init__(self, n=10):self.a = 0self.b = 1self.n = ndef __iter__(self):return selfdef __next__(self):self.a, self.b = self.b, self.a + self.bif self.a > self.n:raise StopIterationreturn self.afibs = Fibs(100)
for each in fibs:print(each, end=' ')# 1 1 2 3 5 8 13 21 34 55 89
14.10 生成器
- 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
- 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
- 调用一个生成器函数,返回的是一个迭代器对象。
def libs(n):a = 0b = 1while True:a, b = b, a + bif a > n:returnyield afor each in libs(100):print(each, end=' ')
# 1 1 2 3 5 8 13 21 34 55 89
15、模块
在前面我们脚本是用 Python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了。
为此 Python 提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块(Module)。
模块是一个包含所有你定义的函数和变量的文件,其后缀名是 .py 。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用 Python 标准库的方法。
15.1 什么是模块
- 容器 -> 数据的封装
- 函数 -> 语句的封装
- 类 -> 方法和属性的封装
- 模块 -> 程序文件
例子:创建一个 hello.py 文件
# hello.py
def hi():print('Hi everyone, I love lsgogroup!')
15.2 命名空间
命名空间因为对象的不同,也有所区别,可以分为如下几种:
- 内置命名空间(Built-in Namespaces):Python 运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如 id() ,不需要做什么操作,拿过来就直接使用了。
- 全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。
- 本地命名空间(Function & Class:Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。
import hellohello.hi() # Hi everyone, I love lsgogroup!
hi() # NameError: name 'hi' is not defined
上述三种命名空间的关系
程序在查询上述三种命名空间的时候,就按照从里到外的顺序,即:Local Namespaces --> Global Namesspaces --> Built-inNamesspaces。
15.3 导入模块
例子:创建一个模块 TemperatureConversion.py
# TemperatureConversion.py
def c2f(cel):fah = cel * 1.8 + 32return fahdef f2c(fah):cel = (fah - 32) / 1.8return cel
- 第一种:import 模块名
import TemperatureConversionprint('32摄氏度 = %.2f华氏度' % TemperatureConversion.c2f(32))
print('99华氏度 = %.2f摄氏度' % TemperatureConversion.f2c(99))# 32摄氏度 = 89.60华氏度
# 99华氏度 = 37.22摄氏度
- 第二种:from 模块名 import 函数名
from TemperatureConversion import c2f, f2cprint('32摄氏度 = %.2f华氏度' % c2f(32))
print('99华氏度 = %.2f摄氏度' % f2c(99))# 32摄氏度 = 89.60华氏度
# 99华氏度 = 37.22摄氏度
下面的方式虽然简单粗暴,但是不推荐
from TemperatureConversion import *print('32摄氏度 = %.2f华氏度' % c2f(32))
print('99华氏度 = %.2f摄氏度' % f2c(99))# 32摄氏度 = 89.60华氏度
# 99华氏度 = 37.22摄氏度
- 第三种:import 模块名 as 新名字
import TemperatureConversion as tcprint('32摄氏度 = %.2f华氏度' % tc.c2f(32))
print('99华氏度 = %.2f摄氏度' % tc.f2c(99))# 32摄氏度 = 89.60华氏度
# 99华氏度 = 37.22摄氏度
15.4 if __ name __ == ‘__ main __’
对于很多编程语言来说,程序都必须要有一个入口,而 Python 则不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
如果一个 .py 文件(模块)被直接运行时,其 __ name __ 值为 __ main __ ,即模块名为 __ main __ 。
所以, if __ name __ == ‘__ main __’ 的意思是:当 .py 文件被直接运行时, if __ name __ == ‘__ main __’ 之下的代码块将被运行;当 .py 文件以模块形式被导入时, if __ name __ == ‘__ main __’ 之下的代码块不被运行。
15.5 搜索路径
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
import sys
print(sys.path)
# ['C:\\ProgramData\\Anaconda3\\DLLs', 'C:\\ProgramData\\Anaconda3\\lib','C:\\ProgramData\\Anaconda3', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages',...]
我们使用 import 语句的时候,Python 解释器是怎样找到对应的文件的呢?
这就涉及到 Python 的搜索路径,搜索路径是由一系列目录名组成的,Python 解释器就依次从这些目录中去寻找所引入的模块。
这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径。
搜索路径是在 Python 编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在 sys 模块中的 path 变量中。
15.6 包
包是一种管理 Python 模块命名空间的形式,采用"点模块名称"。
创建包分为三个步骤:
- 创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字。
- 在文件夹中创建一个 __ init __.py 的模块文件,内容可以为空。
- 将相关的模块放入文件夹中。
不妨假设你想设计一套统一处理声音文件和数据的模块(或者称之为一个"包")。
现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如: .wav,.aiff,.au),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。
并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。
这里给出了一种可能的包结构(在分层的文件系统中):
sound/ 顶层包__init__.py 初始化 sound 包formats/ 文件格式转换子包__init__.pywavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py...effects/ 声音效果子包__init__.pyecho.pysurround.pyreverse.py...filters/ filters子包__init__.pyequalizer.pyvocoder.pykaraoke.py...
在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。
目录只有包含一个叫做 __ init __.py 的文件才会被认作是一个包,最简单的情况,放一个空的 __ init __.py 就可以了。
import sound.effects.echo
这将会导入子模块 sound.effects.echo 。 他必须使用全名去访问:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
还有一种导入子模块的方法是:
from sound.effects import echo
这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
echo.echofilter(input, output, delay=0.7, atten=4)
还有一种变化就是直接导入一个函数或者变量:
from sound.effects.echo import echofilter
同样的,这种方法会导入子模块: echo,并且可以直接使用他的的echofilter() 函数:
echofilter(input, output, delay=0.7, atten=4)
注意当使用 from package import item 这种形式的时候,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。
设想一下,如果我们使用 from sound.effects import * 会发生什么?
Python 会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。
导入语句遵循如下规则:如果包定义文件 __ init __.py 存在一个叫做 __ all __ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。这里有一个例子,在 sounds/effects/__ init __.py 中包含如下代码:
__all__ = ["echo", "surround", "reverse"]
这表示当你使用 from sound.effects import * 这种用法时,你只会导入包里面这三个子模块。
如果 __ all __ 真的没有定义,那么使用 from sound.effects import * 这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包 sound.effects 和它里面定义的所有内容导入进来(可能运行 __ init __.py 里定义的初始化代码)。
这会把 __ init __.py 里面定义的所有名字导入进来。并且他不会破坏掉我们在这句话之前导入的所有明确指定的模块。
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
这个例子中,在执行 from…import 前,包 sound.effects 中的 echo 和 surround 模块都被导入到当前的命名空间中了。
通常我们并不主张使用 * 这种方法来导入模块,因为这种方法经常会导致代码的可读性降低。
16、datetime模块
datetime 是 Python 中处理日期的标准模块,它提供了 4 种对日期和时间进行处理的类:datetime、date、time 和 timedelta。
16.1 datetime类
class datetime(date):def __init__(self, year, month, day, hour, minute, second, microsecond, tzinfo)passdef now(cls, tz=None):passdef timestamp(self):passdef fromtimestamp(cls, t, tz=None):passdef date(self):passdef time(self):passdef year(self):passdef month(self):passdef day(self):passdef hour(self):passdef minute(self):passdef second(self):passdef isoweekday(self):passdef strftime(self, fmt):passdef combine(cls, date, time, tzinfo=True):pass
- datetime.now(tz=None) 获取当前的日期时间,输出顺序为:年、月、日、时、分、秒、微秒。
- datetime.timestamp() 获取以 1970年1月1日为起点记录的秒数。
- datetime.fromtimestamp(tz=None) 使用 unixtimestamp 创建一个 datetime。
例子:如何创建一个 datetime 对象?
import datetimedt = datetime.datetime(year=2020, month=6, day=25, hour=11, minute=23, second=59)
print(dt) # 2020-06-25 11:23:59
print(dt.timestamp()) # 1593055439.0dt = datetime.datetime.fromtimestamp(1593055439.0)
print(dt) # 2020-06-25 11:23:59
print(type(dt)) # <class 'datetime.datetime'>dt = datetime.datetime.now()
print(dt) # 2020-06-25 11:11:03.877853
print(type(dt)) # <class 'datetime.datetime'>
- datetime.strftime(fmt) 格式化 datetime 对象
符号 | 说明 |
---|---|
%a | 本地简化星期名称(如星期一,返回 Mon) |
%A | 本地完整星期名称(如星期一,返回 Monday) |
%b | 本地简化的月份名称(如一月,返回 Jan) |
%B | 本地完整的月份名称(如一月,返回 January) |
%c | 本地相应的日期表示和时间表示 |
%d | 月内中的一天(0-31) |
%H | 24小时制小时数(0-23) |
%I | 12小时制小时数(01-12) |
%j | 年内的一天(001-366) |
%m | 月份(01-12) |
%M | 分钟数(00-59) |
%p | 本地A.M.或P.M.的等价符 |
%S | 秒(00-59) |
%U | 一年中的星期数(00-53)星期天为星期的开始 |
%w | 星期(0-6),星期天为星期的开始 |
%W | 一年中的星期数(00-53)星期一为星期的开始 |
%x | 本地相应的日期表示 |
%X | 本地相应的时间表示 |
%y | 两位数的年份表示(00-99) |
%Y | 四位数的年份表示(0000-9999) |
%Z | 当前时区的名称(如果是本地时间,返回空字符串) |
%% | %号本身 |
例子:如何将 datetime 对象转换为任何格式的日期?
import datetimedt = datetime.datetime(year=2020, month=6, day=25, hour=11, minute=51, second=49)
s = dt.strftime("'%Y/%m/%d %H:%M:%S")
print(s) # '2020/06/25 11:51:49s = dt.strftime('%d %B, %Y, %A')
print(s) # 25 June, 2020, Thursday
- datetime.date() 日期
- datetime.time() 时间
- datetime.year 年
- datetime.month 月
- datetime.day 日
- datetime.hour 小时
- datetime.minute 分钟
- datetime.second 秒
- . datetime.isoweekday 星期几
import datetimedt = datetime.datetime(year=2020, month=6, day=25, hour=11, minute=51, second=49)
print(dt.date()) # 2020-06-25
print(type(dt.date())) # <class 'datetime.date'>
print(dt.time()) # 11:51:49
print(type(dt.time())) # <class 'datetime.time'>
print(dt.year) # 2020
print(dt.month) # 6
print(dt.day) # 25
print(dt.hour) # 11
print(dt.minute) # 51
print(dt.second) # 49
print(dt.isoweekday()) # 4
在处理含有字符串日期的数据集或表格时,我们需要一种自动解析字符串的方法,无论它是什么格式的,都可以将其转化为 datetime 对象。这时,就要使用到 dateutil 中的 parser 模块。
- **parser.parse(timestr, parserinfo=None, kwargs)
例子:如何在 python 中将字符串解析为 datetime对象?
from dateutil import parsers = '2020-06-25'
dt = parser.parse(s)
print(dt) # 2020-06-25 00:00:00
print(type(dt)) # <class 'datetime.datetime'>s = 'March 31, 2010, 10:51pm'
dt = parser.parse(s)
print(dt) # 2010-03-31 22:51:00
print(type(dt)) # <class 'datetime.datetime'>
16.2 date类
class date:def __init__(self, year, month, day):passdef today(cls):pass
- date.today() 获取当前日期信息。
import datetimed = datetime.date(2020, 6, 25)
print(d) # 2020-06-25
print(type(d)) # <class 'datetime.date'>d = datetime.date.today()
print(d) # 2020-06-25
print(type(d)) # <class 'datetime.date'>
16.3 time类
class time:def __init__(self, hour, minute, second, microsecond, tzinfo):pass
例子:如何使用 datetime.time() 类?
import datetimet = datetime.time(12, 9, 23, 12980)
print(t) # 12:09:23.012980
print(type(t)) # <class 'datetime.time'>
注意:
- 1秒 = 1000 毫秒(milliseconds)
- 1毫秒 = 1000 微妙(microseconds)
16.4 timedelta类
timedelta 表示具体时间实例中的一段时间。你可以把它们简单想象成两个日期或时间之间的间隔。
它常常被用来从 datetime 对象中添加或移除一段特定的时间。
class timedelta(SupportsAbs[timedelta]):def __init__(self, days, seconds, microseconds, milliseconds, minutes, hours, weeks,):passdef days(self):passdef total_seconds(self):pass
例子:如何使用 datetime.timedelta()类?
import datetimetd = datetime.timedelta(days=30)
print(td) # 30 days, 0:00:00
print(type(td)) # <class 'datetime.timedelta'>
print(datetime.date.today()) # 2020-07-01
print(datetime.date.today() + td) # 2020-07-31dt1 = datetime.datetime(2020, 1, 31, 10, 10, 0)
dt2 = datetime.datetime(2019, 1, 31, 10, 10, 0)
td = dt1 - dt2
print(td) # 365 days, 0:00:00
print(type(td)) # <class 'datetime.timedelta'>td1 = datetime.timedelta(days=30) # 30 days
td2 = datetime.timedelta(weeks=1) # 1 week
td = td1 - td2
print(td) # 23 days, 0:00:00
print(type(td)) # <class 'datetime.timedelta'>
17、文件与文件系统
17.1 打开文件
- open(file, mode=‘r’, buffering=None, encoding=None, errors=None, newline=None, closefd=True) 打开文件并返回文件对象象,如果该文件无法被打开,会抛出 OSError。
a. file : 必需,文件路径(相对或者绝对路径)。
b. mode : 可选,文件打开模式
c. buffering : 设置缓冲
d. encoding : 一般使用utf8
e. errors : 报错级别
f. newline : 区分换行符
常见的 mode 如下表所示:
打开模式 | 执行操作 |
---|---|
‘r’ | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
‘w’ | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑。即原有内容会被删除。如果该文件不存在,创建新文件。 |
‘x’ | 写模式,新建一个文件,如果该文件已存在则会报错。 |
‘a’ | 追加模式,打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
‘b’ | 以二进制模式打开文件。一般用于非文本文件,如:图片。 |
‘t’ | 以文本模式打开(默认)。一般用于文本文件,如:txt。 |
‘+’ | 可读写模式(可添加到其它模式中使用) |
17.2 文件对象方法
- fileObject.close() 用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。
- fileObject.read([size]) 用于从文件读取指定的字符数,如果未给定或为负则读取所有。
- fileObject.readline() 读取整行,包括 “\n” 字符。
- fileObject.readlines() 用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for… in … 结构进行处理。
- fileObject.tell() 返回文件的当前位置,即文件指针当前位置。
- fileObject.seek(offset[, whence]) 用于移动文件读取指针到指定位置。
a. offset :开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始。
b. whence :可选,默认值为 0。给 offset 定义一个参数,表示要从哪个位置开始偏移;0 代表从文件开头开始算起,1 代表从当前位置开始算起,2 代表从文件末尾算起。 - fileObject.write(str) 用于向文件中写入指定字符串,返回的是写入的字符长度。
f = open('workfile.txt', 'wb+')
print(f.write(b'0123456789abcdef')) # 16
print(f.seek(5)) # 5
print(f.read(1)) # b'5'
print(f.seek(-3, 2)) # 13
print(f.read(1)) # b'd'
在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。
如果文件打开模式带 b ,那写入文件内容时, str (参数)要用 encode 方法转为 bytes 形式,否则报错: TypeError: a bytes-like object is required, not ‘str’ 。
str = '...'
# 文本 = Unicode字符序列
# 相当于 string 类型str = b'...'
# 文本 = 八位序列(0到255之间的整数)
# 字节文字总是以‘b’或‘B’作为前缀;它们产生一个字节类型的实例,而不是str类型。
# 相当于 byte[]
- fileObject.writelines(sequence) 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符 \n 。
17.3 简洁的with语句
一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。
关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行它的清理方法。
try:with open('myfile.txt', 'w') as f:for line in f:print(line)
except OSError as error:print('出错啦!%s' % str(error))# 出错啦!not readable
18、os模块中关于文件/目录常用的函数
- os.getcwd() 用于返回当前工作目录。
- os.chdir(path) 用于改变当前工作目录到指定的路径。
- listdir (path=‘.’) 返回 path 指定的文件夹包含的文件或文件夹的名字的列表。
- os.mkdir(path) 创建单层目录,如果该目录已存在抛出异常。
- os.makedirs(path) 用于递归创建多层目录,如果该目录已存在抛出异常。
- os.remove(path) 用于删除指定路径的文件。如果指定的路径是一个目录,将抛出 OSError 。
- os.rmdir(path) 用于删除单层目录。仅当这文件夹是空的才可以, 否则, 抛出 OSError 。
- os.removedirs(path) 递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常。
- os.rename(src, dst) 方法用于命名文件或目录,从 src 到 dst ,如果 dst 是一个存在的目录, 将抛出OSError 。
- os.system(command) 运行系统的shell命令(将字符串转化成命令)
- os.curdir 指代当前目录( . )
- os.pardir 指代上一级目录( … )
- os.sep 输出操作系统特定的路径分隔符(win下为 \ ,Linux下为 / )
- os.linesep 当前平台使用的行终止符(win下为 \r\n ,Linux下为 \n )
- os.name 指代当前使用的操作系统(包括:‘mac’,‘nt’)
- os.path.basename(path) 去掉目录路径,单独返回文件名。
- os.path.dirname(path) 去掉文件名,单独返回目录路径。
- os.path.join(path1[, path2[, …]]) 将 path1 , path2 各部分组合成一个路径名。
- os.path.split(path) 分割文件名与路径,返回 (f_path,f_name) 元组。如果完全使用目录,它会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在。
- os.path.splitext(path) 分离文件名与扩展名,返回 (f_path,f_name) 元组。
- os.path.getsize(file) 返回指定文件大小,单位是字节。
- os.path.getatime(file) 返回指定文件最近的访问时间。
- os.path.getctime(file) 返回指定文件的创建时间。
- os.path.getmtime(file) 返回指定文件的最新的修改时间。
- 浮点型秒数,可用time模块的 gmtime() 或 localtime() 函数换算。
- os.path.exists(path) 判断指定路径(目录或文件)是否存在。
- os.path.isabs(path) 判断指定路径是否为绝对路径。
- os.path.isdir(path) 判断指定路径是否存在且是一个目录。
- os.path.isfile(path) 判断指定路径是否存在且是一个文件。
- os.path.islink(path) 判断指定路径是否存在且是一个符号链接。
- os.path.ismount(path) 判断指定路径是否存在且是一个悬挂点。
- os.path.samefile(path1,path2) 判断path1和path2两个路径是否指向同一个文件。
19、序列化和反序列化
Python 的 pickle 模块实现了基本的数据序列和反序列化。
- 通过 pickle 模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
- 通过 pickle 模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。
pickle模块中最常用的函数为:
pickle.dump(obj, file, [,protocol]) 将 obj 对象序列化存入已经打开的 file 中。
- obj :想要序列化的 obj 对象。
- file :文件名称。
- protocol :序列化使用的协议。如果该项省略,则默认为0。如果为负或 HIGHEST_PROTOCOL ,则使用最高的协议版本。
pickle.load(file) 将 file 中的对象序列化读出。
- file :文件名称。
总结
通过本次学习,使我对Python基础语法体系有了全新的认识和体会,巩固了基础语法知识。
Python基础语法笔记相关推荐
- python基础语法笔记,这是我四进宫了,再学不进去我就自宫了!!!!
学了四回了,基础视频是换了又换,但是一到稍微进阶一点就弄不懂了,所以这次我打算踏下心来,好好的总结一下基础语法. FBI Warning: 由于避免犯困,我使用了不当言辞,18岁以下禁止观看! 没有讲 ...
- Python基础语法笔记(十六)文件与文件系统
Reference https://github.com/datawhalechina/team-learning-program/blob/master/PythonLanguage 1. 文件与文 ...
- Python基础语法学习笔记
Python基础语法学习笔记 想淘宝省钱看我简介,博客www.liangxin.name (一) 一.Print()函数 1.数字可以直接输出,无需加引号 只能理解数字,却读不懂文字.因为数字和数学运 ...
- 【学习笔记】5、Python基础语法
Python基础语法 [准备工作] 我们在Jupyter notebook里面New一个Python3就可以开始愉快的练习了. 一.数字和字符串的定义方法 a = 100 #赋值语 ...
- Python基础语法毕业笔记-最简单的添加删除程序
学了接近2天Python基础语法,感觉差不多了可以去看Python源码了,做一个基础语法毕业的小程序, 程序运行截图如下: 对应的文本文件如下: 程序结构如下: 源码如下: File.py from ...
- 数学分析笔记—python基础语法
文章目录 1.Python基础语法思维导图 2.补充:python变量的关键字 3.补充:python常用数据类型转换 4.补充:print的格式化输出 1.Python基础语法思维导图 2.补充:p ...
- 【Python基础】Python基础语法14个知识点大串讲
作者:来自读者投稿 来源:Python数据之道 Python基础语法大串讲 Python 是一门面向对象的编程语言,相信这篇文章对于初学者而言应该会有一个比较大的帮助,下面我们将 Python 中常用 ...
- Python基础入门笔记(二)
前言 本文主要为 Python基础入门笔记(一)内容的补充. 一.迭代器和生成器 1.1 Python迭代器 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元 ...
- Python基础学习笔记之(一)
Python基础学习笔记之(一) zouxy09@qq.com http://blog.csdn.net/zouxy09 前段时间参加微软的windows Azure云计算的一个小培训,其中Pytho ...
最新文章
- 【java】用户动态代理
- [算法笔记] 爬楼梯
- 用python处理excel 数据分析_Python应用实现处理excel数据过程解析
- Java 基于 UDP 实现 Socket中的多客户端通信
- 数学--数论--POJ 1061青蛙的约会 (扩展欧几里得算法)
- js重新渲染div_前端工程师必备:从浏览器的渲染到性能优化
- react 消息队列_具有AkkaReact流的React队列
- 百度CDN与360CDN简单评测,果断选择百度CDN
- 程序员私活app排行_iOS程序员,失业就等于成为废人?
- 每天花30分钟看OGRE--(13)Ogre的渲染流程,在渲染时材质是如何起作用的,材质加载和解析...
- gevent实现套接字
- spring的注入和直接new一个对象有什么不同?
- redis击穿、redis雪崩、redis穿透
- 第二课:如何选择适合做小程序的服务器及域名?
- 贴吧自动签到脚本linux,【渣作】shell脚本百度贴吧签到器
- 【游记】记清北学堂国庆刷题班
- java 标点符号_java的标点符号
- Kotlin语言内置函数学习2:with,also,takeIf,takeUnless
- 从招股书看蚂蚁集团的技术底色
- 3)数据科学的数学之序列与极限--阶乘/指数增长比较