Python编程笔记,各种易忘点总结
持续更新
快速排序和归并排序参数不可使用list子列表
- 注意使用子列表时是一个新对象,操作子列表与原始list无关
- 在快速排序和归并排序中不可将子列表传入,以期待可以从函数中修改原始列表的值
list初始化
1 | l = [0] * 10 |
list.count函数的应用
1 | l = [1, 3, 2, 3, 3, 3] |
str是一个不可变对象
1 | s = "12345" |
Random的应用
1 | import random |
- 输出一个[start, end]之间(包括start和end)的随机数
sorted函数不修改原始数组
- sorted函数不修改原始数组
- a.sort()会修改原始数组
1
2
3
4
5
6
7
8l = [1,3,4,2]
l1 = sorted(l)
print l, l1
l.sort()
print l
# output
[1,3,4,2] [1,2,3,4]
[1,2,3,4]
sorted参数cmp和key比较
- key是个单参数函数,返回值为一个可用于比较的值即可
- cmp是个双参数函数,返回值为-1, 1, 0,分别表示小于,大于,等于
- 特别注意不是返回True和False
- 二者均可作为排序的比较函数
Python数值类型自动转换
- 强制类型转换: int(a)
- 隐式转换
- boolean 型转int型: True =1 False =0
- 自动类型提升: int型转float型
- 注意: 两个int型的除法不会保留小数,这点与C++一致
关于bool
- if判断语句中,实际上时调用
bool(object)
bool(object)
调用的时object.__bool__()
- 如果一个对象没有实现
__bool__
方法,那么会尝试调用__len__
方法- 返回为0时表示False
- 否则返回True
对象ID
- Python中对象的ID类似于其他语言中对象的地址
- 调用方法为
1
2id(object)
# Output: 4332312578
运算符号的内部实现
- + 和 +=
- +: add()
- +=: iadd()
- 当没有iadd()时Python解释器会调用add()
- * 和 *=
- *: mul()
- *=: imul()
- 当没有imul()时Python解释器会调用和mul()
- 不可变变量,比如tuple也可以调用
*=
和+=
,表现也是一样的,只是对象id会改变,等价于调用了__add__()
然后又赋值给当前变量*1
2
3
4tu1 = (1,2,3)
tu2 = (2,3,4)
tu1 += tu2 # <==> tu1 = tu1 + tu2, id of tu1 will change
# Output: (1,2,3,2,3,4)
尽量避免使用最小整数
- 需要初始化一个最小值,然后方便求得某个序列的最大值,此时可以初始化为某个可能的值,从而避免寻找最小整数的尴尬,可能会找错,初始化错的话很容易造成后面结果都错
参数”key
“
一些需要比较功能的函数都会有此参数
- key参数是一个函数,这个函数接受一个唯一的对象,然后返回用于比较的值,外层函数比较时会使用key函数返回值进行比较
- 比如可用与字符窜长度
key = len
排序,忽略大小写排序key = str.lower
比较等功能
- 比如可用与字符窜长度
- 可用于list.sort(), sorted(), min(), max()等函数
- 另外一些其他标准库也会接受这个参数,用法相似
Foreach局部变量
- Python for循环语句中的“局部”变量与Java中的不同
1
2
3# Python
for i in range(0, 10):
pass
1 | // Java |
- 上面的代码执行完之后i的值为多少?
- Java中
i
是局部变量,所以在代码执行完成后变量i
是不能访问的 - Python中
i
是全局变量,所以i的值为最后一次迭代的值9
- Java中要实现与Python相同的效果,可以使用全局变量(将i的定义放到for循环外面即可)
- Java中
函数内部定义函数时注意
- 注意内部函数是否访问到Inner外的变量
- 如果某个函数Otter只被访问一次且另一个函数Inner只被Otter访问,那么Inner一般定义在Otter内部比较合适
正则表达式匹配完整字符串
- 必须使用^和$, 否则部分匹配也会返回结果
1
2
3
4
5import re
def totally_match(pattern, string):
if re.match(pattern, string) is not None:
return True
totally_match(r"^cat$", "cat")
函数定义后再定义全局变量
1 | def visit(): |
Python无穷大的数
常用的是无穷大的实数:
- 正无穷: float(‘inf’)
- 负无穷: float(‘-inf’)
运算:
Python里面的无穷大与C++不同,C++里面是定义一个最大的整数实现,Python里面可以视为一个无穷大的对象
和数学分析里面一样,我们可以和无穷大做计算,加上无穷大还是无穷大
1
2
3
4
5
6
7
8
9
10
11
12
13x = float('inf')
print x
print x - 1
print x + 1
print x + x
print x - x
# output
inf
inf
inf
inf
nan- 无穷大减去无穷大为一个未知结果nan
- 判断一个数是否为nan,
nan == nan
返回False
复制一个普通列表时不要用copy模块
copy.deepcopy支持对可变对象的深度复制,直到解析到不可变对象为止
1
2
3import copy
list1 = [1,3,4,[5,6]]
list2 = copy.deepcopy(list1)如果list对象元素都是不可变对象,那么可以有简便实现
1
2list1 = [1,3,4,5,6]
list2 = list1[:]测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import copy
list1 = [1, 3, 4, [5, 6]]
l1 = list1[:]
l2 = copy.deepcopy(list1)
l3 = copy.copy(list1)
l4 = list1
list1.append(10)
list1[3].append(7)
print "l[:]", l1
print "deepcopy", l2
print "copy", l3
print "l", l4
# output
l[:] [1, 3, 4, [5, 6, 7]]
deepcopy [1, 3, 4, [5, 6]]
copy [1, 3, 4, [5, 6, 7]]
l [1, 3, 4, [5, 6, 7], 10]
not " "
返回的是False
- 在编程时容易错误的以为空白就是没有,所以容易认为
not " "
是True
" "
不是什么都没有,而是有个space字符
- 实际上只有空字符串,空列表和
None
等是空的,not None
,not []
,not ''
等均为True
1
2
3
4
5
6
7
8
9
10
11
12
13
14print not " "
print not ""
print not []
print not None
print not 0
print not -1
# output:
False
True
True
True
True
False
Python中32位最小和最大整形数
1 | # max |
使用abs(n)求n的绝对值
1 | print abs(-11) |
使用整除符号//
1 | print 3.5 // 2 |
//
是整除符号,只保留整数部分,但是结果的类型可能为整数,也可能为浮点数,具体取决于除法两边是否含有浮点数
list中的子列表
1 | l = [1,2,3,4,5] |
- list
l
中使用-1
可以理解为len(l)-1
,不管是字列表还是元素的索引操作
sorted的返回值总是list
- 即使传入的是一个string,返回值也是list,需要牢记
1
2
3print sorted("1523")
# output:
['1', '2', '3', '5']
Python的for循环语句结束时i的值与Java不同
Python
1
2
3
4
5
6for i in range(0, 5):
print i
print "final:", i
# output
0 1 2 3 4
final: 4Java/C++
1
2
3
4
5
6
7
8
9int i;
for(i = 0; i < 5; i++){
System.out.print(i);
}
System.out.print("final:")
System.out.print(i)
# output
0 1 2 3 4
final: 4如果想得到Java/C++的效果,可以使用while语句
1
2
3
4
5
6
7
8i = 0
while i < 5:
print i
i+= 1
print "final:", i
# output
0 1 2 3 4
final: 4
join函数调用的条件
特别注意: join函数的参数只能是字符串,不能是数字
1
2
3
4
5l = [1,2,3,4]
print ''.join(l)
# output
TypeError: sequence item 0: expected string, int found- 使用非string元素的列表时抛出TypeError的错误
dict.get()
原始定义
1
dict.get(key[,default=None])
default
参数可以指定默认值,当key
值不存在时可以返回默认值,如果不指定,则默认key
值不存在时返回None
与
dict[key]
对比- 使用
dict[key]
时要确保key
在dict
中,否则会报异常
- 使用
一行太长的代码需要分多行
必须在每个子行行尾部使用
\
子行内部不用对齐,因为解析时Python解释器会将所有子行合并成一行
示例:
1
2if 9 < 10 and 11 < 12 and 13 < 14:
print "works"等价于
1
2
3
4if 9 < 10 and \
11 < 12 and \
13 < 14:
print "works"等价于
1
2
3
4if 9 < 10 and \
11 < 12 and \
13 < 14:
print "works"
全局变量只要在函数调用前声明就行了
- 我们定义函数时,函数里面的变量可以没有定义
- 调用函数的时候,默认这个函数中没定义过的变量都是全局变量,函数会主动寻找相关的全局变量,找不在再报错
- 核心: 定义函数时函数中没定义的变量被使用了(如
x=10
这样的赋值算是变量的定义,不是使用),那么默认函数认为他是全局变量,当函数被调用的时候,才会寻找全局变量是否在当前Python运行环境中 - 所以,可以先定义函数,再初始化(定义全局变量),最后调用函数
- 只要初始化全局变量在调用函数之前即可
- 但是需要注意函数中不能给全局变量赋值,被赋值的变量将被函数认为是局部变量
1
2
3
4
5
6
7
8def sum_x(y):
return x+y
x = 100
print sum_x(10)
# output
110
使用列表切片修改列表
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18a = [1,2,3,4,5,6]
b = [1,2,3,4,5,6]
c = [0,0,0,0,0,0]
a[:2] = c[:2]
print(a)
d = b[:2]
d[:] = c[:2]
print(d)
print(b)
b[:2] = [0]
print(b)
# Output:
[0, 0, 3, 4, 5, 6]
[0, 0]
[1, 2, 3, 4, 5, 6]
[0, 3, 4, 5, 6]- 列表切片在左边时,可以修改数组内部数据,甚至是长度都可以修改(最后两行代码)
- 列表切片在右边时,表现为复制一份列表返回给变量
d
,所以修改d
的值将不影响原始的列表b
使用del
删除列表或字典中的元素
删除列表或字典中的元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17l = [1, 2, 3]
d = {"m": 10, "x": 11}
print(l)
print(d)
del l[0]
print(l)
del l[0]
print(l)
del d["m"]
print(d)
# Output:
[1, 2, 3]
{'m': 10, 'x': 11}
[2, 3]
[3]
{'x': 11}注意不能删除元组中的元素
1
2
3
4
5
6
7
8t = (1,2,3)
del t[1]
# Output:
Traceback (most recent call last):
File "/home/jiahong/JupyterWorkspace/test2.py", line 13, in <module>
del t[1]
TypeError: 'tuple' object doesn't support item deletion
dict.keys()返回的是列表吗?
代码示例
1 | d = {"m": 10, "x": 11} |
Python 2.7中输出
1 | ['x', 'm'] |
Python 3.6中输出
1 | dict_keys(['m', 'x']) |
总结
- Python2.7中输出是列表,丢失了
set
信息,占用空间小,但是会造成使用x in d.keys()
时变成线性搜索时间 O(n) - Python3.6中输出是
dict_keys
类型的对象,保留了set
信息,占用空间也大了,便于使用x in d.keys()
时变成常数搜索时间 O(1)
列表切片的详细说明[::-1]
切片完整用法
1
li[start:end:step]
start
: 开始索引,包含li[start]
,默认为0
end
: 结束索引, 不包含li[end]
,默认为len(li)
step
: 跳着取元素,step
为间隔,默认为1
step
可以设置为负, 此时若start > end
则能得到,从[start,end]
结束的序列,包含li[start]
, 不包含li[end]
, 由于此时start > end
, 所以得到的是逆序列- 注意: 若
step
参数省略的话第二个:
也能省略
代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19A = [0,1,2,3,4,5,6,7,8,9]
print(A)
print(A[::-1])
print(A[::-2])
print(A[::1])
print(A[::2])
print(A[1:5:])
print(A[1:5:])
print(A[5:1:-1])
# Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[9, 7, 5, 3, 1]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8]
[1, 2, 3, 4]
[1, 2, 3, 4]
[5, 4, 3, 2]
vars
函数的使用
定义
1
2
3
4
5
6
7
8def vars(p_object=None): # real signature unknown; restored from __doc__
"""
vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
"""
return {}vars(object)
返回对象的字典
代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class A:
def __init__(self):
self.a = 10
self.b = "abc"
def getA(self):
self.c = "100"
a = A()
print(A.__dict__)
print(vars(A))
# Output:
{'__module__': '__main__', '__init__': <function A.__init__ at 0x7f87b2be01e0>, 'getA': <function A.getA at 0x7f87994c2e18>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
{'__module__': '__main__', '__init__': <function A.__init__ at 0x7f87b2be01e0>, 'getA': <function A.getA at 0x7f87994c2e18>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}注意:
object.__dict__
一般在序列化的时候访问,平时不会访问
整数除法(负整数)
- C++ 和 Java中整数除法是向0取整
- Python中整数除法是向下取整(向负无穷取整)
- 正整数除法他们的商和余数都相同
- 负整数除法商和余数都不同,需要注意,不要用错
如何获取一个正数的小数部分?
方法1
1
2a = 10.234
decimal = a - int(a)方法2
1
2a = 10.234
decimal = a % 1