Python——一些琐碎知识点
总结归纳了一些在牛客刷题中遇到的错误
目录
Python基础数据类型与操作
列表
字典
其他
Python高级特性
函数
类与对象
模块与包
Python标准库
pandas库
re模块
Python编程技巧
列表推导式
匿名函数
Python基础数据类型与操作
列表
-
列表乘法:
a=[2,3]
,print(a*2)
输出[2, 3, 2, 3]
,表示将列表a
中的元素重复两次,生成一个新的列表。 -
列表的复制与修改:
-
赋值引用:
b = a
,b
和a
指向同一个列表对象,对a
的修改会同时反映在b
上。 -
浅拷贝:
c = copy.copy(a)
,c
是a
的浅拷贝,生成一个新的列表对象,但内部的可变对象(如子列表)仍指向原对象。例如,a = [1, 2, 3, 4, ['a', 'b']]
,c = copy.copy(a)
,修改a[4].append('c')
,c
中的子列表也会被修改。 -
深拷贝:
d = copy.deepcopy(a)
,d
是a
的深拷贝,生成一个新的列表对象,并递归地拷贝所有内部对象。修改a
不会影响d
。
-
-
列表推导式:
-
a = [['1','2'] for i in range(2)]
,使用列表推导式创建了两个独立的子列表,每个子列表都是['1','2']
。 -
b = [['1','2']]*2
,将同一个列表['1','2']
复制两次,两个子列表指向同一个对象。修改其中一个子列表,另一个也会跟着改变。
-
-
列表的索引与切片:
-
a[::2]
表示从索引0开始,每隔一个元素取一个元素,直到列表结束。 -
a[-2:]
表示从倒数第二个元素开始到列表结束。 -
a[:-2:]
表示从索引0开始,到倒数第二个元素之前的所有元素。
-
字典
-
字典的
pop
方法:dicts.pop('c')
,从字典dicts
中移除键为'c'
的项,并返回对应的值。如果键不存在,会抛出KeyError
。 -
dict.fromkeys
方法:tmp = dict.fromkeys(['a', 'b'], 4)
,创建一个新的字典,键为['a', 'b']
中的元素,值为4
。
其他
-
布尔值测试:在Python中,空字符串、空列表、空元组、空字典、空集合、
None
、False
、数值0
等的布尔值为False
,其他为True
。 -
id
函数:id(l1) == id(l1.extend(l2))
,id
函数返回对象的内存地址。l1.extend(l2)
会修改l1
,但不会返回新列表,而是返回None
,所以id(l1.extend(l2))
实际上是None
的id
,与id(l1)
不同。
Python高级特性
函数
-
闭包:
adder
函数是一个闭包的例子。adder(x)
返回一个内部函数wrapper(y)
,wrapper(y)
可以访问外部函数adder
的变量x
。adder5 = adder(5)
,adder5
是一个指向wrapper
函数的引用,调用adder5(6)
会返回5 + 6 = 11
。 -
强制关键字参数:
def fun(a,*,b)
,b
是一个强制关键字参数,必须以b=
的形式传递,不能作为位置参数传递。
类与对象
-
魔术方法:
__getitem__
方法允许类表现得像序列,可以通过索引访问元素。Foo
类实现了__getitem__
方法,可以通过foo[pos]
访问元素。 -
鸭子类型:Python支持鸭子类型,只要一个类实现了某些方法(如
__getitem__
、__len__
等),它就可以表现得像某种类型的对象,而不需要继承自特定的类。
模块与包
-
__name__
属性:__name__
用于区分当前文件是被直接运行还是被导入。直接运行时,__name__
为"__main__"
;作为模块导入时,__name__
为模块名。
Python标准库
pandas
库
-
query
方法:df.query('x > @a')
,在pandas
中使用query
方法进行数据筛选时,如果要引用DataFrame外部的变量,需要在变量名前加上@
符号。
re
模块
-
正则表达式:
regex = r"[^c|p]ed"
,[^c|p]
匹配任何不是c
或p
的字符,ed
匹配字符串"ed"
。pattern.findall(mstr)
会返回所有匹配的子字符串。
Python编程技巧
列表推导式
-
嵌套循环:
shirts1 = [(size,color) for color in colors for size in sizes]
,列表推导式中包含两个嵌套的循环,外层循环遍历colors
列表,内层循环遍历sizes
列表。
匿名函数
-
lambda
函数:res = lambda x: x+x
,lambda
函数是一个匿名函数,可以用于简单的函数定义。res([1, 2, 3, 4])
会返回[1, 2, 3, 4, 1, 2, 3, 4]
,表示将列表[1, 2, 3, 4]
与自身拼接。
a=[2,3]
print(a*2) #[2, 3, 2, 3]dicts = {'a': 1, 'b': 2, 'c': 3}
#print(dicts.pop())
print(dicts.pop('c'))
'''
Python 中字典的 pop 方法需要至少一个参数(键)
dict.pop(key[, default])
'''import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')
print(a,"\n",b,"\n",c,"\n",d)
'''
在Python中,对象的复制分为三种情况:
1. 赋值引用(b = a): 指向同一个对象
2. 浅拷贝(copy.copy()): 创建新对象,但内部的引用对象仍指向原对象(共享列表中的列表)
3. 深拷贝(copy.deepcopy()): 创建新对象,同时递归地拷贝所有内部对象
'''#a = [['1','2'] for i in range(2)]
b = [['1','2']]*2
a[0][1] = '3'
b[0][0] = '4'
print(a,b)
'''
列表的浅拷贝和深拷贝
a = [['1','2'] for i in range(2)] 是使用列表推导式创建了两个独立的子列表,每个子列表都是['1','2']。这种方式创建的是独立的对象。
b = [['1','2']]*2 是将同一个列表['1','2']复制两次,这种方式创建的两个子列表实际上指向同一个对象。
当执行 a[0][1] = '3' 时,只会修改第一个子列表的第二个元素,变成['1','3'],第二个子列表保持不变,仍是['1','2']。
当执行 b[0][0] = '4' 时,由于b中的两个子列表指向同一个对象,所以修改其中任意一个,另一个也会跟着改变,因此两个子列表都变成了['4','2']。
'''class Person:def __init__(self):passdef getAge(self):print(__name__)
p = Person()
p.getAge()
'''
__name__ 的作用:
用于区分当前文件是被直接运行还是被导入。
直接运行时,__name__ 为 "__main__"。
作为模块导入时,__name__ 为模块名。
'''#tmp = dict.fromkeys(['a', 'b'], 4)
print(tmp)
'''
dict.fromkeys() 是一个类方法,它用于创建一个新的字典,其中包含从指定序列(如列表或元组)中提取的键,每个键都映射到指定的值。
语法:dict.fromkeys(iterable, value=None)
iterable:一个可迭代对象,其元素将用作字典的键。
value:一个值,将被分配给每个键。如果省略,每个键将被分配默认值 None。
'''#def adder(x):def wrapper(y):return x + yreturn wrapper
adder5 = adder(5)
print(adder5(adder5(6)))
'''
调用 adder(5) 时:
创建了一个新的 wrapper 函数,此时 x 被设置为 5。
adder5 现在是一个指向这个 wrapper 函数的引用。首先,调用 adder5(6):
adder5 是 wrapper 函数,其中 x = 5。
wrapper(6) 返回 5 + 6 = 11。
然后,调用 adder5(11):
adder5 仍然是 wrapper 函数,其中 x = 5。
wrapper(11) 返回 5 + 11 = 16。
'''#if " ":print(1)
else:print(0)
'''
Python中布尔测试
1. 任何对象都可以进行布尔测试
2. 以下情况的布尔值为False:
- None
- False
- 值为0的任何数值类型(0, 0.0等)
- 空序列(空字符串、空列表、空元组、空字典等)
- 空集合
'''#l = []
for i in range(2):r = [1]* 2l.append(r)
l[0][0] = 2
print(l)
'''
由于列表 r 在每次循环中都是新创建的,所以 l 中的两个子列表是不同的对象。
因此,当修改 l[0][0] 时,只会影响第一个子列表的第一个元素,
而不会影响第二个子列表。
'''#l1 = [1,2]
l2 = [3,4]
print(id(l1) == id(l1.extend(l2)))
'''
l1 是一个包含两个元素 [1, 2] 的列表。
l2 是另一个包含两个元素 [3, 4] 的列表。
l1.extend(l2) 方法将 l2 中的所有元素添加到 l1 的末尾。
这个操作不会返回一个新的列表,而是直接修改 l1。
因此,id(l1) 和 id(l1.extend(l2)) 都指向同一个列表对象在内存中的地址。
由于 l1.extend(l2) 不返回新列表,而是返回 None,
所以 id(l1.extend(l2)) 实际上返回的是 None 的 id,这与 id(l1) 是不同的。
'''#import pandas as pd
df = pd.DataFrame({'x':[1, 2, 3, 4], 'y':[3, 4, 5, 6]})
a = df.x.mean()
print(df.query('x > @a'))
'''
在pandas中使用query()方法进行数据筛选时,
如果要引用DataFrame外部的变量,需要在变量名前加上@符号
'''#def fn():t = []i = 0while i < 2:t.append(lambda x: print(i*x,end=","))i += 1return t
for f in fn():f(2)
'''
匿名函数的行为:
在 Python 中,匿名函数(lambda)会捕获变量的引用,而不是变量的值。
这意味着在匿名函数中使用的变量 i 是在函数被调用时的值,而不是定义时的值。
返回的列表 t:
t 包含两个匿名函数:
第一个匿名函数是在 i = 0 时添加的。
第二个匿名函数是在 i = 1 时添加的。
但是,由于 i 是在函数外部定义的,当这些匿名函数被调用时,它们会捕获 i 的最终值,即 i = 2。
'''#a = 0
for i in range(5):a += i
print(i, a) #i不会自加
#
#
#
a = '123'
b = '123'
print(a is b)
'''
在 Python 中,字符串是不可变对象,当我们创建两个内容相同的字符串字面量时,
为了节省内存,Python 解释器会让它们指向同一个对象。
这就是字符串驻留(string interning)机制。Python中的is运算符和==运算符是不等价的,它们有着本质的区别:1. is运算符用于判断两个对象是否是同一个对象(即比较对象的身份标识,id是否相同)
2. ==运算符用于判断两个对象的值是否相等(即比较对象的值)举例说明:
```python
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True,因为列表的值相等
print(a is b) # False,因为是两个不同的列表对象x = 256
y = 256
print(x == y) # True
print(x is y) # True,因为小整数对象池的缘故m = 257
n = 257
print(m == n) # True
print(m is n) # False,超出了小整数对象池范围t1 = (1,2)
t2 = t1[:]
print(t1 is t2) #True
print(t1 == t2) #True
对于元组,如果元组内部的元素都是小整数,Python也会重用这些元组对象。虽然在某些特定情况下(如小整数、小字符串等)它们的结果可能相同,
但这只是Python对象重用机制导致的特殊现象,不能说明两个运算符等价。
在大多数情况下,is和==的结果是不同的。
'''#a = 100
b = 14
print(divmod(a, b))
'''
divmod() 函数是一个内置函数,它用于计算两个数相除的商和余数,并将这两个结果以元组的形式返回
'''#strs = '123456'
print(strs.find('9')) # -1
'''
与数据容器有关的异常:
IndexError:访问序列(列表、元组、字符串)时使用了无效的索引。
KeyError:访问字典时使用了不存在的键。
TypeError:对数据容器执行了不支持的操作,例如,尝试对只读数据容器进行修改。
ValueError:向数据容器提供无效值,例如,给集合(set)添加重复元素。
AttributeError:尝试访问数据容器不存在的属性或方法
'''#lists = [1, 2, 3, 4]
tmp = 0
for i,j in enumerate(lists): # i,j分别对应索引和值tmp += i * j
print(tmp) #20 = 0*1+1*2+2*3+3*4#set_empty={}
set_empty2=set()
print(type(set_empty)) #dict
print(type(set_empty2)) #set#a=[2, 4, 6, 8, 20,30,40]
print(a[::2])
print(a[-2:]) # [30,40]
print(a[:-2:]) #[2, 4, 6, 8, 20],不包含30#func = lambda x:x%2
result = filter(func, [1, 2, 3, 4, 5])
print(list(result))
'''
filter() 函数返回一个迭代器,其中包含所有让 func 返回 True 的元素。
在这个例子中,func 返回 True 的是奇数(余数为1),
所以 result 迭代器将包含列表中的所有奇数
'''#lists = [1, 2, 3, 4, 5, 6]
print(lists[6:]) #[]
'''
lists[6:] 表示从索引6开始到列表结束的所有元素。
由于列表索引是从0开始的,索引6实际上是列表中的最后一个元素(值为6的元素)。
因此,lists[6:] 将返回一个包含从索引6开始到列表末尾的所有元素的新列表。
'''#strs = 'abcd12efg'
print(strs.upper().title())
'''
strs.upper() 会将字符串 strs 中的所有小写字母转换为大写,得到 'ABCD12EFG'。
然后,title() 方法将这个结果中的每个单词的首字母转换为大写,其余字母转换为小写。
但是,由于字符串 'ABCD12EFG' 中没有空格分隔单词,
title() 方法会将整个字符串视为一个单词,并将第一个字母转换为大写,其余字母转换为小写,
得到 'Abcd12efg'。
'''#def outer():def inner():print('inner',end=" ")print('outer',end = " ")return inner
outer()
outer()()
'''
如果要执行inner函数,需要在最后加上()进行调用,如outer()()
- 函数作为返回值时,如果没有调用操作(),该函数不会被执行
- Python中函数也是对象,可以作为返回值传递
'''class Foo():def __init__(self):passdef __getitem__(self,pos):return range(0,30,10)[pos]
foo = Foo()
'''
鸭子类型(Duck Typing)
Python 是一种支持鸭子类型的语言,这意味着如果一个对象实现了某些方法,那么它就可以表现得像某种类型的对象,而不需要继承自特定的类。例如,只要一个类实现了 __getitem__ 和 __len__ 方法,它就可以表现得像一个序列。
魔术方法(Magic Methods)Python 中有一些特殊的方法,通常称为魔术方法或双下方法,它们允许你定义或修改对象的行为。以下是一些常见的魔术方法:
__init__(self, ...):类的构造函数,用于初始化对象。
__del__(self):类的析构函数,用于清理对象。
__str__(self):返回对象的字符串表示,用于 print() 函数。
__repr__(self):返回对象的官方字符串表示,用于 repr() 函数。
__len__(self):返回对象的长度,用于 len() 函数。
__getitem__(self, key):定义对象如何使用索引访问其元素。
__setitem__(self, key, value):定义对象如何设置其元素的值。
__iter__(self):返回迭代器对象,用于 for 循环。
__next__(self):返回迭代器的下一个元素。
__contains__(self, item):定义对象是否包含某个元素,用于 in 操作符。序列类型
在Python中,序列类型(如列表、元组、字符串)支持以下操作:
索引访问:使用 obj[index] 访问元素。
切片操作:使用 obj[start:stop:step] 获取子序列。
长度获取:使用 len(obj) 获取元素个数。
迭代:使用 for 循环遍历元素。
成员测试:使用 item in obj 检查元素是否存在。
要使一个类表现得像序列,通常需要实现以下方法:
__getitem__(self, index):定义如何使用索引访问元素。
__len__(self):定义如何获取元素个数。
__iter__(self):定义如何迭代元素(可选,如果需要支持 for 循环)。
'''def fun(a,*,b):print(b)
# fun(1,2,3,4)
fun(1, b=2)
'''
1. 普通位置参数
这些是最基本的参数类型,函数调用时需要按顺序提供这些参数的值。
2. 默认参数
这些参数在函数定义时就给定了默认值,调用时可以不提供这些参数,将使用默认值。
3. 可变位置参数(*args)
使用 *args 可以接收任意数量的位置参数,这些参数在函数内部以元组的形式存在。
4. 可变关键字参数(**kwargs)
使用 **kwargs 可以接收任意数量的关键字参数,这些参数在函数内部以字典的形式存在。
5. 强制关键字参数(仅Python 3)
在函数定义中,通过在参数名前加一个星号(*)来指定强制关键字参数。这意味着这些参数必须以关键字形式传递,不能作为位置参数传递。# 正确的调用方式
fun(1, b=2) # 输出: 2
# 错误的调用方式,会引发TypeError
fun(1, 2) # TypeError: fun() takes 2 positional arguments but 3 were given
在这个例子中,b 是一个强制关键字参数,必须以 b= 的形式传递。
'''sizes = ['S','M']
colors = ['white','black']
shirts1 = [(size,color) for color in colors for size in sizes]
#[('S', 'white'), ('M', 'white'), ('S', 'black'), ('M', 'black')]
shirts2 = [(size,color) for size in sizes for color in colors ]
#[('S', 'white'), ('S', 'black'), ('M', 'white'), ('M', 'black')]
print(shirts1)
print(shirts2)
'''
[(size,color) for color in colors for size in sizes]
列表推导式中包含两个嵌套的循环,
外层循环遍历 colors 列表,
内层循环遍历 sizes 列表。
'''dict1 = {'Name': 'nowcoder', 'num':{'first': '99', 'second': '88'}, 'age': '15'}
print(dict1.get('first')) #None
'''
返回 -1:特定方法(如字符串的 find())在未找到目标时返回 -1。
抛出异常:索引越界、键错误、类型错误等情况下会抛出相应异常(如 IndexError、KeyError、TypeError)。
返回 None:字典的 get() 方法在没有找到键时返回 None。函数如果没有显式返回值,默认返回 None。
'''import re
mstr = r"red hed ced ped"
regex = r"[^c|p]ed"
pattern = re.compile(regex)
print(pattern.findall(mstr))
'''
regex = r"[^c|p]ed":定义一个正则表达式。
[^c|p]:匹配任何不是 c 或 p 的字符。
ed:匹配字符串 "ed"。普通字符:直接匹配字符本身,如 a 匹配 a,abc 匹配 abc。
特殊字符:一些特殊字符具有特定的意义,如 . 匹配任意单个字符(除了换行符),* 表示前面的字符可以出现零次或多次。
字符类:[abc] 匹配 a、b 或 c 中的任意一个字符。[a-z] 匹配任意一个小写字母。[^abc] 匹配除 a、b、c 之外的任意字符。
预定义字符集:\d 匹配任意数字,等同于 [0-9]。\D 匹配任意非数字字符。\s 匹配任意空白字符(包括空格、制表符、换行符等)。\S 匹配任意非空白字符。\w 匹配任意字母、数字或下划线,等同于 [a-zA-Z0-9_]。\W 匹配任意非字母、非数字、非下划线的字符。
量词:* 表示前面的字符可以出现零次或多次。+ 表示前面的字符至少出现一次。? 表示前面的字符可以出现零次或一次。{n} 表示前面的字符恰好出现 n 次。{n,} 表示前面的字符至少出现 n 次。{n,m} 表示前面的字符至少出现 n 次,最多出现 m 次。
分组:使用圆括号 () 将多个字符组合成一个组,可以对整个组进行量词匹配。
选择:使用竖线 | 表示选择,匹配左边或右边的表达式,如 cat|dog 匹配 cat 或 dog。
转义:使用反斜杠 \ 对特殊字符进行转义,使其失去特殊意义,如 \. 匹配点号 .。
断言:正向先行断言 ?= 匹配后面跟着特定模式的字符串。正向后发断言 ?! 匹配后面不跟着特定模式的字符串。负向先行断言 ?! 匹配前面不跟着特定模式的字符串。负向后发断言 ?<! 匹配前面跟着特定模式的字符串。
贪婪与非贪婪:默认情况下,量词是贪婪的,尽可能多地匹配字符。在量词后添加 ? 使其变为非贪婪,尽可能少地匹配字符。
'''res = lambda x: x+x
print(res([1, 2, 3, 4])) #[1, 2, 3, 4, 1, 2, 3, 4]
'''
列表的加法表示列表的拼接
'''