数据类型
分类
bytearray、byte
基本引用类型:
空引用:
None 不可变
数字:
bool 不可变
int 不可变
flout 不可变
complex 不可变
序列:
str字符串 有序 不可变 可重复
tupl元组 有序 不可变 可重复
list列表 有序 可变 可重复
散列:
dict字典 无序 可变 不可重复(指key) {1:1, 2:2, 3: 3}
set集合 无序 可变 不可重复 {1:?, 2:?, 3: ?}
直接与间接
基本数据类型:变量中直接存储目标数据,操作变量即直接操作目标数据
引用数据类型:变量中存储指向目标数据的地址,操作变量即简介操作目标数据
Python中一切皆对象,一切皆为引用数据类型,内置六大类引用类型,数字类型、字符串类型、元组类型、列表类型、字典类型、集合类型
可变与不可变
不可变数据类型:不可原地修改,修改变量指向的目标数据时,必须重新申请内存以存储修改后值的数据类型。Number(数字)、String(字符串)、Tuple(元组)为不可变数据类型。
可变数据类型:可以原地修改,修改变量指向的目标数据时,可以在原地存储修改后值的数据类型。可变数据类型即可变数据类型修改时内存地址不发生变化。包括List(列表)、Dictionary(字典)、Set(集合)为可变数据类型。
# 不可变类型不可原地修改
a = 1 # a指向目标数据1的内存
id(a) # a指向的地址为140720495850280
b = a + 1 # b指向a+1的结果的内存
print(b) # 2为b指向的目标数据
id(a) # 140720495850280 a+1并未改变a指向的内存地址
id(b) # 140720495850312 b指向新开辟的存储a+1结果的内存地址,若非如此id(a)应当与id(b相等)
# 可变类型可以原地修改
a = [1] # a指向[1]的内存
id(a) # 2955498803968
a[0] = 2 # 修改a中第一个元素的值
print(a) # [2]
id(a) # 2955498803968
# 可变类型可以不原地修改
a = [1]
id(a) # 2955498788416
a = a + [1]
print(a) # [1, 1]
id(a) ## 2955498806720
字节类型
s = b"yuzao"
print(s, type(s))
print(s.__sizeof__())
print(s.__len__())
数字类型,Number
不可变类型
整型
# <class 'int'>
print(type(999)) # 十进制整型
print(type(0b1010)) # 二进制整型
Python中整型取值范围无限制
浮点型
# <class 'float'>
print(type(3.1415926)) # 浮点数
print(type(3.1415926e2)) # 科学计数法浮点数
浮点数取值范围约±10^308
# 计算机中无法精确表示所有浮点数,这是由浮点数存储方案决定的系统误差,要以有限空间尽可能存储无限的浮点数是要做取舍的
a = 0.1
b = 0.2
print(a + b)
# 0.30000000000000004
布尔型
# <class 'bool'>
from numbers import Number
print(issubclass(bool, Number)) # T
print(type(True)) # <class 'bool'>
print(type(False)) # <class 'bool'>
print(True == 1) # True
print(True == 2) # False
print(False == 0) # True
print(False == 2) # False
复数
# <class 'complex'>
print(type(3-3j))
print(type(complex(3,-3)))
z = 1 + 3j
z.real
z.imag
字符串类型
不可变类型,字符串是若干字符的有序序列。
注:Python3字符集默认使用Unicode,编码方式默认使用UTF-8。Python2字符集默认使用ASCII,编码方式采用ASCII简易映射,Python2版本常在文件首行附加# -\*- coding: UTF-8 -\*-注释用以显式指定编码方式,Python3版本代码无需指定。
字符串字面量
Python中单引号和双引号的等价的。
单行字符串:单引号对、双引号对
'xxxxx' "xxxxx"多行字符串:三单引号对、三双引号对
""" xxxxx xxxxx """ ''' xxxxx xxxxx '''
字符串操作符
| 字符串操作符 | 含义 |
|---|---|
| + | 字符串连接符 |
| * | 字符串复制符 |
| in | 子串判断符 |
| string[x] | 获取第x-1个字符 |
| string[S:E:L] | 从[S, E)按照L的步长切片,L可为附属 |
# 步长超过字符串总长度会返回S位置上的字符
a = "0123456789"
a[::100]
# '0'
# 字符串可以使用r不进行转义,保留原始字符串
字符串操作函数
| 字符串操作函数 | 含义 |
|---|---|
| len(x) | 返回字符串x的长度 |
| str(x) | 返回任意类型x对应的字符串形式,str(1.23)结果为”1.23”,str([1,2])结果为”[1,2]” |
| eval(expression) | eval() 函数用来执行一个字符串表达式,并返回表达式的值。eval(‘print(‘hello’)’),结果为hello |
| hex(x) | 返回整数x的十六进制小写形式字符串 |
| oct(x) | 返回整数x的八进制小写形式字符串 |
字符串处理方法
| 字符串处理方法 | 含义 |
|---|---|
| string.lower() | 返回字符串副本,全部字符小写 |
| string.upper() | 返回字符串副本,全部字符大写 |
| string.split(sep=None) | 返回一个列表,由string根据被分隔的部分组成,”A,B,C”split(“,”)结果为[‘A’,’B’,’C’] |
| string.count(sub) | 返回字串在string中出现的次数,”aaa”.count(“aa”)结果为1 |
| string.replace(o;d,new) | 返回字符串副本,所有old字串被替换为new |
| string.center(width[,fillchar]) | 字符串根据宽度width居中,filler可缺省 |
| string.strip(chars) | 在string左侧和右侧去掉chars中列出的字符,逐一去除直至非chars所列字符 |
| string.join(iter) | 在字符串中相邻两个字符之间增加字符串string |
格式字符串
Format Specification Mini-Language
https://docs.python.org/3/library/string.html#format-string-syntax
# f-str
print(f'予早个人blog,技术碎碎念,主要语言为{None}、{{1, 2, 3}}、{"{Go}"},包含前端、后端、AI、算法、测试、运维等内容')
# format-str
# format-str会将对象按照一定规则转为字符串并填充到模板中
# {field_name[!conversion][:format_pecification]}
# 默认位置方式
print('予早个人blog,技术碎碎念,主要语言为{}、{}、{},包含{}、{}、{}、{}、{}、{}等内容'.format(
3.14, ["Java", 0], None, b"front_end", r"后端\n", True, {"算法": False}, ("测试",), {}
))
# 指定位置方式
print('予早个人blog,技术碎碎念,主要语言为{2}、{1}、{1},包含前端、后端、AI、算法、测试、运维等内容'.format(
'Python', 'Java', 'Go'
))
# 指定名称方式
print('予早个人blog,技术碎碎念,主要语言为{v1}、{v1}、{v3},包含前端、后端、AI、算法、测试、运维等内容'.format(
v1='Python', v2='Java', v3='Go'
))
# 默认位置方式和指定名称方式可以混用,指定位置方式只能单独使用
print('予早个人blog,技术碎碎念,主要语言为{}、{}、{v1},包含{v2}、后端、AI、算法、测试、运维等内容'.format(
'Python', 'Java', v1='Go', v2="前端"
))
# 符号设置
# 给数据加前置符号。可选为+、-、space
print('{:+}'.format(520)) # +520 正数可以加+
print('{:-}'.format(520)) # 520 正数不会加-
print('{: }'.format(520)) # 520 整数可加空格,能与负数对齐
print('{:+}'.format(-520)) # -520 复数不会加+,因为有-
print('{:-}'.format(-520)) # -520 复数不会加-,因为有-
print('{: }'.format(-520)) # -520 复数不会加空格,因为有-
print('{: ,}'.format(5200)) # 5,200
# 分组设置
print('{:,}'.format(5200)) # 5,200
print('{:_}'.format(5200)) # 5_200
# 对齐设置
print('{:6}'.format(520))
print('{:=6}'.format(520))
print('{:>6}'.format(520))
print('{:<6}'.format(520))
print('{:^6}'.format(520))
print('{:06}'.format(-520))
print('{:0=6}'.format(-520))
print('{:0>6}'.format(-520))
print('{:0<6}'.format(-520))
print('{:0^6}'.format(-520))
# print('{:06}'.format( 'Python')) # ValueError: '=' alignment not allowed in string format specifier
# print('{:0=6}'.format('Python')) # ValueError: '=' alignment not allowed in string format specifier
print('{:0^6}'.format('yz'))
print('{:0>6}'.format('yz'))
print('{:0<6}'.format('yz'))
print('{:0^6}'.format('yz'))
# 类型设置
print('{0:b} {0:#b}'.format(520)) # 二进制
print('{0:o} {0:#o}'.format(520)) # 八进制
print('{0:d} {0:#d}'.format(520)) # 十进制
print('{0:x} {0:#x} {0:#X} {0:#X}'.format(552200)) # 十六进制
print('{:c}'.format(80)) # P 80的Unicode字符
print('{:e}'.format(3.14)) # 3.140000e+00 科学计数法,精度默认为精确到小数点后6位
print('{:E}'.format(3.14)) # 3.140000E+00 科学计数法,精度默认为精确到小数点后6位
print('{:f}'.format(3.14)) # 3.140000 f将参数以定点法的形式输出(不是数用nan标示,无穷用inf标示,默认精度为6)
print('{:F}'.format(3.14)) # 3.140000 F将参数以定点法的形式输出(不是数用NAN标示,无穷用INF标示,默认精度为6)
print('{:g}'.format(3.14)) # 通用浮点类型
print('{:g}'.format(31457788)) # 通用浮点类型
print('{:%}'.format(0.89)) # 89.000000% 百分数,精度默认为精确到小数点后6位
# 精度设置
print('{:.2f}'.format(3.1415)) # 3.14,小数点后的位数为2
print('{:.2g}'.format(3.1415)) # 3.1,小数点前后总位数为2
print('{:.6s}'.format('i love you')) # i hate,总位数6
import decimal
print("{:,}".format(decimal.Decimal("{:.2f}".format(1))))
print("{:,}".format(decimal.Decimal("{:.2f}".format(decimal.Decimal("1231231.3252")))))
"""
字符串
"""
s = " davis JoNes_aBc "
print(s.capitalize())
print(s.upper())
print(s.lower())
print(s.swapcase())
print(s.title())
print(s.startswith("Da"))
print(s.endswith("Bc"))
print(s.count("a"))
print(s.find("a")) # 找不到返回-1
print(s.find("aB"))
print(s.replace('davis', 'DAVIS'))
print(s.index("JoNes")) # 找不到抛出异常
print(s.join(" "))
print(s.strip())
print(s.strip(" "))
print(s.rstrip(" "))
print(s.lstrip(" "))
print(s.split())
print(s.split(" "))
print(s.split("a"))
s = ”Hello World“
print(s[3])
print(s[2:6])
print(s[::])
print(s[::-1])
# 字符串索引切片
# 字符串与列表相互转换,join、split
print(' '.join(['1', '2', '3', '4', '5']))
# 字符串%格式化输出,仅有%s、%d
name = input("请输入姓名:")
age = input("请输入年龄:")
process = input("请输入学习进度:")
msg = "我是%s,今年%s岁,学习进度为%s%%" % (name, age, process) # 前面%为转义标识,即%%输出%
print(msg)
# 正则表达式
# python内置模块
# re
import re
pattern = ""
str_ = ""
result = re.search(pattern, str_)
print(result.group() if result else None)
result = re.match(pattern, str_) # 必须从头匹配
print(result.group() if result else None)
result = re.findall(pattern, str_)
print(result)
result = re.finditer(pattern, str_) # 找的内容比较多的时候
for i in result:
print(i.group() if i else None)
result = re.split(pattern, str_)
result = re.sub(pattern, 'O', str_)
print(result)
obj = re.compile(pattern)
result = obj.search(str_)
print(result)
pattern = "/\b[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,6}\b/g"
str_ = "abcd test1@jld.com 1234 test2@jld.com"
result = re.search(pattern, str_)
print("---", )
print(result.group() if result else None)
# ()表示捕获分组,() 会把每个分组里的匹配的值保存起来,python分组优先加?
import string
print(string.whitespace) # whitespace = ' \t\n\r\v\f' 空格 水平制表符 换行符 回车符 垂直制表符 换页符
print(string.ascii_lowercase) # abcdefghijklmnopqrstuvwxyz
print(string.ascii_uppercase) # ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.digits) # 0123456789
print(string.hexdigits) # 0123456789abcdefABCDEF
print(string.octdigits) # 01234567
print(string.punctuation) # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
print(string.printable) # digits + ascii_letters + punctuation + whitespace
# whitespace -- a string containing all ASCII whitespace
# ascii_lowercase -- a string containing all ASCII lowercase letters
# ascii_uppercase -- a string containing all ASCII uppercase letters
# ascii_letters -- a string containing all ASCII letters
# digits -- a string containing all ASCII decimal digits
# hexdigits -- a string containing all ASCII hexadecimal digits
# octdigits -- a string containing all ASCII octal digits
# punctuation -- a string containing all ASCII punctuation characters
# printable -- a string containing all ASCII characters considered printable
print(string.capwords("hello world")) # Hello World
# Template
# Formatter
字符串判断是否是数字
isalnum
是否为字母数字字符串,字符串中所有字符为字母或者数字,且至少有一个字符,则为True,否则为False。
字母数字字符 c 判定条件,四者任一为True即可:
- c.isalpha()
- c.isdecimal()、
- c.isdigit()
- c.isnumeric()
isalpha
str.isalpha()
是否为字母字符串。若字符串中所有字符均为字母且至少有一个字符,则为True,否则为False。
Note that this is different from the Alphabetic property defined in the section 4.10 ‘Letters, Alphabetic, and Ideographic’ of the Unicode Standard.
isdecimal、isdigit、isnumeric
c.isdecimal()
是否为十进制字符构成的字符串。若字符串中所有字符均为十进制数字且至少有一个字符,则为True,否则为False。
十进制字符是 Unicode 常规类别“Nd”中的字符
str.isdigit()
从形式上讲,数字是属性值为 Numeric_Type=Digit 或 Numeric_Type=Decimal 的字符。
str.isnumeric()
从形式上讲,数字字符是属性值为 Numeric_Type=Digit、Numeric_Type=Decimal 或 Numeric_Type=Numeric 的字符。
# 测试字符串
test_str = (
# 数字字符构成的字符串
"1234", # 十进制数字
"¹²³", # 上角标整数
"¼2½", # 上角标分数
"1234", # 全角数字
"ⅠⅡⅢⅣⅤ", # 罗马数字
"①②③④⑤", # 序号数字
"一二三四", # 汉字数字
# 数字字符和其他字符构成的字符串
"12.34", # 小数
"1/3", # 分数
"0b1011", # 二进制数字
"0xABCD", # 十六进制数字
)
print(f"{'string':<10}: {'isdecimal':<10} {'isdigit':<10} {'isnumeric':<10}")
for s in test_str:
print(f"{s:<10}: {s.isdecimal():<10} {s.isdigit():<10} {s.isnumeric():<10}")
string : isdecimal isdigit isnumeric
1234 : 1 1 1
¹²³ : 0 1 1
¼2½ : 0 0 1
1234 : 1 1 1
ⅠⅡⅢⅣⅤ : 0 0 1
①②③④⑤ : 0 1 1
一二三四 : 0 0 1
12.34 : 0 0 0
1/3 : 0 0 0
0b1011 : 0 0 0
0xABCD : 0 0 0
isdecimal、isdigit、isnumeric是判断字符串中字符是否均为数字字符的方法,并非用于判断字符串是否可表示数字,例如12.34、1/3、0b1011和0xABCD可表示数字但字符串中并非所有字符为数字字符。isdecimal、isdigit、isnumeric判定数字字符的范围依次扩大。
通用正则
整数
r"^[+-]?0$|^[+-]?[1-9]\d*$"
小数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
元组类型,Tuple
不可变类型,列表是若干元素的无序序列。
<class 'tuple'>
# 定义方式
a = (1, 2, 3)
b = tuple([1, 2, 3])
# 元组字面量
a = (1, 2, 3) # 标准形式
b = (1,) # 单一元素需要加,与(1)区分,(1)与1是等价的
c = 1, 2, 3 # 可省略小括号,函数返回值即为元组类型,通常不加小括号
d = 1, # 添加,与整型1区分
"""
元组
"""
t = (1, 2, 3, 'tuple', [1, 'tuple'])
t[4][0] = 2
print(t)
列表类型,List
可变类型
# 定义方式
a = [1,2, 3]
b = list([1, 2, 3])
# 列表字面量
a = [1, 2, 3]
b = [
"12",
"21"
"1e",
"er"
] # 实际上只有三个元素,['12', '211e', 'er']
"""
列表
"""
l = [1, 2, 3]
# 索引切片同字符串,增删改查
l.append('4')
l.pop(-1)
l.extend((1, 2, 3))
l.remove(1)
l.clear()
l[0:1] = '123457890' # 根据切片修改,有多少改多少
print(len(l))
l.sort(reverse=True)
l.reverse()
列表操作符
| 列表操作符 | 含义 |
|---|---|
| ls[i] = x | 替换列表ls第i位元素为x |
| ls[i:j:k] = lt | 用列表lt替换ls切片后多对应的子元素列表 |
| ls += lt | 更新列表ls,将列表lt中的元素增加到列表ls中 |
| ls *= n | 更新列表ls,将其元素重复n次 |
列表操作函数
| 列表操作函数 | 含义 |
|---|---|
| del ls[i] | 删除ls列表中第i元素 |
| del ls[i:j:k] | 删除列表ls中第i到j以k为步长的元素 |
列表处理方法
| 列表处理函数 | 含义 |
|---|---|
| ls.append(x) | 在列表ls最后增加一个元素x |
| ls.clear() | 删除列表中所有的元素 |
| ls.copy() | 生成一个新的列表,赋值ls中所有的元素 |
| ls.insert(i,x) | 在列表的第i位置增加元素x |
| ls.pop(i) | 将列表ls中第i位置元素返回并删除该元素 |
| ls.remove(x) | 将列表ls中出现的第一个元素x删除 |
| ls.reserve() | 将列表ls中的元素反转 |
字典类型,Dictionary
可变类型,字典是若干键值对组成的整体,key不允许重复,key为任意不可变类型
a = {1: "A", "c": None, (1, 2): [0]}
b = dict([(1, 2), [2, 3], {3,4}]) # 容器相对自由
"""
字典
"""
d = {'1': 1, '2': 2, '3': 3}
a = [1]
d = {a: 12}
a = 2
print(d)
# 字典的key需要是基本数据类型?
# 增
d[2] = 2
# 删
d.keys()
d.values()
d.copy()
d.clear()
d.get(1, 'NULL')
k, v = d.items()
d.setdefault(1, 12) # 有键值对不更改,无则使用值更改
d.pop(100, '123')
d.popitem() # 随机删除
d2 = {1: 2, 4: 4}
d.update(d2) # 字典更新
a, b = 1, 2
b, a = a, b
# builtins
字典合并
d1 = {"A": 1, "B": 2, "C": 3}
d2 = {"B": 4, "C": 5, "D": 6}
print({**d1, **d2})
print(d1 | d2)
d = {'hash': 'bang', 'slash': 'dot'}
d = dict(hash='bang', slash='dot')
d = dict({'hash': 'bang', 'slash': 'dot'})
d = dict([['hash', 'bang'], ['slash', 'dot']])
直接赋值的x
from timeit import timeit
timeit("a = {'a': 1, 'b': 2}")
0.424...
timeit("a = dict(a = 1, b = 2)")
0.889...
注:
- Python3.7以前,dict中键值对的插入顺序和存储顺序不一致,通常使用OderedDict保证插入和存储顺序的一致,Python3.7及之后,dict默认键值对插入顺序和存储顺序一致。
- 字典key使用.操作,则需要实现重写__getattr__方法
字典类型操作符
| 字典类型操作符 | 含义 |
|---|---|
| k in d | 返回boolean,判断k键是否在字典d中 |
| d[k] | 获取k对应的v,若没有对应的k则报错 |
| d[k] = v | 将k对应的值修改为v,没有k就创建键值对 |
| d3 = d1 | d2 | 将两个字典合并生成一个新的字典,注意,是浅拷贝的合并,d3是一个新字典,同key会被覆盖,右边覆盖左边 |
PEP 584
字典合并符号并不高效,d | e | f | g | h 会创建和销毁三个临时映射。
序列级联的每一次合并都会使序列中的元素总数增加,最终会带来 O(N^2) 的性能开销。而字典合并有可能会有重复键,因此临时映射的大小并不会如此快速地增长。
正如我们很少将大量的列表或元组连接在一起一样,PEP的作者任务合并大量的字典也是少见情况。若是确实有这样的诉求,那么最好使用显式的循环和就地合并:
new = {}
for d in many_dicts:
new |= d
d1 = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5}
d2 = {1: 2, 3: 4, 5: 6, 7: 8, 9: 0}
d3 = d1 | d2
print(d1, d2, d3)
print(id(d1), id(d2), id(d3))
d1 |= d2
print(d1)
print(id(d1))
字典类型操作函数
| 字典类型操作函数 | 含义 |
|---|---|
| del d[k] | 删除字典d中键k对应的键值对 |
| len(k) | 返回字典中元素的个数 |
字典类型处理方法
| 字典类型处理方法 | 含义 |
|---|---|
| d.keys() | 返回字典d中所有键的信息 |
| d.values() | 返回字典d中所有值的信息 |
| d.items() | 返回字典d中所有键值对的信息 |
| dict.get(key[, value]) | 若键k存在,返回相应值,反之返回 |
| d.pop(k[, value]) | 若键k存在,返回并删除相应值,反之返回 |
| d.popitem() | 随机从字典d中以元组形式返回并删除一个键值对 |
| d.clear() | 删除字典d中所有键值对 |
| d.setdefault(k, default=None) | 若字典中没有k,则为k设置默认值 |
集合类型,Set
可变类型,集合是若干无序唯一元素组成的整体,集合中的元素都是不可变类型
a = {1, 2, 3} # 集合没有空集合字面量,不同于()、[]、{}
b = set([1, 2, 3])
"""
集合
"""
s = {1, 2, 3}
# frozenset
集合操作符
| 集合操作符 | 含义 |
|---|---|
| S | T | 并,返回一个集合,包含S、T所有元素 |
| S - T | 差,返回一个集合,包含在S但不在T中的元素 |
| S & T | 交,返回一个集合,包含S、T都有的元素 |
| S ^ T | 返回一个集合,包含S、T中互不相同的元素 |
| S <=T 或 S<T | 返回boolean,判断S和T的子集关系 |
| S>=T 或 S>T | 返回boolean,判断S和T的包含关系 |
| S |= T | 更新集合S,包括在集合S和T中的所有元素 |
| S -= T | 更新集合S,包括在集合S但不在T中的元素 |
| S &= T | 更新集合S,包括同时在集合S和T中的元素 |
| S ^= T | 更新集合S,包括集合S和T中非相同的元素 |
集合操作函数
| 集合操作函数 | 含义 |
|---|---|
| len(s) | 返回集合s的元素个数 |
| x in s | 返回boolean,判断x是否在集合s中 |
| x not in s | 返回boolean,判断x是否不在集合s中 |
| set(x) | 将其他变量x转换为集合类型 |
集合处理方法
| 集合处理方法 | 含义 |
|---|---|
| s.add(x) | 若x不在集合中,将x增加到s |
| s.discard(x) | 移除s中的元素x,若x不在集合s中,不报错 |
| s.remove(x) | 移除s中的元素x,若x不在集合s中,产生KeyError异常 |
| s.clear() | 移除s中所有元素 |
| s.pop() | 随机返回s的一个元素并更新s,若s为空,产生KeyError异常 |
| s.copy | 返回集合的一个副本 |
数字操作
| 函数 | 含义 |
|---|---|
| abs(x) | x的绝对值 |
| divmod(x,y) | 商余,(x//y,x%y),同时输出商数和余数 |
| pow(x,y[,z]) | 幂余,(x**y)%z,参数z可缺省 |
| round(x[,d]) | 四舍五入,d是保留小数位数,默认值为0 |
| max(x1,x2,x3,…,xn) | 最大值,n不限 |
| min(x1,x2,x3,…,xn) | 最小值,n不限 |
| int(x) | 将x变为整数,舍弃小数部分,非四舍五入,int(123.5)==123,int(“123.5”)==123 |
| float(x) | 将x变为浮点数,增加小数部分,int(123)==123.0,int(“123”)==123.0 |
| complex(x) | 将x变为复数,增加虚数部分 |
序列操作
字符串、元组、列表均是序列。
序列类型
序列操作符
正向递增序号、反向递增序号
序列操作函数
序列处理方法
数据类型转换
# 数据类型转换
# str -> bool
# 非空字符串为真,空字符串为假
collection
from collections import Counter #引入Counter
a = [29,36,57,12,79,43,23,56,28,11,14,15,16,37,24,35,17,24,33,15,39,46,52,13]
b = dict(Counter(a))
print ([key for key,value in b.items()if value > 1]) # 只展示重复元素
print ({key:value for key,value in b.items()if value > 1}) # 展现重复元素和重复次数
import collections
d1 = collections.OrderedDict() # 将普通字典转换为有序字典
d1['a'] = 1
d1['b'] = 2
d1['d'] = 4
d1['c'] = 3
for k, v in d1.items():
print(k, v)
d1 = {'a': '1', 'b': '2', 'd': '4', 'c': '3'}
d1 = collections.OrderedDict(d1)
for k, v in d1.items():
print(k, v)
# 3.7及以后版本dict插入顺序和存储顺序一致
类型提示,type hint
Python类型提示有type annotation和type comment两种方式,类型提示与linter协同工作,实际类型与类型提示不一致不影响运行时
typing库用于类型提示
pydantic做类型提示和类型检查
https://www.cnblogs.com/popapa/p/PEP484.html
https://peps.python.org/pep-0563/
Type Annotation
:语句将信息附加到变量或函数参数中,->运算符用于将信息附加到函数/方法的返回值中
import math
def circumference(radius: float) -> float:
return 2 * math.pi * radius
print(circumference.__annotations__)
def test(request_data: Any):
pass
from typing import Union
from typing import Optional
def f(l1: Optional[int] = None, l2: Union[int, str, None] = None):
"""
Optional是Union的特例
:param l1:
:param l2:
:return:
"""
print(l1, l2)
注:
- type annotation方式会导入所有类型提示中使用到的类型依赖,即使运行时中不会用到。
- 另外复合类型如List[str],解释器在首次加载文件时会执行一些操作构造该类型,Python 3.7时引入了 PEP-563 ~ postponed evaluation of annotations,使用
from __future__ import annotations避免类型构造
泛型类型提示
"""
Python 的类型提示基于泛型,简称泛型类型提示,静态检查工具基于泛型类型提示进行检查,解释器不会检查
"""
from typing import Generic, TypeVar, List
T = TypeVar('T') # 泛型类型变量T
class MyGenericClass(Generic[T]): # 泛型类
def __init__(self):
self.items: List[T] = []
def add_item(self, item: T): # 泛型函数
self.items.append(item)
# 使用
my_int_list = MyGenericClass[int]()
my_int_list.add_item(1)
my_int_list.add_item('1') # 此处 PyCharm 会有提示
print(my_int_list.items)
# [1, '1']
Type Comment
# headlines.py
def headline(
text, # type: str
width=80, # type: int
fill_char="-", # type: str
): # type: (...) -> str
return f" {text.title()} ".center(width, fill_char)
print(headline("type comments work", width=40))
Stub FIle
Stub FIle,存根文件,以.pyi为后缀,可参考https://www.cnblogs.com/popapa/p/PEP484.html
将demo.py和demo.pyi放在同一目录,在PyCharm中可以在.py、.pyi文件看到变量val和函数hello所在行有一个*标记,可以点击该标记在.py和.pyi之间跳转
# demo.py
val = 1
def hello(name):
return "Hello" + name
print(hello("World"))
print(hello(12345)) # PyCharm会报黄
# demo.pyi
val: int
def hello(name: str): ... # 函数体通常以...来省略细节
鸭子类型
鸭子类型,不通过其本身类型判断类型,而是通过其属性、表现判断。狗拿耗子,狗即为猫。
types
types,类型库,Python标准库
动态创建模块
import types
m = types.ModuleType("config")
def get_version():
print("mouse.bull.mouse")
setattr(m, "get_version", get_version)
print(m, type(m), m.__dict__)
m.get_version() # mouse.bull.mouse
代码分析
遍历元素性能分析
import time
l1 = list(range(10000))
t = time.perf_counter()
for i in range(10000):
if i in l1:
...
print(time.perf_counter() - t)
# 0.6000013
l2 = set(range(10000))
t = time.perf_counter()
for i in range(10000):
if i in l2:
...
print(time.perf_counter() - t)
# 0.0009529999999999816
迭代器切片
import itertools
# 与slice()区分
l1 = range(40, 50)
l11 = l1[2:30]
print(l11)
for i in l11:
print(i, end=" ")
print()
for i in l1:
print(i, end=" ")
print()
l2 = range(40, 50)
l22 = itertools.islice(l2, 2, 30)
for i in l22:
print(i, end=" ")
print()
for i in l2:
print(i, end=" ")
print()
# 生成的是副本
# 在 Python 中,对迭代器进行切片操作会创建一个新的迭代器,并且在对新的迭代器进行遍历时,会重新遍历整个切片范围内的元素。