PYTHON入门
参考这个视频链接
python的执行入口
if __name__ == `__main__`:
可执行语句
1. 计算机基础
计算机的组成
- 硬件
- 操作系统
- 软件(应用程序)
2. 数据类型
2.1 数字类型
2.1.1 整型 int
整型,整数
v1 = 5
# v1.bit_length()获取v1的二进制由多少个位组成
result = v1.bit_length() #result = 3
python 2与python 3关于整型的区别:
-
长整型
- python 3:整型(无限制)
- python 2:整型(int)、长整型(long)
-
地板除
-
python 3:
v1 = 9/2 print(v1) # 4.5
-
python 2:
v1 = 9/2 print(v1) # 4
from __future__ import division v1 = 9/2 print(v1) # 4.5
-
2.1.2 浮点型 float
表示小数
'''
内置函数--type
返回变量的类型
'''
count = 1050
print(type(count))
-
保留小数点后n位
v = 3.1415926 result = round(v, 2) print(result) # 3.14
-
浮点型的坑
# 计算不精确 v1 = 0.1 v2 = 0.2 v3 = v1 + v2 print(v3) # 0.30000000000000004 # 精确的小数计算 import decimal v1 = decimal.Decimal("0.1") v2 = decimal.Decimal("0.2") v3 = v1 + v2 print(v3) # 0.3
2.2 字符串类型 str
通过" "
、' '
或者""" """
、 ''' '''
装饰起来。
对于字符串:
- 加, 将两个字符串拼接起来;
- 乘,整型和字符串可以相乘,实现让字符串重复出现N次并拼接起来。
2.2.1 .startswith("xx")
判断字符串是否以xx开头
v1 = "Hello world!"
result = v1.startswith("Hello")
print(result) # True
2.2.2 .endswith("xxx")
判断字符串是否以xx结尾
v1 = "Hello world!"
result = v1.endswith("!")
print(result) # True
2.2.3 .isdecimal()
判断字符串是否为整数
v1 = "123"
result = v1.isdecimal()
print(result) # True
注释:
v1.isdigit()
也可以判断,但是会把①的结果也返回TRUE。
2.2.4 .strip()
去除字符串两边的空格、换行符\n
、制表符\t
,返回一个新的字符串
v1 = " 123 "
result = v1.strip()
print(result) # "123"
result = v1.lstrip()
print(result) # "123 "
result = v1.rstrip()
print(result) # " 123"
补充:
-
v1.strip("xx")
去除字符串两边指定的内容xx -
v1.lstrip("xx")
去除字符串左边指定的内容xx -
v1.rstrip("xx")
去除字符串右边指定的内容xx
2.2.5 .upper()
将字符串变大写,返回一个新的字符串
v1 = "Hello world!"
result = v1.upper()
print(result) # HELLO WORLD!
2.2.6 .lower()
将字符串变小写,返回一个新的字符串
v1 = "Hello world!"
result = v1.lower()
print(result) # hello world!
2.2.7 .replace("xx", "**")
将字符串中的xx替换成**,返回一个新的字符串
2.2.8 .split("xx")
将字符串以xx切割,返回一个列表
v1 = "Hello world !"
result = v1.split(" ")
print(result) # ["Hello", "world", "!"]
result = v1.split(" ", 1)
print(result) # ["Hello", "world !"]
补充:
v1.rsplit("")
将字符串从后往前切割,返回一个列表
2.2.9 .join()
将字符串、列表、元组等拼接,返回一个新的字符串
data_list = ["Hello", "world", "!"]
v1 = " ".join(data_list)
print(v1) # "Hello world !"
2.2.10 .center()
将字符串居中、居左、居右展示
v1 = "hello"
# 居中
result = v1.center(20, "*")
print(result) # *******hello********
# 居左
result = v1.ljust(20, "*")
print(result) # hello***************
# 居右
result = v1.rjust(20, "*")
print(result) # ***************hello
2.2.11 .zfill(8)
填充0,返回一个新的字符串
2.2.12 常用功能
# 1. 相加:字符串 + 字符串
v1 = "hello" + "world"
print(v1) # hello world
# 2. 相乘:字符串 * 整数
v2 = "hello" * 3
print(v2) # hellohellohello
# 3. 字符串长度
v3 = "hello"
print(len(v3)) # 5
# 4. 按照索引获取字符串中的对应字符
v4 = "hello"
print(v4[0]) # h
print(v4[-1]) # o
# 5. 获取字符串中的子序列
v5 = "hello"
print(v5[0:2]) # he
# 6. 步长
v6 = "hello"
# v6[0:5:2]中0:5表示区间范围[0,5),2表示步长
print(v6[0:5:2]) # hlo
# v6[::-1]中::表示区间范围为整个字符串,-1表示逆序为1的步长
print(v6[::-1]) # olleh
2.3 布尔类型 bool
True/False
-
整型和字符串无法比较大小。
-
整型、字符串、列表、字典转布尔类型时,除了0、空字符串、空列表、空字符串其他都是
True
。
2.4 空类型 None
表示空,一定程度上可以节省内存
2.5 列表类型 list
用于存储一些数据的容器(有序&可修改)
2.5.1 .append(xx)
将xx添加到列表中,并返回给列表
data_list = []
data_list.append(1)
print(data_list) # [1]
2.5.2 .extend(xx)
将xx列表内容逐一添加到列表中,并返回给列表
data_list = [1,2]
num_list = [3,4]
data_list.extend(num_list)
print(data_list) # [1, 2, 3, 4]
2.5.3 .insert(num, xx)
将xx内容插入到列表的索引num位置,并返回给列表
2.5.4 .remove(xx)
将列表中的xx删除,并返回给列表,如果列表内不包含xx,则程序会报错
2.5.5 .pop(num)
根据索引num删除列表对应位置内容,并返回给列表
num_list = [1, 2, 3, 4]
# num_list.pop()里面不写索引默认删除最后一个,并将删除的值返回
num = num_list.pop()
print(num) # 4
print(num_list) # [1, 2, 3]
2.5.6 .clear(num)
清空列表,并返回给列表
2.5.7 .index(xx)
获取xx值在列表中的索引,并返回索引值
2.5.8 .sort()
对列表进行从小到大排序,并返回给列表
注:1. 列表内部元素数据类型不统一时,程序可能会报错。
2. .sort(reverse=True)
:将列表从大到小排序。
2.5.9 .reverse()
对列表进行反转,并返回给列表
2.5.10 常用功能
# 1. 相加:列表 + 列表
v1 = ["hello"] + ["world"]
print(v1) # ["hello", "world"]
# 2. 相乘:列表 * 整数
v2 = ["hello"] * 3
print(v2) # ["hello", "hello", "hello"]
# 3. in,判断元素是否在列表中
v3 = ["hello", "world"]
result = "hello" in v3
print(result) # True
# 4. 获取列表长度
v4 = ["hello", "world"]
print(len(v4)) # 2
# 5. 索引
v5 = ["hello", "world"]
print(v5[0]) # "hello"
v5[0] = "world" # 修改列表元素
del v5[1] # 删除列表元素
print(v5) # ["world"]
# 6. 切片
v6 = ["hello", "world", "!", "!"]
print(v6[0:2]) # ["hello", "world"]
v6[0:2] = ["?", "?"] # 修改列表元素
del v6[2:] # 删除列表元素
print(v6) # ["?", "?"]
# 7. 步长
v7 = ["hello", "world", "!", "!"]
# v7[0:3:2]中0:3表示区间范围[0,3),2表示步长
print(v7[0:3:2]) # ["hello", "!"]
# v7[::-1]中::表示区间范围为整个字符串,-1表示逆序为1的步长
new_list = v7[::-1]
print(new_list) # ["!", "!", "world", "hello"]
**注意:**如果要边循环边删除列表中的元素,使用索引并且倒着处理。正序处理会忽略一些元素。
2.5.11 嵌套
列表内部可以嵌套列表。
2.6 元组类型 tuple
用于存储一些数据的容器(有序&不可修改),可以存放多个不同类型的元素。
**注意:**建议在元组的最后多加一个逗号,用于标识它是一个元组。
2.6.1 常用功能
# 1. 相加: 元组 + 元组
v1 = ("hello",) + ("world",)
print(v1) # ("hello", "world")
# 2. 相乘: 元组 * 整数
v2 = ("hello",) * 3
print(v2) # ("hello", "hello", "hello")
# 3. in,判断元素是否在元组中
v3 = ("hello", "world")
result = "hello" in v3
print(result) # True
# 4. 获取元组长度
v4 = ("hello", "world")
print(len(v4)) # 2
# 5. 索引
v5 = ("hello", "world")
print(v5[0]) # "hello"
# 6. 切片
v6 = ("hello", "world", "!", "!")
print(v6[0:2]) # ("hello", "world")
# 7. 步长
v7 = ("hello", "world", "!", "!")
# v7[0:3:2]中0:3表示区间范围[0,3),2表示步长
print(v7[0:3:2]) # ("hello", "!")
# v7[::-1]中::表示区间范围为整个字符串,-1表示逆序为1的步长
new_list = v7[::-1]
print(new_list) # ("!", "!", "world", "hello")
**注意:**其他类型转换为元组,使用tuple(类型),只有字符串、列表可以转换成元组。
2.7 字典类型 dict
一个无序、键不重复、元素是键值对的可变的容器
注:Python3.6+之后的字典是有序的。
2.7.1 定义
字典中对键值的要求:
- 键:可哈希;
- 值:任意类型。
2.7.2 获取值
info = {
"name": "lalala"
"age": 12
}
data1 = info.get("name")
print(data1) # "lalala"
data2 = info.get("age")
print(data2) # 12
data3 = info.get("email")
print(data3) # None
data4 = info.get("email", 123)
print(data4) # 123
2.7.3 获取键
info = {
"name": "lalala"
"age": 12
}
data = info.keys()
print(data) # dict_keys(["name", "age"])
**注意:**在Python2中字典.key()直接获取到的是列表,而Python3中返回的是高仿列表
2.7.4 获取所有值
info = {
"name": "lalala"
"age": 12
}
data = info.values()
print(data) # dict_values(["lalala", 12])
**注意:**在Python2中字典.values()直接获取到的是列表,而Python3中返回的是高仿列表
2.7.5 获取所有的键值对
info = {
"name": "lalala"
"age": 12
}
data = info.items()
print(data) # dict_items([("name", lalala"), ("age", 12)])
2.7.6 .setdefault()
更新或者添加键值对,并返回给字典。
2.7.7 .update()
批量更新或者添加键值对,并返回给字典。
2.7.8 .pop("key")
移除指定键值对,并返回移除后的值。
2.7.9 .popitem()
按顺序移除键值对,并返回移除后的键值对(元组类型)。
- Python3.6+,移除最后的键值对。
- Python3.6之前,随机某个删除键值对。
2.7.10 并集
Python3.9新加入的。
info1 = {
"name1": "lalala"
"age1": 12
}
info2 = {
"name2": "hahaha"
"age2": 14
}
info = info1 | info2 # 取两个字典的并集,并返回一个新字典
print(info) # {"name1": "lalala", "age1": 12, "name2": "hahaha", "age2": 14}
2.7.11 其他
- 存储原理
- 利用哈希函数将键转换成数值;
- 取余数;
- 根据得到的余数将元素放在对应索引位置。
- 查找速度快
- 字典的键必须可哈希
2.8 集合类型 set
一个无序、可变、不允许数据重复的容器
2.8.1 定义
v1 = set() # 定义一个空集合
v2 = {1, 2} # 定义一个集合
2.8.2 .add(xx)
添加元素,并返回给集合
2.8.3 .discard(xx)
删除元素,并返回给集合
2.8.4 交集
v1 = {1, 2, 3, 4}
v2 = {3, 4, 5, 6}
v3 = v1.intersection(v2) # 取两个集合的交集,并返回一个新集合
v4 = v1 & v2 # 取两个集合的交集,并返回一个新集合
print(v3) # {3, 4}
print(v4) # {3, 4}
2.8.5 并集
v1 = {1, 2, 3, 4}
v2 = {3, 4, 5, 6}
v3 = v1.union(v2) # 取两个集合的并集,并返回一个新集合
v4 = v1 | v2 # 取两个集合的并集,并返回一个新集合
print(v3) # {1, 2, 3, 4, 5, 6}
print(v4) # {1, 2, 3, 4, 5, 6}
2.8.6 差集
v1 = {1, 2, 3, 4}
v2 = {3, 4, 5, 6}
v3 = v1.difference(v2) # 取两个集合的差集,并返回一个新集合
v4 = v1 - v2 # 取两个集合的差集,并返回一个新集合
print(v3) # {1, 2}
print(v4) # {1, 2}
2.8.7 常用功能
# 计算长度
v1 = {1, 2, 3, 4}
print(len(v1)) # 4
# for循环
for item in v:
print(item)
# 类型转换
# set()将其他类型转换为集合类型,如果数据有重复自动剔除
v2 = (11, 11, 22, 22)
v3 = set(v2)
print(v3) # {11, 22}
2.8.8 其他
-
集合的存储原理
- 利用哈希函数将集合的元素转换成数值;
- 取余数;
- 根据得到的余数将元素放在对应索引位置。
-
元素必须可哈希
集合的元素必须是可哈希的值,所以集合的元素只能是int、bool、str、tuple
-
查找速度特别快
-
True & False
由于True & False本质上存储是1 & 0,而集合又不允许重复,所以在整数0、1和False、True出现在集合中会有如下四种 现象:
v1 = {True, 1} print(v1) # {True} v2 = {1, True} print(v2) # {1} v3 = {False, 0} print(v3) # {False} v4 = {0, False} print(v4) # {0}
3. 变量
命名规范
- 变量只能由字母、数字、下划线组成;
- 不能以数字开头;
- 不能用Python内置关键字。
4. 字符串格式化
4.1 %
- 示例1
name = "peiqi"
text = "My name is %s" %name
- 示例2
name = "peiqi"
age = "3"
text = "My name is %s, and I am %d years old." %(name, age)
- 示例3
name = "peiqi"
age = "3"
text = "My name is %(name)s, and I am %(age)d years old." %{"name":name, "age":age}
- 示例4
text = "My name is %s, and I am %d years old."
data1 = text %("peiqi", "3")
data2 = text %("qiaozhi", "2")
字符串格式化中存在百分比的显示,写成%%
。
4.2 format
- 示例1
text = "My name is {}, and I am {} years old.".format("peiqi", "3")
- 示例2
text = "My name is {0}, and I am {1} years old.I am {0}.".format("peiqi", "3")
- 示例3
text = "My name is {name}, and I am {age} years old.I am {name}.".format(name="peiqi", age="3")
- 示例4
text = "My name is {name}, and I am {age} years old."
data1 = text.format(name="peiqi", age="3")
data2 = text.format(name="qiaozhi", age="2")
4.3 f
python 3.6版本及以上可以使用。
- 示例1
name = "peiqi"
age = "3"
text = f"My name is {name}, and I am {age} years old."
- 示例2
text = f"My name is peiqi, and I am {1 + 2} years old."
- 示例3
python 3.8版本及以上可以使用。
text = f"My name is peiqi, and I am {1 + 2 = } years old."
- 示例4
name = "peiqi"
age = "3"
text = f"My name is {name.upper()}."
5. 运算符
5.1 算数运算符
运算符 | 描述 |
---|---|
+ | 相加 |
- | 相减 |
* | 相乘或者字符串重复n次 |
/ | 除 |
% | 取余 |
** | 幂运算 |
// | 相除得到商的整数部分 |
5.2 比较运算符
运算符 | 描述 |
---|---|
== | 等于 |
!= | 不等于 |
<> | 不等于(python3 不支持) |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
5.3 赋值运算
运算符 | 描述 |
---|---|
= | 赋值 |
+= | 相加后赋值 |
-= | 相减后赋值 |
*= | 相乘后赋值 |
/= | 相除后赋值 |
%= | 取余后赋值 |
**= | 幂运算后赋值 |
//= | 相除得到商的整数部分后赋值 |
5.4 成员运算
运算符 | 描述 |
---|---|
in | 如果在指定的序列中找到值返回True,否则返回False |
not in | 如果在指定的序列中没有找到值返回True,否则返回False |
5.5 逻辑运算
运算符 | 描述 |
---|---|
and | 与 |
or | 或 |
not | 非 |
# 1. 将and前后的值转化为布尔值
# 2. 前面是True,就取后面的值;前面是False,就取前面的值
v1 = "peiqi" and "qiaozhi" #v1 = "qiaozhi"
v2 = "" and "qiaozhi" #v2 = ""
# 1. 将or前后的值转化为布尔值
# 2. 前面是True,就取前面的值;前面是False,就取后面的值
v3 = "peiqi" or "qiaozhi" #v3 = "peiqi"
v4 = "" and "qiaozhi" #v4 = "qiaozhi"
5.6 is
和==
-
is
:用于表示内存地址是否一致 -
==
:用于比较两个值是否相等
5.7 位运算
-
&
:与 -
|
:或 -
^
:异或 -
~
:取反 -
<<
:左移 -
>>
:右移
6. 文件操作
6.1 读文件
# 1. 打开文件
file_obj = open('info.txt', mode='rb')
# 2. 读取文件
data = file.obj.read()
# 3. 关闭文件
file.obj.close()
6.2 写文件
# 1. 打开文件
file_obj = open('info1.txt', mode='wb')
# 2. 文件写入
file.obj.write("hello world".encode("utf-8"))
# 3. 关闭文件
file.obj.close()
# 1. 打开文件
# 默认以utf-8的格式写入
file_obj = open('info2.txt', mode='wt', encoding="utf-8")
# 2. 文件写入
file.obj.write("hello world")
# 3. 关闭文件
file.obj.close()
6.3 文件打开模式
模式 | 操作 |
---|---|
r | open for reading (default) |
w | open for writing, truncating the file first |
x | create a new file and open it for writing |
a | open for writing, appending to the end of the file if it exitsts |
b | binary mode |
t | text mode (default) |
+ | open a disk file for updating (reading and writing) |
6.4 常见功能
6.4.1 .read()
.read()
读所有.read(n)
读n个字符(字节)
6.4.2 .readline()
读一行
6.4.3 .readlines()
读所有行,返回列表
6.4.4 .write()
写(先将内容写的缓冲区,系统再将缓冲区的内容刷到硬盘)
6.4.5 .flush()
立即将缓冲区的内容刷到硬盘
6.4.6 .seek()
移动光标到n个字节的位置
**注:**在a模式下,调用write在文件中写入内容时,只能将内容写到文件尾部。
6.4.7 .tell()
获取光标的位置(字节的位置)
6.5 上下文管理
with open("xxx.txt", mode='rb') as f:
pass
6.6 ini格式
import configparser
config = configparser.ConfigParser()
config.read('my.ini', encoding='utf-8')
# 读取所有节点
ret = config.sections()
# 读取xxx节点下面的键值
item_list = config.items("xxx")
# 读取xxx节点下xx键的值
result = config.get("xxx", "xx")
# 判断是否存在xx节点
v1 = config.has_section("xx")
# 添加group节点
config.add_section("group") # 只是把数据写入内存中
# 添加group节点下的键值
config.set('group', 'name', 'Tom')
config.write(open('my.ini', mode='w', encoding='utf-8')) # 将内存数据存入文件中
# 删除group节点
config.remove_section("group") # 只是把数据写入内存中
# 删除xxx节点下的键值xxx
config.set('xxx', 'xxx')
config.write(open('my.ini', mode='w', encoding='utf-8')) # 将内存数据存入文件中
6.7 压缩文件
import shutil
# 1. 压缩文件
"""
# base_name, 压缩后的压缩包文件
# format, 压缩的格式,"zip", "tar", "gztar", "bztar", "xztar"
# root_dir, 要压缩的文件夹路径
shutil.make_archive(base_name=r"D:\xxx\xxx\xxx", format="zip", root_dir=r"D:\xxx\xxx")
"""
# 2. 解压文件
"""0
# filename, 要解压的压缩包文件
# format, 压缩文件格式
# extract_dir, 解压的路径,目录不存在会创建目录
shutil.unpack_archive(file_name=r"D:\xxx\xxx\xxx.zip", extract_dir=r"D:\xxx\xxx", format="zip")
"""
6.8 文件路径
import os
import shutil
# 获取当前所执行脚本的上一级文件夹目录
base_dir = os.path.dirname(os.path.abspath(__file__))
# 路径拼接,为了在window和linux通用
file_path = os.path.join(base_dir, 'files', 'info.txt')
# 判断文件路径是否存在
result = os.path.exists(file_path)
# 创建文件夹
os.makedir(file_path)
# 删除文件夹
shutil.rmtree(file_path)
"""
# 拷贝文件夹
shutil.copytree("original_folder_path", "destination_folder_path")
# 拷贝文件
shutil.copy("original_file_path", "destination_file_path")
# 文件夹或文件重命名
shutil.copy("original_file_name", "destination_file_name")
"""
7 函数
7.1 参数
7.1.1 默认参数
- 位置传参
- 关键字传参
7.1.2 动态参数
-
def func(*args)
位置传参,args会被封装成一个元组
-
def func(**kwargs)
关键字传参,kwargs会被封装成一个字典
注:函数执行传参时,传递的是内存地址。
7.2 返回值
- return后面的值如果有逗号,则默认将返回值转换成元组再返回
- 函数一旦遇到return就会立即退出函数
- 函数的返回值是内存地址
7.3 函数作元素
-
函数可被哈希,所以函数名可以当作元组、列表、集合的元素、字典的键。
-
函数可以做参数和返回值
7.4 作用域
Python以函数为作用域,所以在函数内创建的所有数据,可以在此函数中被使用,无法在其他函数中被使用。
7.4.1 全局和局
函数的作用域是局部作用域。
**注:**全局变量一般都是大写。
7.4.2 global关键字
默认情况下,在局部作用域对全局变量只能进行:读取和修改内部元素(可变类型),无法对全局变量进行重新赋值。
可以基于global
关键字实现。
7.5 函数的嵌套
嵌套引发的作用域问题:
- 优先在自己的作用域找,自己没有就去上级作用域。
- 在作用域中寻找值时,要确保此次此刻值是什么。
- 分析函数的执行,并确定函数的
作用域链
。(函数嵌套)
7.6 闭包
多线程
from concurrent.futures.thread import ThreadPoolExecutor
def task():
pass
def outer(args):
def done():
pass
return done
# 线程池10个
POOL = ThreadPoolExecutor(10)
for i in range(3):
# 取一个线程执行task函数
future = POOL.submit(task)
# 线程执行完会执行的函数
future.add_done_callback(outer(i))
7.7 装饰器
@函数名
# Python内部会自动执行 函数名(xxx),执行完之后,将结果赋值给xxx。
# xxx = 函数名(xxx)
@函数名
def xxx():
pass
注:
-
基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。
-
可以在不改变原函数内部代码和调用方式的前提下,实现在函数执行和执行扩展功能。
-
适用场景:多个函数系统统一在执行前后自定义一些功能。
-
示例(面试很重要(⊙o⊙)):
def outer(origin): def inner(*arg, **kwargs): # 执行前 res = origin(*arg, **kwargs) # 调用原来的func函数 # 执行后 return res return inner @outer def func(): pass func()
-
升级( •̀ ω •́ )
def func(): """这是一个xxx的函数 """ pass # 获取函数名 print(func.__name__) # "func()" # 获取函数的注释 print(func.__doc__) # "这是一个xxx的函数"
函数加了装饰器之后,在使用
函数名.__name__
、函数名.__doc__
得到的是装饰器里面的对应的函数名和注释,如果想得到原来函数名和注释,可以引入functools(装饰器最好都这样写)。import functools def auth(func): @functools.warps(func) def inner(*args, **kwargs): # 执行前 res = func(*arg, **kwargs) # 调用原来的func函数 # 执行后 return res return inner @auth def admin(): """这是一个xxx的函数 """ pass # 获取函数名 print(func.__name__) # "func()" # 获取函数的注释 print(func.__doc__) # "这是一个xxx的函数"
7.8 匿名函数
越来越抽象了/(ㄒoㄒ)/
基于lambda表达式实现定义一个可以没有名字的函数:lambda 参数:函数体
- 参数:支持任意参数;
- 函数体:只能支持单行的代码;
- 返回值:默认将函数的单行代码执行结果作为函数的返回值。
在编写匿名函数时,由于受限,函数体只能写一行,所以匿名函数只能处理非常简单的功能。
7.9 三元运算
简单的条件语句,可以基于三元运算实现。
结果 = 条件成立时 if 条件 else 不成立
7.10 生成器
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用**next()函数和send()**函数恢复生成器。
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器。
示例:
#只有把一个列表生成式的[]中括号改为()小括号,就创建一个generator
#列表生成式
lis = [x*x for x in range(10)]
print(lis)
#生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x000002A4CBF9EBA0>
generator保存的是算法,每次调用next(generaotr_ex)就计算出他的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误,而且上面这样不断调用是一个不好的习惯,正确的方法是使用for循环,因为generator也是可迭代对象:
#生成器
generator_ex = (x*x for x in range(10))
for i in generator_ex:
print(i)
结果:
0
1
4
9
16
25
36
49
64
81
7.10.1 generator和函数的执行流程
-
函数:顺序执行,遇到return语句或者最后一行函数语句就返回。
-
generator函数:在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时候从上次的返回yield语句处急需执行,也就是用多少,取多少,不占内存。
-
生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始
-
生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果
-
import random
def gen_random_num(max_count):
counter = 0;
while counter < max_count:
yield random.randint(1000,9999)
counter += 1
data_list = gen_random_num(3000000)
# 使用时,去data_list获取即可
n1 = next(data_list)
7.11 内置函数
7.11.1 abs()
绝对值
7.11.2 pow()
指数
v1 = pow(2,5) #2 ** 5
print(v1) # 32
7.11.3 sum()
求和,参数可以被迭代
7.11.4 divmod()
商和余数
v1, v2 = divmod(9,2) #分别返回9除以2的商和余数
print(v1, v2) # 4, 1
7.11.5 round()
保留小数点后n位
v1 = round(3.1415, 2) #保留小数点后2位
print(v1) # 3.14
7.11.6 min()
最小值
7.11.7 max()
最大值
7.12 推导式
7.12.1 列表推导式
variable = [out_exp_res for out_exp in input_list if out_exp == 2]
- out_exp_res:列表生成元素表达式,可以是有返回值的函数。
- for out_exp in input_list:迭代input_list将out_exp传入out_exp_res表达式中。
- if out_exp == 2:根据条件过滤哪些值可以。
7.12.2 字典推导式
{ key_expr: value_expr for value in collection if condition }
7.12.3 集合推导式
{ expr for value in collection if condition }
7.12.4 元组推导式
( expr for value in collection if condition )
返回一个生成器
示例
info = {
'sign_type': "MD5",
'out_refund_no': "12323",
'appid': "wx55cca",
'mch_id': "15264",
'total_fee': "9900",
'refund_fee': "10000",
}
data = "&".join(["{}={}".format(k, v) for k,v in sort(info.items(), key=lambda x: x[0])])
print(data)
高级烧脑🤔
def num():
return [lambda x: i * x for i in range(4)]
# 1. num()并获取返回值 [函数, 函数, 函数, 函数] i=3
# 2. for循环返回值
# 3. 返回值的每个元素执行(2)
result = [m(2) for m in num()]
print(result) # [6, 6, 6, 6]
def num():
return (lambda x: i * x for i in range(4))
# 1. num()并获取返回值 生成器对象
# 2. for循环返回值0
# 3. 返回值的每个元素执行(2)
result = [m(2) for m in num()]
p0rint(result) # [0, 2, 4, 6]
8 模块
在Python中一般对文件夹和文件的称呼:
- .py文件,模块(module);
- 包含多个py文件的文件夹,包(package)。
注意:在包(文件夹)中有一个默认内容为空的__init__.py
的文件,一般用于描述当前包的信息。
- py2必须有,如果没有导入包会报错;
- py3可有可无。
8.1 导入
当定义好一个模块或包之后,如果想要使用其中定义的功能,必须要先导入,然后再能使用。
导入,其实就是将模块或包加载到内存中,以后再去内存中中去拿就行。
导入时的路径:
在python内部默认设置了一些路径,导入模块或包时,都会按照指定顺序逐一去特定的路径查找。
import sys
print(sys.path) # 在导入模块或包时,python内部默认设置的查找路径
# 想要导入任意的模块和包,都必须写在如下路径下,才能被找到。
# 也可以手动在sys.path中添加指定路径,然后再导入即可。
sys.path.append("路径xxx")
1. 项目执行文件一般都在根目录。
2. pycharm中默认会将项目目录加入到sys.path中。
8.1.1 import
和from
两种都支持as别名。
import
:项目根目录的包模块级别的导入。
from
:成员、嵌套的包模块导入。
- 导入成员,
from 包 import 成员
,成员导入不会节省内存 - 导入模块,
from 模块 import 模块
- 导入包,
from 模块 import 包
8.1.2 相对导入
相对导入只能用在包中的py文件中(即:嵌套在文件中的py文件才可以使用,项目根目录下无法使用)。
8.1.3 主文件
# 1. 执行一个py文件时
__name__ = "main"
# 2. 导入一个py文件时
__name__ = "模块名"
8.2 第三方模块
8.2.1 pip
-
安装pip
-
下载
get-pip.py
文件,到任意目录;地址: https://bootstrap.pypa.io/get-pip.py
-
打开终端进入目录,用python解释器去运行已下载的
get-pip.py
文件即可安装成功。python3 get-pip.py
-
-
pip导入第三方模块
只需要在终端执行:
pip install 模块名称==版本
即可。 -
换源
-
一次性使用
pip install 模块名称 -i 国内源
-
永久使用
-
配置
# 在终端执行如下命令 pip config set global.index-url https://pypi.douban.com/simple/ # 执行完成后,提示在本地文件中写入了豆瓣源,以后再通过pip去安装第三方模块时,就会默认使用豆瓣源了 # 或者也可以打开文件直接修改源地址 Writing to /Users/xxx/.config/pip/pip.conf
-
使用
pip install 模块名称
-
-
8.2.2 源码安装
-
下载requests源码(压缩包zip、tar、tar.gz)并解压
下载地址:https://pypi.org/project/requests/
-
进入目录
-
执行编译和安装命令
python3 setup.py build python3 setup.py install
8.2.3 wheel
-
安装wheel格式支持
pip3.9 install wheel
-
下载第三方的包(wheel格式)
-
进入下载目录,在终端基于pip直接安装
pip3.9 install xxx.whl
8.3 内置模块
8.3.1 os
import os
# 1. 获取当前脚本绝对路径
abs_path = os.path.abspath(__file__)
# 2. 获取当前文件的上级目录
base_path = os.path.diename(abs_path)
# 3. 路径拼接
join_path = os.path.join(base_path, "xxx")
# 4. 判断路径是否存在
exists = os.path.exists(join_path)
# 5. 创建文件夹
os.makedirs("xxxx/xxxx/xxxx/xxxx")
# 6. 是否是文件
is_dir = os.path.isdir(base_path)
# 7. 删除文件或文件夹
os.remove("xxxx/xxxx/xxxx/xxxx")
-
listdir,查看目录下所有的文件
-
walk,查看目录下所有的文件(包含子孙文件)
import os data = os.walk("xxxxxx") for path, folder_list, file_list in data: pass
8.3.2 shutil
import shutil
# 1. 删除文件夹
path = os.path.join(os.path.abspath(__file__), "xx")
shutil.rmtree(path)
# 2. 拷贝文件夹
shutil.copytree("xxx/xxx/", "xxx/xxx/xxx")
# 3. 拷贝文件
shutil.copy("xxx/xxx/xxx", "xxx/xxx/xxx")
# 4. 文件或文件夹重命名
shutil.move("xxx/xxx/xxx", "xxx/xxx/xxxxxx")
# 5. 压缩文件
"""
base_name, 压缩后的压缩包文件
format, 压缩的格式,例如:"zip", "tar", "gztar", "bztar", or "xatar"
root_dir,要压缩的文件夹路径
"""
shutil.make_archive(base_name="xxx", format="zip", root_dir="xxx/xxx")
# 6. 解压文件
"""
filename, 要解压的压缩包文件
extract_dir, 解压的路径
format, 压缩文件的格式
"""
shutil.unpack_archive(file_name="xxx", extract_dir="xxx/xxx", format="zip")
8.3.3 sys
import sys
# 1. 获取解释器版本
print(sys.version)
print(sys.version_info)
print(sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
# 2. 导入模块路径
print(sys.path)
# 3. 执行脚本时,python解释器后面传入的参数
print(sys.argv)
8.3.4 random
import random
# 1. 获取范围内的随机整数
v = random.randint(10, 20)
print(v)
# 2. 获取范围内的随机小数
v = random.uniform(10, 20)
print(v)
# 3. 随机抽取一个元素
v = random.choice([10, 20, 30, 40, 50])
print(v)
# 4. 随机抽取多个元素
v = random.sample([10, 20, 30, 40, 50], 3)
print(v)
# 5. 打乱顺序
data = [10, 20, 30, 40, 50]
random.shuffle(data)
print(data)
8.3.5 hashlib
import hashlib
# 加密
hash_object = hashlib.md5("ghhh".encode("utf-8"))
hash_object.update("啦啦啦".encode("utf-8"))
result = hash_object.hexdigest()
print(result)
8.4 json
跨语言传输
-
数据类型 --> json,一般称为:序列化
import json data = [ {"id":1, "name":"lalala", "age":18}, {"id":2, "name":"xixixi", "age":16}, ] res = json.dumps(data) print(res) res = json.dumps(data, ensure_ascii=False) print(res)
-
json --> 数据类型,一般称为:反序列化
import json data = '[{"id":1, "name":"lalala", "age":18}, {"id":2, "name":"xixixi", "age":16}]' data_list = json.loads(data_string) print(data_list)
-
json.dump
,将数据序列化并写入文件import json data = [ {"id":1, "name":"lalala", "age":18}, {"id":2, "name":"xixixi", "age":16}, ] file_object = open('xx.json', mode='w', encoding='utf-8') json.dump(data, file_object) file_object.close()
-
json.load
,读取文件中的数据并反序列化为python的数据类型import json file_object = open('xx.json', mode='r', encoding='utf-8') data = json.load(file_object) print(data) file_object.close()
8.5 时间处理
- UTC/GMT:世界时间
- 本地时间
8.5.1 time
import time
# 获取当前时间戳
v1 = time.time()
print(v1)
# 时区
v2 = time.timezone
# 停止3s,再执行后续的代码
time.sleep(3)
8.5.2 datetime
-
datetime
from datetime import datetime, timezone, timedelta v1 = datetime.now() # 当前本地时间 print(v1) v2 = datetime.uctnow() # 当前UTC时间 print(v2) tz = timezone(timedelta(hours=7)) # 当前东7区时间 print(tz) v3 = v1 + timedelta(days=140, minutes=5) # 时间相加 print(v3) v4 = v1 - v3 # 时间相减,仅支持datetime类型-datetime类型,也可以比较,不能相加 print(v4)
-
字符串
# 字符串格式的时间--->datetime格式时间 text = "2021-11-20" v1 = datetime.strptime(text, '%Y-%m-%d') # datetime格式时间--->字符串格式的时间 v2 = datetime.now() val = v2.strftime('%Y-%m-%d %H:%M:%S')
-
时间戳
# 时间戳格式--->datetime格式 ctime = time.time() v1 = datetime.fromtimestamp(ctime) # datetime格式--->时间戳格式 v2 = datetime.now() val = v2.timestamp()
8.6 正则表达式
8.6.1 正则表达式相关
1. 字符相关
-
lalala
:匹配文本中的lalalaimport re text = "今天天气很好lalala,处处花儿香lalala" data_list = re.findall("lalala", text) print(data_list) #["lalala", "lalala"] 可用于计算字符串中某个字符出现的个数
-
[abc]
:匹配a或b或c字符import re text = "今天天气很好a,b处处花儿香cb" data_list = re.findall("[abc]", text) print(data_list) #["a", "b", "c", "b"]
import re text = "今天天气很好qa,b处处花儿香qcb" data_list = re.findall("q[abc]", text) print(data_list) #["qa", "qc"]
-
[^abc]
:匹配除了abc以外的其他字符import re text = "abcdef" data_list = re.findall("[^abc]", text) print(data_list) #["d", "e", "f"]
-
[a-z]
:匹配a~z之间的任意字符,[0-9]
类似import re text = "abcdef" data_list = re.findall("[a-c]", text) print(data_list) #["a", "b", "c"]
-
.
:代指除换行符以外的任意字符import re text = "xlalalblac" data_list = re.findall("l.l", text) print(data_list) #["lal", "lbl"]
import re text = "xlalalblac" data_list = re.findall("l.+l", text) #贪婪匹配 print(data_list) #["lalalbl"]
import re text = "xlalalblac" data_list = re.findall("l.+?l", text) #非贪婪匹配 print(data_list) #["lal"]
-
\w
:代指字母或数字或下划线(汉字)import re text = "xlalalbelac" data_list = re.findall("l\w+e", text) print(data_list) #["lalalbe"]
-
\d
:代指数字import re text = "xl111alalbelac" data_list = re.findall("l\d", text) print(data_list) #["l1"]
import re text = "xl111alalbelac" data_list = re.findall("l\d+", text) print(data_list) #["l111"]
-
\s
:代指任意的空白符,包括空格、制表符等import re text = "root admin add admin" data_list = re.findall("a\w+\s\w+", text) print(data_list) #["add admin"]
2. 数量相关
-
*
:重复0次或多次import re text = "lclaccclaaccc" data_list = re.findall("la*c", text) print(data_list) # ["lc", "lac", "laac"]
-
+
:重复1次或多次import re text = "lclaccclaaccc" data_list = re.findall("la{+}c", text) print(data_list) # ["lac", "laac"]
-
?
:重复0次或1次import re text = "lclaccclaaccc" data_list = re.findall("la?c", text) print(data_list) # ["lc", "lac"]
-
{n}
:重复n次import re text = "lclaccclaaccc" data_list = re.findall("la{2}c", text) print(data_list) # ["laac"]
-
{n,}
:重复n次或n+次import re text = "lclaccclaaccc" data_list = re.findall("la{1,}c", text) print(data_list) # ["lac", "laac"]
-
{n, m}
:重复n到m次import re text = "lclaccclaaccc" data_list = re.findall("la{1, 2}c", text) print(data_list) # ["lac", "laac"]
3. 括号(分组)
-
提取数据区域
import re text = "lclaccclaaccc" data_list = re.findall("l(a{1, 2}c)", text) print(data_list) # ["ac", "aac"]
import re text = "lclaccclaaccc" data_list = re.findall("(l(a{1, 2}c))", text) print(data_list) # [("lac", "ac"), ("laac", "aac")]
-
获取指定区域+或条件
import re text = "lclaccclaaccc" data_list = re.findall("la(c+|ac+)", text) print(data_list) # ["ccc", "accc"]
import re text = "lclaccclaaccc" data_list = re.findall("(la(c+|ac+))", text) print(data_list) # [("laccc", "ccc"), ("laaccc", "accc")]
4. 起始和结束
一般用于对用户输入数据格式校验。
-
^
:开始 -
$
:结束import re text = "233333@qq.com" email_list = re.findall("^\w+@\w+.\w+$", text, re.ASCII) print(text) # ["233333@qq.com"]
5. 特殊字符
由于正则表达式中* . \ { } ( )*
等都具有特殊含义,所以如果想要在正则中匹配这种指定的字符,需要\
转义。
import re
text = "lalalal{2}la"
email_list = re.findall("l\{2\}l", text, re.ASCII)
print(text) # ["l{2}l"]
8.6.2 re模块
-
findall
,获取匹配到的所有数据 -
match
,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None -
search
,浏览整个字符串去匹配第一个,未匹配成功返回None -
sub
,替换匹配成功的位置 -
split
,根据匹配成功的位置分割 -
finditer
,迭代器,循环一次匹配一次import re text = "xxx20000101xxx20101010" data_list = re.finditer("\d{3}(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2})") for item in data_list: info_dict = item.groupdict() print(info_dict) # {'year': '2000', 'month': '01'; 'day':'02'} # {'year': '2010', 'month': '10'; 'day':'10'}
9 项目开发规范
9.1 单文件应用
"""
1. 文件注释
2. 导入模块(内置、第三方、自定义)
3. 全局变量大写
4. 函数名命名规范&函数功能注释
5. TODO信息
6. 部分功能代码注释
7. 主文件
"""
import re
import requuests
from openpyxl import load_workbook
DB="VVV"
def do_something():
""" 函数注释 """
# TODO 待完成时,下一期实现xx功能
for i in range(10):
pass
def run():
""" 函数注释 """
# 对功能代码进行注释
text = input(">>>")
print(text)
if __name__ = '__main__':
run()
9.2 单可执行文件
9.3 多可执行文件
10 关键字
10.1 nolocal关键字
非局部声明变量指代的已有标识符是最近外面函数的已声明变量,但是不包括全局变量。这个是很重要的,因为绑定的默认行为是首先搜索本地命名空间。nonlocal声明的变量只对局部起作用,离开封装函数,那么该变量就无效。
非局部声明不像全局声明,我们必须在封装函数前面事先声明该变量
非局部声明不能与局部范围的声明冲突
count = 1
def a():
count = 'a函数里面' #如果不事先声明,那么函数b中的nonlocal就会报错
def b():
nonlocal count
print(count)
count = 2
b()
print(count)
if __name__ == '__main__':
a()
print(count) # a函数里面
# 2
# 1
10.2 深浅拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
-
浅拷贝
copy.copy()
浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。
- 不可变类型,不拷贝
- 可变类型,只拷贝第一层
-
深拷贝
copy.deepcopy()
深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。
- 不可变类型,不拷贝,特殊的:元组,如果内部有可变类型,则可以被拷贝
- 可变类型,无论在哪一层都会拷贝
10.3 yield from关键字
Python3.3版本的PEP 380中添加了
yield from
语法,允许一个generator
生成器将其部分操作委派给另一个生成器。其产生的主要动力在于使生成器能够很容易分为多个拥有send和throw方法的子生成器,像一个大函数可以分为多个子函数一样简单。Python的生成器是协程coroutine
的一种形式,但它的局限性在于只能向它的直接调用者yield值。这意味着那些包含yield的代码不能想其他代码那样被分离出来放到一个单独的函数中。这也正是yield from
要解决的。
对于简单的迭代器,yield from iterable
本质上等于for item in iterable: yield item
的缩写版,yield from
允许子生成器直接从调用者接收其发送的信息或者抛出调用时遇到的异常,并且返回给委派生产器一个值
11面向对象
- 定义类,在类中定义方法,在方法中实现具体的功能
- 实例化类的一个对象,通过对象去调用并执行方法
注意:
- 类名称首字母大写&驼峰式命名
- py3之后默认类都继承object
- 在类中编写的函数称为方法
- 每个方法的第一个参数是self
11.1 对象和self
在每个类中都可以定义一个特殊的:__init_初始化方法
,在实例化类创建对象时自动执行。
- 面对对象的思想:将数据封装到对象中,在执行方法时,再去对象中获取
- 函数式思想:函数内部需要的数据均通过参数的形式传递
- self,本质上就是一个参数,这个参数是python内部会提供,其本质就是调用当前方法那个对象
- 对象,基于类实例化出来“一块内存”,默认里面没有数据;经过类的
__init_
方法,可以在内存中初始化一些数据。
11.2 应用示例
-
将数据封装到一个对象,便于以后使用
class UserInfo: def __init__(self, name, pwd): self.name = name self.password = pwd def run(): user_object_list = [] while True: user = input("用户名") if user.upper() == "Q": break pwd = input("密码") user_object = UserInfo(user, pwd) user_object_list.append(user.object) for obj in user_object_list: print(obj.name, obj.password)
-
将数据分装到对象中,在方法中对原始数据进行加工处理
class Pagination: def __init__(self, current_page, per_page_num=10): self.per_page_num = per_page_num if not current_page.isdecimal(): self.current_page = 1 return current_page = int(current_page) if current_page < 1: self.current_page = 1 self.current_page = current_page def start(self): return (self.current_page - 1) * self.per_page_num def end(self): return self.current_page * self.per_page_num user_list = ["用户-{}".format(i) for i in range(1, 3000)] # 分页显示,每页显示10条 while True: page = input("请输入页码:") pg_object = Pagination(page, 10) page_data_list = user_list[pg_object.start():pg_object.end()] for item in page_data_list: print(item)
-
根据类创建多个对象,在方法中对对象中的数据进行修改
11.3 成员
在编写面向对象相关代码时,最常见的成员有:
- 实例变量,属于对象,只能通过对象调用;
- 绑定方法,属于类,通过对象调用或通过类调用。
面向对象中的所有成员如下:
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
11.3.1 变量
- 实例变量,属于对象,每个对象中各自维护自己的数据。
- 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似全局变量)。
提示:当把每个对象中都存在的相同的示例变量时,可以选择把它放在类变量中,避免对象中维护多个相同数据。
11.3.2 方法
- 绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】
- 类方法,默认有一个cls参数,类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】
- 静态方法,无默认参数,类或对象都可以调用【对象&类均可调用】
class Foo(object):
def __init__(self, name):
self.name = name
def f1(self):
print("绑定方法", self.name)
@classmethod
def f2(cls):
print("类方法", cls)
@staticmethod
def f3():
print("静态方法")
# 绑定方法
obj = Foo("xxx", 20)
obj.f1()
11.3.3 属性
属性是由 绑定方法+特殊装饰器 组合创造出来的,让以后调用方法时可以不加括号。
class Foo(object):
def __init__(self, name):
self.name = name
def f1(self):
return 123
@property
def f2(cls):
return 123
obj = Foo("xxx")
v1 = obj.f1()
print(v1)
v1 = obj.f1
print(v1)
注意:由于属性和实例变量的调用方式相同,所以在编写时需要注意:属性名称 不要和 实例变量 重名。
11.3.4 成员修饰符
python中成员的修饰符指的是:共有和私有。
- 共有:在任何地方都可以调用这个成员。
- 私有:只有在类的内部才可以调用该成员(成员是以两个下划线开头,则表示该成员私有)。
class Foo(object):
def __init__(self, name, age):
self.__name = name
self.age = age
def get_data(self):
return self.__name
def get_age(self):
return self.age
def __get_info(self):
return self.__name, self.age
obj = Foo('xxx', 18)
# 公有成员
print(obj.age)
v1 = self.get_age()
print(v1)
# 私有成员
# print(obj.name) # 错误,由于是私有成员,只能在类中调用
v2 = self.get_data()
print(v1)
# 私有成员
obj._Foo_msg() # 可以通过这个特殊语法从外部调用私有成员
父类中的私有成员,子类无法继承。
11.3.5 嵌套
组合、关联、依赖。
11.4 三大特性
封装,继承,多态。
11.4.1 封装
封装主要体现在两个方面:
- 将同一类方法封装到一个类中,
- 将数据封装到了对象中,在实例化一个对象时,可以通过
__init_
初始化方法在对象中封装一些数据,便于以后使用。
11.4.2 继承
子类可以继承父类中的方法和类变量。
- 执行对象方法时,优先去当前对象所关联的类中找,没有的话才去父类中查找;
- Python支持多继承,先继承左边,再继承右边的;
- 理清self所指,去self对应的那个类中去获取成员,没有就按照继承关系向上查找。
11.4.3 多态
多态是指一类事物有多种形态,比如动物类,可以有猫,狗,猪等等。(一个抽象类有多个子类,因而多态的概念依赖于继承)。
11.5 特殊成员
在Python的类中存在一些特殊的方法,__方法__
,[非常多参见此博客](Python 类的魔术方法 - Dahlhin - 博客园 (cnblogs.com)),懒得写不是。
-
__init__
,初始化方法class Foo(object): def __init__(self, name): self.name = name obj = Foo("xxx")
-
__new__
,构造方法class Foo(object): def __init__(self, name): print("第二步:初始化对象,在空对象中创建数据") self.name = name def __new__(cls, *arg, **kwargs): print("第一步:首先创建空对象并返回") return object.__new__(cls) obj = Foo("xxx")
-
__call__
class Foo(object): def __call__(cls, *arg, **kwargs): print("执行call方法") obj = Foo() obj()
-
__str__
, 定义当被 str() 调用或者打印对象时的行为class Foo(object): def __str__(self): return "lalalala" obj = Foo() data = str(obj) print(data) # lalalala print(obj) # lalalala
-
__dict__
class Foo(object): def __init__(self, name, age): self.name = name self.age = age obj = Foo("one_ear", 18) print(obj.__dict__) #{'name': 'one_ear', 'age': '19'}
-
__getitem__
、__setitem__
、__getitem__
class Foo(object): def __getitem__(self, item): # 定义获取容器中指定元素的行为,相当于 self[key] print(item) def __setitem__(self, key, value): # 定义设置容器中指定元素的行为,相当于 self[key] = value print(key, value) def __delitem__(self, key): # 定义删除容器中指定元素的行为,相当于 del self[key] print(key) obj = Foo() obj["one_ear"] = 18 # 自动触发类中__setitem__ obj["two_ears"] # 自动触发类中__getitem__ del obj["one_ear"] # 自动触发类中__delitem__
-
__enter__
、__exit__
,上下文管理class Foo(object): def __enter__(self): # 1. 定义当使用 with 语句时的初始化行为 # 2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定 return 123 def __exit__(self, exc_type, exc_val, exc_tb): # 1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么 # 2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作 pass obj = Foo() # with 对象 as j 在内部会执行__enter__方法 # 当with缩进中的代码执行完毕,自动会执行__exit__方法 with obj as j: pass with Foo() as j: pass
-
__add__
,定义加法的行为:+class Foo(object): def __add__(self, other): return 123 o1 = Foo() o2 = Foo() # 对象+值, 内部回去执行 对象.__add__方法,并将+后面的值当作参数传递过去 o3 = o1 + o2 print(o3) # 123
-
__iter__
,定义当迭代容器中的元素的行为