Python最难懂的10大知识点,学会就是大牛!

在这里插入图片描述

你好,我是忆愿,全网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)))

这些知识点看起来多,但是慢慢来,一个一个攻克。写代码就像练功夫,光看不练是不行的,得多写代码,多实践。

记住,代码写得越多,这些概念就越容易理解。每个程序员都是从菜鸟开始的,别怕犯错,多尝试,多思考,就能写出更好的代码。

温馨提示:学习这些高级特性的时候,建议先把基础打扎实。不要为了用而用,要在合适的场景使用合适的特性,有时候简单的代码反而是最好的选择。

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆愿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值