Skip to content

杂项

约 2078 个字 81 行代码 预计阅读时间 8 分钟

关于输入输出

  • print函数输出字符串,如果不打逗号是不会有空格的,打了逗号会有一个空格
print("hello""world")
# helloworld
print("hello" "world")
# helloworld
print("hello", "world")
# hello world
print("hello","world")
# hello world
  • 格式化字符串
  • C风格:Python中一般不使用

    print("My name is %s and I am %d years old." % (name, age))
    
  • str.format():Python风格的格式化字符串

    print("Pi is approximately {:.2f}".format(3.1415926))  # 保留2位小数
    
  • f-string,新的格式化字符串

    num = 1
    print(f"{num:5d}")
    print(f"{num:<5d}")  # 左对齐,宽度为5
    print(f"{num:^5d}")  # 居中对齐
    print(f"{num:*^5d}")  # 居中对齐并用*填充
    
  • print(f"{3.1415926:.2}")输出是3.1,因为这个并不是保留两位小数而是保留两位有效数字,根本原因是没有指定类型,所以触发了默认的有效位数,正确的保留两位小数应该是print(f"3.1415926:.2f}")

  • Python的默认对齐方式是字符串左对齐(<),数字右对齐>

关于类型转换

  1. Python始终是动态类型的语言,即便如今有什么类型提示之类的东西,类型提示的语法def f(text : str) -> None
  2. int(num, base=10) 如果是不写第二个参数,那么默认是十进制,可以处理各种类型,包括字符串,类比特对象或者是一个实数,但是不能为空
int(10)
# 10
int(10.6)
# 10
int("10")
# 10
int(None)
# TypeError

第二参数代表从多少进制转换到十进制,默认是十进制,如果写了第二个参数,第一个参数就必须是字符串

int("10" 8)
# 8
int(10.5, 2)
# TypeError

关于列表

  • Python的list是支持存储不同类型的元素的
  • Python的list可以比较大小,比较方法和字符串一样
  • [4, 5] * 3的结果为[4, 5, 4, 5, 4, 5]
  • 列表喜欢考切片slice,形如[begin:end:step],但是可以省略参数,具体是哪个参数是按:来确定的,还有就是Python支持反向索引,最后一个元素的编号是-1
  • 列表切片超出索引范围也不会报错,但是直接访问越界会报错IndexError
  • 切片赋值语法,可以用切片接受一个别的列表,用来替换切片所表示的那一段
l = [1, 5]
l[1:1] = [2, 3, 4]
# 操作后 l是[1, 2, 3, 4, 5]
# 但是注意,如果是把切片赋值给一个变量,那么这个变量是列表的浅拷贝
  • 列表生成式可以带筛选条件
l = [x for x in range(10) if x % 2 == 0]

关于dict

  • dict是没有默认值的,访问不存在的键会抛出错误,如果要修改键值应该先检查有没有
  • 字典理论上是按照插入顺序保持元素的,但它不被认为是有序的
  • items返回键值对视图
  • dict创建在使用dict()时是用的关键字参数,所以参数本身是不打引号的,比如d = dict(name="Alice", age=30)
  • 字典推导式:同时指定键值对,d = {k:v for k,v in ["12", "34", "56"]},这个会发生拆包,比如"12"会被拆成"1""2"

关于set

  • 添加是add,删除是remove,还有一个discard用于删除,区别是不存在不会抛出错误
  • 交集|,并集&,差集是-,对称差集是^

关于字符串

内置方法的方法名看起来都是小写的

  • 大小写处理,包括upper()lower()
  • 查找与替换,find找不到会返回-1,但是index找不到会报错
  • 分割与连接:分割使用split,连接使用join
  • 判断类型:isalpha()isdigit()isalnum(),islower(),isupper()

拆包和解包

  • i, *j = [1, 2, 3]的结果为i=1, j=[2, 3]
  • print(*[1,2,3])的结果为1 2 3

列表去重

l = ['a', 'e', 'd', 'f', 'e']
l_ = list(set(l))
print(l_)
# sort 的关键字参数 key 传递的是一个可调用对象
# 这个对象接受一个参数,然后返回一个可比较的值
# 一般是函数(有可能是匿名的)
l_.sort(key=l.index)
print(l_)

关于垃圾回收

Python 显然是自动管理内存的,但是也提供了手动删除的方式del,可以del object[index/key...]del object,如果索引不存在会抛出IndexError

