04-Python 代码

一些变量

  • low、high
  • left、right
  • i、j

题型

  • 查找、二分
  • 排序:冒泡、选择、插入、快排、归并、树排、桶排、基数、计数
  • 链表:
  • 栈、队列
  • 指针 i, j

一些基础语法

字符串

1
2
3
4
5
6
7
8
9
10
s = "abcd"
s.find("b")
s.index("a")
s.split()
s.strip()
for i in s:
pass
s.center(100, " ")
# s.replace()
s[1:2]

列表

1
2
3
4
5
6
7
l = [1, 2, 3]
l.append(4) # 右边 append
l.insert(0, 0) # 按照索引添加
l.extend([5, 6])# 迭代着添加
l.pop() # 右边 pop
l.pop(1) # 按照索引进行 pop
l.sort(kye="key", reverse=False)

其他

1
2
3
range(10)   # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
li = [i for i in range(10)] # 列表推导式
li = (i for i in range(10)) # 列表生成器

加减乘除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 除号 / 有小数
3 / 2 # 1.5

# 除号 // 没小数,向下取整
7 // 4 # 1

# 取余 %
7 % 4 # 3

# 位移
bit_index = 5
1 << bit_index # 位移 5 位
1 | 0 # 或
1 & 1 # 且

切片

1
2
3
4
5
6
7
8
9
10
11
num_list = [1, 2, 3, 4, 5, 6, 7, 8]
print(num_list[0: 6]) # [1, 2, 3, 4, 5, 6] 左闭右开
print(num_list[0: 6:]) # [1, 2, 3, 4, 5, 6]
print(num_list[0: 6: -1]) # []
print(num_list[0: -1]) # [1, 2, 3, 4, 5, 6, 7]
print(num_list[6: -3]) # []
print(num_list[0: -1: -1]) # []
print(num_list[-1: -6]) # []
print(num_list[-1: -6: -1]) # [8, 7, 6, 5, 4]
print(num_list[::]) # [1, 2, 3, 4, 5, 6, 7, 8]
print(num_list[::-1]) # [8, 7, 6, 5, 4, 3, 2, 1]

总结:

1
2
3
4
5
6
7
8
语法:
sequence[start:stop:step]

参数:
start:切片的起始索引(包括)
stop:切片的结束索引(不包括)
step:切片的步长(默认为1
只有 start 大于 stop 时,才能切出来,否则为空,这时需要使用 负值 使其显示(如-1, -2),此时为倒序。

and or

1
2
3
4
5
6
7
8
9
print(1 or 3)           # 1
print(1 and 3) # 3
print(1 < (2 == 2)) # False
print((1 < 2) == 2) # False
print(1 < 2 == 2) # True,python 链式比较:1 < 2 == 2 即 1 < 2 and 2 == 2,所以结果为True。
print(0 and 2 and 1) # 0
print(0 and 2 or 1) # 1
print(0 and 2 or 1 or 4)# 1
print(0 or False and 1) # False

总结:

  • x or y 如果 x 为真,则值为 x,否则为 y
  • x and y 如果 x 为真,则值为 y,否则为 x
  • 优先级:() > not > and > or
  • 同等优先级下,从左向右
  • 数字和 True、False 比较时,1==True0==False

& ^ |

1
2
3
print(2 & 5)  # 10 & 101 = 000 = 0 
print(2 ^ 5) # 10 ^ 101 = 111 = 1*2**0+1*2**1+1*2**2=1+2+4=7
print(2 | 5) # 10 | 101 = 111 = 1*2**0+1*2**1+1*2**2=1+2+4=7

dict.fromkeys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v1 = dict.fromkeys(['k1', 'k2'])  
print(v1) # {'k1': None, 'k2': None}

v2 = dict.fromkeys(['k1', 'k2'], [])
print(v2) # {'k1': [], 'k2': []}


v = dict.fromkeys(['k1', 'k2'], [])
v['k1'].append(666)
print(v) # {'k1': [666], 'k2': [666]}
v['k1'] = 777
print(v) # {'k1': 777, 'k2': [666]}

# 解释:dict.fromkeys(seq[, value]) 函数用于创建一个新字典,以序列 seq 中元素做字典的键,value 为字典所有键对应的初始值,默认为None。

a = [1,2,3]b = [(1),(2),(3)] 以及 c = [(1,),(2,),(3,)] 的区别?

a = [1,2,3]b = [(1),(2),(3)] 是数字类型,c = [(1,),(2,),(3,)] 是元祖类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 补充1:a=[1,2,3,4,5],b=a和b=a[:],有区别么?

a = [1,2,3,4,5]
b = a
b1 = a[:]
print(b) # [1, 2, 3, 4, 5]
print(b1) # [1, 2, 3, 4, 5]

b.append(6)
print("a", a) # a [1, 2, 3, 4, 5, 6]
print("b", b) # b [1, 2, 3, 4, 5, 6] # 传递引用
print("b1",b1) # b1 [1, 2, 3, 4, 5] # 浅拷贝

# 补充2:一个列表 A=[2, 3, 4],Python 如何将其转换成 B=[(2,3),(3,4),(4,2)]?
A = [2, 3, 4]
B = zip(A, A[1:]+A[:1])

列表推导式和生成器表达式

1

1
2
3
4
5
6
7
8
9
10
print([i*i for i in [1, 2, 3]]) # [1, 4, 9]

def multipliers():
return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()]) # 6,6,6,6

