1.基础数据类型
1.1 变量赋值和引用
- 每定义一个新变量时,就会在内存中开辟一块空间用于数据存储。不同的变量,内存地址是不同的。
- 使用
id()
获取内存地址,使用is
判断变量内存地址是否相同。
把一个变量的内存地址同时关联到另一个变量上,称为引用。两个变量对应同一块内存地址
1
2
3
4a = 100
b = a
assert id(a) == id(b)
assert a is b不可变类型变量和可变类型变量在引用时的区别
常用int、字符串都是不可变类型, 字典、集合、列表都属于可变类型的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# b引用a所指向的数据
a = 100
b = a
assert id(a) == id(b)
assert a is b
a = 100
b = a
a = 200
print(a, b) # 200 100
assert a is not b
assert id(a) != id(b)
a1 = "str"
b1 = a1
a1 = "string"
print(a1, b1) # string str
a = [1, 2, 3, 4]
b = a
a[0] = 100
print(a[0], b[0]) # 100, 100
assert a is b
assert id(a) == id(b)
1.2 小整数池和字符串驻留
Python中存在一个小整数池,范围通常在-5到256之间。在这个范围内的整数会被提前创建并缓存,以便节省内存。
字符串驻留范围:英文字母、数字、下划线
以下代码在Ipthon中执行,使用Vscode和PythonCharm执行结果可能不同
1 | # 在ipython中执行 |
1.3 数据类型
数值: int float bool complex(复数)
序列: str list tuple
散列: set dict
常见基础面试题
列表去重方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 方案一 set() 利用集合去重的特性
original_list = [1, 2, 3, 4, 3, 2, 1]
deduplicated_list = list(set(original_list))
print(deduplicated_list) # 输出: [1, 2, 3, 4]
# 方案二 使用enumerate 找到列表下标判断元素是否存在
deduplicated_list = [x for i, x in enumerate(original_list) if x not in original_list[:i]]
print(deduplicated_list) # 输出: [1, 2, 3, 4]
# 方案三 使用 dict.fromkeys():利用字典的键的唯一性
deduplicated_list = list(dict.fromkeys(original_list))
print(deduplicated_list) # 输出: [1, 2, 3, 4]
# 方案四 使用 Counter 是 collections 模块提供的一个计数器对象,可以用来统计元素出现的次数
deduplicated_list = list(Counter(original_list)) # Counter({1: 2, 2: 2, 3: 2, 4: 1})
print(deduplicated_list) # 输出: [1, 2, 3, 4]字符串反转
1
2
3print("第一种方式:", "".join(reversed(data)))
print("第二种方式:", data[::-1])
推导式
list推导式
1
result = ["data{}".format(i) for i in range(0, 100) if i % 2 == 0]
dict 推导式
1
print({f"data{(i + 1)}": i + 1 for i in range(3)}) # {'data1': 1, 'data2': 2, 'data3': 3}
set 推导式
1
{ expression for item in Sequence if conditional }
tuple 推导式 (生成器表达式)
1
2a = (x for x in range(1,10)) # <generator object <genexpr> at 0x7faf6ee20a50> 生成器对象
tuple(a) # 使用 tuple() 函数,可以直接将生成器对象转换成元组
1.4 collections
这个模块实现了一些专门化的容器,提供了对 Python 的通用内建容器 dict、list、set 和 tuple 的补充。
1 | from collections import namedtuple, deque, ChainMap |
1.5 iterable
可迭代对象: 可被 for 遍历都是可迭代对象
- 实现了 iter 方法,并且该方法返回一个迭代器对象。
- 实现了 getitem 方法,并且可以通过索引访问元素。
class collections.abc.Iterable
提供了
__iter__()
方法的抽象基类。使用
isinstance(obj, Iterable)
可以检测一个类是否已经注册到了Iterable
或者实现了__iter__()
函数,但是无法检测这个类是否能够使用__getitem__()
方法进行迭代。检测一个对象是否是 iterable 的唯一可信赖的方法是调用iter(obj)
。
示例1: 实现 __iter__
但是返回一个list 非迭代器对象
1 | class Iterable1: |
示例2: 实现 __iter__
返回一个迭代器对象
1 | class Iterable2: |
示例3: 实现 __getitem__
访问元素
1 | class Iterable3: |
1.6 iterator
迭代器:必须要同时拥有 __iter__
和 __next__
方法才是迭代器
迭代器调用
__next__
方法会调用迭代器中的下一个值
示例1:通过 iter(iterable) 得到迭代器
1 | my_iterator = iter(["1", "2", "3"]) |
示例2:实现一个迭代器,必须要实现 __next__
和 __iter__
方法
示例中并没有手动实现
__iter__
会使用父类的__iter__
1 | from typing import Iterator |
示例3:实现一个迭代器,自己实现 __init__
方法
1 | class Students2(Iterator): |
示例4:实现一个 range 迭代器
- range 方法的签名 start、stop 两个参数
__iter__
方法要求返回值必须是一个”迭代器“ (或者返回值必须要有__next__
方法)
1 | class Next: |
示例5: 基于MyRange使用while实现for
for 会自动调用
__iter__
,__next__
方法,但是while不会,需要手动调用
1 | # 基于MyRange使用while实现for |
1.7 generator
生成器(高效):生成器是特殊的迭代器,迭代器是特殊的可迭代对象,那么生成器必定是可迭代对象
使用yield关键字返回一个生成器对象
1 | from typing import Iterable, Iterator |
1.8 for循环的本质
- 调用iter(),将numbers转化为迭代器numbers_iterator
- 调用next(numbers_iterator),返回出numbers的第一个元素
- 循环步骤2,迭代完numbers内所有数据,捕获异常
1 | # while + iterator |
1.9 itertools
为高效循环而创建迭代器的函数
1 | iterable = itertools.chain(["A", "B", "C"], ["D", "E", "F"]) |
1.10 lambda、map、zip
lamdba 处理简单业务逻辑
1
2
3
4
5
6
7
8
9
10
11
12y: any = lambda x: x + 1
print(y(10))
Students = [
{"name": "a", "age": 18},
{"name": "c", "age": 20},
{"name": "b", "age": 19},
{"name": "ca", "age": 19},
{"name": "cb", "age": 19}
]
# 根据age排序,age一致时根据name排序
print(sorted(Students, key=lambda student: (student["age"], student["name"])))map(func, *iterables) –> map object
1
2
3
4
5
6
7
8
9# map 可迭代对象元素合并 返回新的map对象,按最短的对象合并
a = [1, 2, 3]
b = [4, 5, ]
# map(func, *iterables)
# func --> lambda a1, b1: (a1, b1)
# *iterables --> a, b
num1 = map(lambda a1, b1: (a1, b1), a, b) # <map object at 0x109efed60>
for i in num1:
print(i) # (1, 4), (2, 5)reduce 求和
1
2from functools import reduce
print(reduce(lambda x, y: x + y, range(1, 101))) # 5050filter 过滤
1
print(list(filter(lambda x: x > 5, range(10)))) # <filter object at 0x106ad6c40>
zip
1
2
3a = [1, 2, 3]
b = [4, 5, 6, 7, 8]
print(list(zip(a, b))) # [(1, 4), (2, 5), (3, 6)] # 元素个数与最短的列表一致
1.11 namespace
一般有三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
Python的作用域一共有4种【规则顺序: L –> E –> G –> gt; B】
L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。
比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等。最后被搜索
闭包
1.在一个函数内部定义了另一个函数
2.内部函数引用了外部函数的变量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21g_count = 0 # 全局作用域
def outer():
o_count = 1 # 闭包函数外,函数中
print(f"Enclosing: {o_count}")
def inner():
i_count = 2 # 局部作用域
print(f"Local: {i_count}")
nonlocal o_count # 外层作用域
o_count += 5
print(f"Enclosing: {o_count}")
return inner # 返回函数名称 可以被调用
print(f"Global: {g_count}") # Global: 0
func = outer() # Enclosing: 1
func() # Local: 2 Enclosing: 6
func() # Local: 2 Enclosing: 11
1.12 private_name
1 | # import 私有变量 |