关于内置函数

  • print(bin(12.5))这个是错的,因为bin只接受整数
  • int("92",8),八进制怎么可能会有9的出现!?
  • "34" in "1234"==True"34" in "1234"确实是正确的,但是这个表达式的优先级有问题,in的优先级很低
  • 3 and 0 and "hello"这个的结果是0,0不是False
  • list("abcd")的结果是['a','b','c','d']list可以把一个可迭代对象转化成列表
  • '3//11//2018'.split('/')这个是正斜杠,而不是反斜杠,着实难绷(
  • print("{:>08s}".format(bin(31)[2:])),内置函数bin输出有个0b,[2:]其实是去除前缀
  • Python只有字符串有find,列表那些应该用内置运算符in或者index
  • Pythonrandom.randint(m,n)默认是区间,但random.randrange(m,n)是左闭右开的
  • 对于列表而言,in只能检查单个数值是否在列表中,[2 ,3] in [1, 2, 3, 4]的结果是False,但是对于字符串而言,in可以检查某个字符串是否是另一个字符串的一部分
  • sort有两个关键字参数,一个是key,表示排序所使用的键,另一个是reverse表示是否要降序,如果你想要按照多个元素排序,那么可以用一个元组作为排序元素,sortlist的类方法,所以可以list.sort()
  • sort需要看清楚排序对象是数字还是数字字符串
  • join作用于字符串相当于先把字符串转化为列表,再拼接列表
  • eval可以进行任意代码执行,但是第一个参数必须是字符串,比如a,b=eval(input().split())就是错误的
  • abs是内置函数,fabsmath包中,abs可以用于复数,但是fabs不能

关于函数

  • Python 允许使用内置函数名作为自定义函数名,但是会覆盖内置函数
  • Python 如果当前文件名和包名相同会发生冲突,大概会报错找不到对应的库
  • from math import sin实际上并未导入math包,只导入了sin这个函数,输入math.sin会报错name 'math' is not defined
  • import math as m实际上导入了math包的,但是这个包现在的名称是m,直接用math会报错
  • 关键字参数必须在位置参数后面,位置参数已经对应了的参数不能重复赋值

python中的函数都是对象,所以如果去查函数的类型会返回function,但是用print去输出就不一样了,对此的解释为type()返回值的类型为type,返回值本身确实是function,但是要使用print输出需要调__repr__转化为字符串

# 假设是在交互式解释器环境,f是一个函数
type(f) # 结果应该是function
print(type(f)) # 结果应该是<class 'function'>

关于异常

Python的异常捕获格式长这样,异常本质上是一个对象,所以可以自定义异常:

class MyError(Exception):
    pass

try:
    raise MyError("这是一个自定义异常")
except MyError as e:
    print(f"捕获到自定义异常:{e}")

浅拷贝和深拷贝

对于简单类型,浅拷贝和深拷贝其实没什么区别,因为它们是不可变的,id()Python中返回一个对象的“标识值”,这个标识值是一个整数,它在对象生命周期中是唯一且恒定的,可以把它理解为对象的地址。

a = 1
b = a
# 对于小的整数和字符串,Python 会进行对象复用,所以id可能相同
# 考试应该不至于这么考这么神经的,我实测也是 True
print(id(a) == id(b))
# 但是修改了之后就一定可以看出区别了
a = 2
print(id(a) == id(b)) # False,此时 a = 2 , b = 1

但是对于可变类型的拷贝,浅拷贝和深拷贝是可能有区别的,Python中的copy模块提供了浅拷贝和深拷贝,浅拷贝是copy.copy,深拷贝是copy.deepcopy

# 这里依次列举所有可能情况,非常容易混,主要是解释器有些时候的行为比较 confusing
l1 = [1, 2]
l2 = l1 # l1 和 l2 是同一个对象,因为赋值其实是赋值的指针
l3 = l1[::] # l1 和 l3 是不同的对象,因为切片是浅拷贝
l4 = copy.copy(l1) # l1 和 l4 是不同的对象,因为 copy.copy 是浅拷贝
l5 = copy.deepcopy(l1) # l1 和 l5 是不同的对象,因为 copy.deepcopy 是深拷贝

单层的列表深浅拷贝其实看不出区别,但是多层的列表深拷贝和浅拷贝是不同的

l1 = [1, [2, 3]]
l2 = l1.copy()
l3 = copy.deepcopy(l1)
l1[0] = 4
l1[1][0] = 5
print(l2) # [1, [5, 3]]
print(l3) # [1, [2, 3]]

其他

  • \ooo(三位八进制数)或者\xhh(两位十六进制数)都表示一个转义字符,比如\141表示a\x61也表示a
  • ascell码'0'是48,A是65,a是97,大小写之间差32
  • float类型的默认输出会带小数点,比如2//1的结果是2,但是2//1.0的结果是2.0
  • 题目中的在程序填空题可以忽略
  • Python 的==是按照值相等,实际调用__eq__,而不是根据是不是同一个对象,is才是比较是不是同一个对象,即地址相等,id也是比较是不是为同一个对象
  • Python的赋值是浅拷贝,准确说连拷贝都不是,实际上只是创建一个指针指向等号右边的对象,copy.copy()、切片、list.copy()等是浅拷贝
  • 序列赋值a,b = "12",这个的结果是a="1", b="2"
  • 运算符优先级大概是幂、正负、乘除取模、加减、比较、逻辑否、与、或
  • **是右结合的
  • split()会使用任意空白字符作为分隔符进行分割,split(' ')按单个空格进行分割,多个空格被视为多个分隔符,并且会生成空的子字符串
"a   b".split() # 结果为 ['a', 'b']
"a   b".split(' ') # 结果为 ['a', '', ' ', 'b']
  • 只有strfind方法,
  • enumerate()可以在遍历时获取索引
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(f"索引: {index}, 水果: {fruit}")
'''
索引: 0, 水果: apple
索引: 1, 水果: banana
索引: 2, 水果: cherry
'''

运算符优先级

  1. 括号()
  2. 指数**
  3. 一元+-
  4. 乘除*///%
  5. 加减+-
  6. 比较<><=>===!=
  7. 身份运算符:in,not in
  8. 成员运算符:is,is not
  9. 逻辑运算符:notandor
  10. 赋值运算符:=+=-=*=/=//=%=