# 解释:
# 函数返回值为一个列表推导式,经过 4 次循环结果为包含 4 个 lambda 函数的列表
# 由于函数未被调用,循环中的 i 值未被写入函数,经过多次替代,循环结束后 i 值为 3,
# 故结果为:6,6,6,6

请修改 multipliers 的定义来产生期望的结果(0,2,4,6)

1
2
3
def multipliers():  
return (lambda x:i*x for i in range(4)) # 返回一个生成器表达式
print([m(2) for m in multipliers()])

2

1
2
3
4
5
6
items = [1, 2, 3, 4] 
print([i for i in items if i > 2]) # [3, 4]
print([i for i in items if i % 2]) # [1, 3]
print([(x, y) for x, y in zip('abcd', (1, 2, 3, 4, 5))]) # [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
print({x: f'item{x ** 2}' for x in (2, 4, 6)}) # {2: 'item4', 4: 'item16', 6: 'item36'}
print(len({x for x in 'hello world' if x not in 'abcdefg'}))# 6

3

现有两个元组 (('a'),('b')),(('c'),('d')),请使用 Python 中匿名函数生成列表 [{'a':'c'},{'b':'d'}]

1
2
3
4
5
6
7
8
9
10
# 匿名函数形式:
l1=(('a'), ('b'))
l2=(('c'), ('d'))
ret=map(lambda n:{n[0]:n[1]},zip(l1,l2))
print(list(ret))

# 列表推导式形式:
l1=(('a'), ('b'))
l2=(('c'), ('d'))
print([{n[0]:n[1]} for n in zip(l1,l2)])
1
2
3
4
print([i % 2 for i in range(10)])  # [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]  
print([i for i in range(10)]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print([10 % 2]) # [0] % 是个运算符。
print((i % 2 for i in range(10) )) # <generator object <genexprat 0x00000000020CEEB8 生成器

在 Python 中,有一种自定义迭代器的方式,称为生成器(Generator)。定义生成器有两种方式:

  1. 创建一个生成器,只要把一个列表生成式的 [] 改成 () ,就创建了一个生成器:
    生成器保存的是算法,每次调用 next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的错误。

  2. 定义生成器的另一种方法。如果一个函数定义中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个生成器

一行代码

如何实现 1,2,3 变成 ['1','2','3']

1
list("1,2,3".split(','))

如何实现 ['1','2','3'] 变成 [1,2,3]

1
[int(x) for x in ['1','2','3']]

如何用一行代码生成 [1,4,9,16,25,36,49,64,81,100]

1
[i*i for i in range(1, 11)]

一行代码实现删除列表中重复的值

1
list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))

用一行代码实现数值交换

1
2
3
a = 1
b = 2
a, b = b, a

