你好,我是忆愿,全网4w+粉丝,《遂愿盈创》社群主理人。
副业启航① | 遂愿盈创(对副业感兴趣免费可入,多种赚钱实战项目等你来,一起探寻副业快速变现的途径;以及对接互联网大厂商务合作,一起来搞点小外快,认识更多互联网大咖)
目前群里已经带很多小伙伴(大部分大学生)变现几百块啦,程序员搞副业有额外加成~ 对副业感兴趣可+V : suiyuan2ying 拉你进群。
文章目录
写代码这些年,我深感Python里有些知识点真是让人头疼不已。
每次面试,这些知识点都成了面试官的最爱,仿佛是一道道难以逾越的关卡。
今天,我决定把这些这些年遇到的最难啃的骨头都毫无保留地分享给大家。
这些知识点涵盖了Python的方方面面,从基础的语法到高级的编程技巧,从简单的数据类型到复杂的模块应用,每一个都是面试中的高频考点。
但别担心,我会用最通俗易懂、最简单的方式帮你逐一剖析这些看似高深莫测的概念,让你能够轻松掌握它们的精髓。
当你把这些知识点都整明白了,那可真就是Python高手了,能够在编程的世界里游刃有余,轻松应对各种复杂的项目和挑战。
1. 装饰器的套路
装饰器确实是让许多Python新手感到头疼的概念之一。
简单来说,它就像是给函数穿上了一件“外套”,从而赋予了函数新的功能。
举个例子,就像我们平时穿衣服一样,夏天天气炎热,我们会选择穿短袖;而到了冬天,天气寒冷,我们就会在短袖外面再加一件外套来保暖。
在Python中,装饰器就扮演着这件“外套”的角色,它能够在不改变原有函数代码的基础上,为函数增添额外的功能,让函数变得更加灵活和强大。
1.1 基础装饰器
咱们先来看最简单的装饰器:
def timer(func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
print(f"函数运行时间:{time.time() - start}秒")
return result
return wrapper
@timer
def slow_function():
import time
time.sleep(1)
print("我是慢吞吞的函数")
这个装饰器可以计算函数运行时间,特别实用。但是装饰器可不止这么简单。
1.2 带参数的装饰器
有时候我们需要装饰器能接收参数,这就需要再包一层:
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"你好,{name}!")
温馨提示:写装饰器时最容易忘记返回值,记得每一层都要有return!
1.3 类装饰器
装饰器不一定非得是函数,类也可以当装饰器:
class Singleton:
def __init__(self, cls):
self._cls = cls
self._instance = None
def __call__(self, *args, **kwargs):
if self._instance is None:
self._instance = self._cls(*args, **kwargs)
return self._instance
@Singleton
class Database:
def __init__(self):
print("数据库连接建立")
2. 生成器的黑魔法
生成器是Python中最优雅的特性之一,它能帮我们节省内存,处理大数据特别有用。
与列表等数据结构不同,生成器不会一次性将所有数据加载到内存中,而是按需生成数据。
这使得它在处理海量数据时,能够有效避免内存溢出,提高程序的运行效率,让数据处理变得更加高效和可行。
2.1 基础生成器
最简单的生成器就是用yield关键字:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
for i in range(5):
print(next(fib)) # 输出:0, 1, 1, 2, 3
2.2 生成器表达式
除了函数,还可以用生成器表达式:
# 生成器表达式
squares = (x * x for x in range(10))
# 对比列表推导式
squares_list = [x * x for x in range(10)]
2.3 send方法
生成器还有个厉害的send方法,可以跟生成器交互:
def counter():
n = 0
while True:
x = yield n
if x is not None:
n = x
else:
n += 1
c = counter()
print(next(c)) # 0
print(c.send(10)) # 10
print(next(c)) # 11
3. 元类搞事情
元类是Python中一个非常高级且强大的概念,它是用来创建类的类。
虽然听起来有点绕,但其实它有着广泛的应用。
通过元类,我们可以实现诸如自定义类的创建过程、控制类的属性和方法、实现单例模式等多种高级功能,为Python编程提供了极大的灵活性和扩展性。
3.1 基础元类
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
# 把所有属性名变成大写
uppercase_attrs = {
key.upper(): value for key, value in attrs.items()
if not key.startswith('__')
}
return super().__new__(cls, name, bases, uppercase_attrs)
class Test(metaclass=MyMetaclass):
x = 1
y = 2
print(Test.X) # 1
print(Test.Y) # 2
3.2 元类实现单例模式
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Database(metaclass=Singleton):
def __init__(self):
print("连接数据库...")
3.3 元类实现接口检查
class InterfaceMetaclass(type):
def __new__(cls, name, bases, attrs):
for key, value in attrs.items():
if getattr(value, "__isabstractmethod__", False):
raise TypeError(f"Can't create abstract class {name} with abstract method {key}")
return super().__new__(cls, name, bases, attrs)
4. 闭包的小心思
闭包是函数式编程中的一个重要概念,它具有强大的功能。
闭包能够记住创建时的环境,即使外部函数已经执行完毕,闭包依然可以访问其外部函数的局部变量。
这使得闭包可以封装和保留状态,为程序设计提供了更多的灵活性和可能性,常用于实现一些需要保持状态的功能,如计数器等。
4.1 基础闭包
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
times3 = make_multiplier(3)
times5 = make_multiplier(5)
print(times3(7)) # 21
print(times5(7)) # 35
4.2 闭包陷阱
def create_functions():
functions = []
for i in range(3):
def func():
return i
functions.append(func)
return functions
fs = create_functions()
for f in fs:
print(f()) # 全都打印2!
4.3 正确的闭包写法
def create_functions():
functions = []
for i in range(3):
def func(x=i): # 用默认参数捕获当前值
return x
functions.append(func)
return functions
5. 协程与异步
异步编程是Python处理高并发任务的利器,它能够让程序在等待某些耗时操作(如I/O操作)完成时,继续执行其他任务,从而大大提高程序的效率。
异步编程涉及到协程、事件循环等概念,使用不当就容易把自己绕晕,需要深入理解和合理运用才能发挥其最大优势。
5.1 基础协程
import asyncio
async def hello(name):
print(f"{name} 开始")
await asyncio.sleep(1)
print(f"{name} 结束")
async def main():
await asyncio.gather(
hello("任务1"),
hello("任务2"),
hello("任务3")
)
asyncio.run(main())
5.2 异步上下文管理器
class AsyncContext:
async def __aenter__(self):
print("进入异步上下文")
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("退出异步上下文")
async def main():
async with AsyncContext():
print("异步操作中...")
5.3 异步迭代器
class AsyncCounter:
def __init__(self, stop):
self.current = 0
self.stop = stop
def __aiter__(self):
return self
async def __anext__(self):
if self.current < self.stop:
await asyncio.sleep(1)
self.current += 1
return self.current
raise StopAsyncIteration
6. 描述符的魔力
描述符是Python中一个非常强大的特性,它允许我们通过定义特定的方法来控制属性的访问方式。
通过使用描述符,我们可以实现属性的懒加载、输入验证、属性缓存等多种功能,从而让代码更加灵活、高效且易于维护。
它为属性的访问和修改提供了更加精细的控制,是实现复杂业务逻辑时不可或缺的工具之一。
6.1 基础描述符
class Integer:
def __init__(self, min_value=None, max_value=None):
self.min_value = min_value
self.max_value = max_value
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, owner):
if obj is None:
return self
return getattr(obj, f"_{self.name}", 0)
def __set__(self, obj, value):
if not isinstance(value, int):
raise TypeError(f"{self.name} must be an integer")
if self.min_value is not None and value < self.min_value:
raise ValueError(f"{self.name} must be >= {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"{self.name} must be <= {self.max_value}")
setattr(obj, f"_{self.name}", value)
class Person:
age = Integer(min_value=0, max_value=150)
6.2 属性缓存
class cached_property:
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, obj, cls):
if obj is None:
return self
value = self.func(obj)
setattr(obj, self.name, value)
return value
7. 上下文管理器
上下文管理器是Python中一个非常实用的特性,它能够自动管理资源的获取和释放,常用于文件操作、数据库连接等场景。
通过上下文管理器,我们可以在进入上下文时自动获取资源,在退出上下文时自动释放资源,无需手动干预,有效避免了资源泄露等问题,使代码更加简洁、安全且易于维护。
7.1 基础上下文管理器
class File:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
return False # 不处理异常
# 使用
with File('test.txt', 'w') as f:
f.write('Hello, World!')
7.2 contextlib装饰器
from contextlib import contextmanager
@contextmanager
def timer():
import time
start = time.time()
yield
print(f"运行时间:{time.time() - start}秒")
with timer():
# 做一些耗时操作
import time
time.sleep(1)
8. 多重继承与MRO
多重继承是Python的一个强大特性,它允许一个类同时继承多个父类,从而可以继承多个父类的属性和方法。
多重继承也容易出问题,比如方法解析顺序(MRO)可能会导致一些难以预料的错误,不同父类中相同方法的调用可能会产生冲突等。
在使用多重继承时需要谨慎设计,合理安排父类之间的关系,以避免出现继承相关的问题。
8.1 钻石继承问题
class A:
def speak(self):
print("A")
class B(A):
def speak(self):
print("B")
super().speak()
class C(A):
def speak(self):
print("C")
super().speak()
class D(B, C):
def speak(self):
print("D")
super().speak()
8.2 Mixin模式
class LoggerMixin:
def log(self, message):
print(f"[LOG] {message}")
class DBMixin:
def save(self):
print("保存到数据库")
class User(LoggerMixin, DBMixin):
def __init__(self, name):
self.name = name
def register(self):
self.log(f"用户 {self.name} 注册")
self.save()
9. 垃圾回收机制
Python的垃圾回收机制包含引用计数和分代收集两部分。
引用计数是Python垃圾回收的主要机制,每个对象都有一个引用计数器,用于跟踪有多少个引用指向该对象。
当一个对象的引用计数降为0时,即没有任何引用指向该对象,Python会将其标记为可回收对象,等待下一次垃圾回收操作。
引用计数机制实现了对于内存块的立即回收,允许高效地处理许多短期对象的创建和销毁。
9.1 引用计数
import sys
class Test:
pass
a = Test()
print(sys.getrefcount(a) - 1) # 1
b = a # 增加引用
print(sys.getrefcount(a) - 1) # 2
del b # 减少引用
print(sys.getrefcount(a) - 1) # 1
9.2 循环引用
class Node:
def __init__(self):
self.next = None
def create_cycle():
a = Node()
b = Node()
a.next = b
b.next = a
return a
# 创建循环引用
node = create_cycle()
10. 线程与GIL
GIL是Python中最具争议的特性之一,它限制了Python的多线程性能。由于GIL的存在,同一时刻只有一个线程能够执行Python字节码,这导致在多核CPU上,Python多线程程序无法充分利用多核并行性能。
对于CPU密集型任务,多线程并不能提升性能,甚至可能比单线程更慢。
对于IO密集型任务,线程在等待IO时会释放GIL,允许其他线程执行Python字节码,因此IO密集型任务受到的影响相对较小。
10.1 基础线程使用
import threading
import time
def worker(n):
print(f"线程 {n} 开始工作")
time.sleep(1)
print(f"线程 {n} 结束工作")
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
10.2 线程安全
import threading
class Counter:
def __init__(self):
self.count = 0
self.lock = threading.Lock()
def increment(self):
with self.lock:
current = self.count
time.sleep(0.1) # 模拟耗时操作
self.count = current + 1
counter = Counter()
threads = [threading.Thread(target=counter.increment) for _ in range(10)]
10.3 线程池
from concurrent.futures import ThreadPoolExecutor
def process_item(item):
# 处理单个项目
return item * item
# 创建线程池
with ThreadPoolExecutor(max_workers=3) as executor:
results = list(executor.map(process_item, range(10)))
这些知识点看起来多,但是慢慢来,一个一个攻克。写代码就像练功夫,光看不练是不行的,得多写代码,多实践。
记住,代码写得越多,这些概念就越容易理解。每个程序员都是从菜鸟开始的,别怕犯错,多尝试,多思考,就能写出更好的代码。
温馨提示:学习这些高级特性的时候,建议先把基础打扎实。不要为了用而用,要在合适的场景使用合适的特性,有时候简单的代码反而是最好的选择。