一行代码实现 9*9 乘法表

1
print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

一行代码模拟 Linux 中的 tail

1
2
3
4
5
6
7
8
9
10
11
# import queue # 不能设置大小
from collections import deque

# q = deque() # 双向队列,可以设置大小,超过大小,后进队的数据会使前进队的数据被丢掉
# q.append(1)
# q.append(2)
# q.append(3)
# print(q.popleft())
# head tail

# print(deque(open('test.txt', 'r', encoding='utf-8'), 5))

根据数字返回相应位置数字

1
2
3
4
5
def get_digit(num, i):
# i=0 个位 1 十位 2 百位...
return num // (10 ** i) % 10

# print(get_digit(12345, 6))

转化类

通过代码实现如下转换(进制之间转换)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 二进制转换成十进制-->int  
v = "0b1111011"
b = int(v,2)
print(b) # 123

# 十进制转换成二进制--->bin
v2 = 18
print(bin(v2)) # 0b10010

# 八进制转换成十进制
v3 = "011"
print(int(v3, 8)) # 11

# 十进制转换成八进制--->oct
v4 = 30
print(oct(v4)) # 0o36

# 十六进制转换成十进制:
v5 = "0x12"
print(int(v5,16)) # 18

# 十进制转换成十六进制:---hex
v6 = 87
print(hex(v6)) # 0x57

总结:

  • int() 十进制
  • bin() 二进制
  • oct() 八进制
  • gex() 十六进制

列表反转,不用内置函数

1
2
3
4
5
6
7
def reverse_list(li):
n = len(li)
for i in range(n // 2):
li[i], li[n-i-1] = li[n-i-1], li[i]
return li

# print(reverse_list([1,2,3,4,5,6]))

数字反转,不用切片,不用内置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 123->321 12300->321
def reverse_int(num):
is_neg = False
if num < 0:
is_neg = True
num = -1 * num
res = 0
while num > 0:
res = res * 10
res += num % 10
num = num // 10
if is_neg:
res = res * -1
return res

# print(reverse_int(-123001))

数字转列表

1
2
3
4
5
6
7
8
9
def int2list(num):
li = []
while num > 0:
li.append(num % 10)
num = num // 10
li.reverse()
return li

# print(int2list(123456))

判断类

假设你使用的是官方的 CPython,说出下面代码的运行结果。

点评:下面的程序对实际开发并没有什么意义,但却是 CPython 中的一个大坑,这道题旨在考察面试者对官方的 Python 解释器到底了解到什么程度。

1
2
3
4
5
6
7
8
9
10
11
a, b, c, d = 1, 1, 1000, 1000
print(a is b, c is d) # True False

def foo():
e = 1000
f = 1000
print(e is f, e is d) # True False
g = 1
print(g is a) # True

foo()

上面代码中 a is b 的结果是 Truec is d 的结果是 False,这一点的确让人费解。CPython 解释器出于性能优化的考虑,把频繁使用的整数对象用一个叫 small_ints 的对象池缓存起来造成的。

small_ints 缓存的整数值被设定为 [-5, 256] 这个区间,也就是说,在任何引用这些整数的地方,都不需要重新创建 int 对象,而是直接引用缓存池中的对象。如果整数不在该范围内,那么即便两个整数的值相同,它们也是不同的对象。

CPython 底层为了进一步提升性能还做了另一个设定,对于同一个代码块中值不在 small_ints 缓存范围内的整数,如果同一个代码块中已经存在一个值与其相同的整数对象,那么就直接引用该对象,否则创建新的 int 对象。

需要大家注意的是,这条规则对数值型适用,但对字符串则需要考虑字符串的长度,这一点大家可以自行证明。

扩展:如果你用 PyPy(另一种 Python 解释器实现,支持 JIT,对 CPython 的缺点进行了改良,在性能上优于CPython,但对三方库的支持略差)来运行上面的代码,你会发现所有的输出都是 True。


04-Python 代码
https://flepeng.github.io/interview-20-开发语言类-21-Python-04-Python-代码/
作者
Lepeng
发布于
2020年8月8日
许可协议