1. 推荐一本看过最好的python书籍?
1. 《流畅的 Python》(Fluent Python)
作者:Luciano Ramalho
适合读者:中级到高级 Python 开发者
内容概述: 《流畅的 Python》是一本非常适合深入学习 Python 的书籍,尤其是对于有一定基础的开发者。这本书深入探讨了 Python 的各种高级特性,包括迭代器、生成器、装饰器、上下文管理器、协程、元编程等。它不仅讲解了 Python 的语法和标准库的高级使用,还注重如何以 Pythonic 的方式编写代码,教你如何写出简洁且高效的 Python 代码。
推荐理由:如果你已经掌握了 Python 的基础,想要提升自己的编程水平并写出更优雅的 Python 代码,这本书是最好的选择之一。
2. 《Python CookBook》
作者:David Beazley 和 Brian K. Jones
适合读者:中级到高级开发者
内容概述: 《Python CookBook》是一本非常实用的书籍,书中通过“食谱”的形式,讲解了 Python 中常见的编程技巧和最佳实践。这本书包含了大量的示例代码,解决了许多 Python 编程中的常见问题,包括数据结构操作、文本处理、并发编程、网络编程等内容。书中的内容非常适合那些希望提升自己的 Python 编程技能并能够处理复杂问题的开发者。
推荐理由:如果你已经具备 Python 基础,想通过实际案例提升自己的编程技巧,这本书非常适合。
3. 《Python 高级编程》
作者:Gabriele Lanaro
适合读者:中级到高级开发者
内容概述: 这本书侧重于 Python 高级特性的学习,介绍了多进程、协程、网络编程、性能优化、调试技巧等方面的内容。通过这些高级主题的学习,开发者能够更好地编写高效、可靠的 Python 程序。
推荐理由:对于有一定 Python 基础的开发者,这本书帮助你深入理解 Python 的内部机制,并提升你在实际工作中的编程能力。
2. 变量:可变对象和不可变对象的区别
总结
可变对象和不可变对象的存储过程是不一样的,一个存储的是指针(不可变),一个存储的是引用(可变)
- 指针指向了内存地址,内存地址存的是什么就是什么,不可变对象就是实际存储数的内存地址。
可变对象:其内容可以被修改,修改时不创建新的对象,内存地址不变。
不可变对象:其内容无法被修改,修改时会创建新的对象,内存地址会变化。
可变对象和不可变对象在内存中的存储和管理方式有所不同,主要体现在对象的修改、内存分配和引用计数等方面。下面是它们存储过程的详细对比:
1.1 不可变对象在内存中存储时,具有以下特点:
内存分配和共享:
- 不可变对象一旦创建,它的值是固定的,无法改变。因此,Python 会尽可能重用这些对象,以提高性能。
- 对于常见的不可变对象(如数字、字符串),Python 使用一种机制叫做“内存池”或“对象池”,也就是共享内存空间。当一个不可变对象被创建时,Python 会检查是否已经有一个相同的对象存在,如果有,直接返回现有的对象,而不是创建一个新的对象。
修改操作:
- 修改不可变对象时,实际上会创建一个新的对象,而不是直接修改原来的对象。
- 例如,字符串是不可变的,当你执行 s = s + " world" 时,Python 会创建一个新的字符串对象,并让 s 引用新的字符串对象,原来的字符串对象则会被垃圾回收。
内存管理:
- 不可变对象的内存地址是固定的,因为它的值不能改变。
- 因为不可变对象不会改变,Python 可以优化内存使用(如字符串池)。这意味着多个引用相同的不可变对象时,它们指向同一个内存地址。
引用计数:
- 不可变对象的引用计数在对象被创建时就确定,一旦没有引用指向该对象,Python 会通过垃圾回收机制释放该对象的内存。
1.2 与不可变对象不同,可变对象的存储过程具有以下特点:
内存分配和共享:
- 可变对象在内存中有一个固定的内存位置,但可以改变其内容(例如列表的元素或字典的键值对)。
- 当你修改一个可变对象的内容时,Python 会直接在原地修改,不会创建一个新的对象。
修改操作:
- 对于可变对象(如列表、字典、集合),你可以直接修改对象的内容,这些操作不会改变对象的内存地址。
内存管理:
- 可变对象的内存地址是固定的,因为它的值可以被修改。修改内容时,不会创建新的对象,而是改变原有对象的内容。
引用计数:
- 可变对象的引用计数与不可变对象相同,依赖于对象被引用的次数。当引用计数为零时,Python 会通过垃圾回收机制释放内存。
- 但如果一个可变对象被多个变量引用并且其中一个变量修改了对象的内容,其他变量的内容也会受到影响。
总结
- 不可变对象:存储时会被共享,修改时会创建新对象,内存地址不变。它们通过内存池和引用计数机制进行优化。
- 可变对象:存储时内存地址固定,可以在原地修改,修改时不会创建新对象,修改会影响所有引用。
3. 深拷贝和浅拷贝怎么发生的,是怎么一种情况?
- 浅拷贝适用于当你只需要复制对象的结构,而不关心嵌套对象是否共享引用时。对于嵌套的可变对象,浅拷贝只会复制它们的引用,修改嵌套对象会影响到原始对象和拷贝对象。
- 深拷贝适用于当你需要完全独立的对象时,它会递归地复制对象及其所有嵌套对象,确保每个对象都是独立的。
1. 浅拷贝(Shallow Copy)
- 这意味着浅拷贝会创建一个新对象,但对象内部的嵌套对象仍然是原始对象中的引用。copy.copy
如何发生:
- 对于原始对象中的每个元素,浅拷贝只会复制对象的引用,而不复制对象本身。
- 如果原始对象中有可变的子对象(如列表、字典等),这些子对象的引用会被拷贝到新对象中,因此对这些子对象的修改会影响到原始对象。
- 浅拷贝时,修改嵌套对象的内容会影响到原对象和拷贝对象,因为嵌套对象的引用被共享。
2. 深拷贝(Deep Copy)
- 深拷贝是指创建一个新对象,并递归地复制原始对象中的所有对象(包括嵌套的对象)。深拷贝会创建一个完全独立的新对象,包括所有子对象的副本。因此,深拷贝后的对象与原始对象是完全独立的,修改深拷贝对象或原始对象不会相互影响。
如何发生:
- 对于原始对象中的每个元素,深拷贝会递归地创建这些元素的副本(对于可变对象如列表、字典,会创建新的列表或字典,而不是引用原有的列表或字典)。
- 深拷贝会确保对象及其所有嵌套的子对象都被复制,不会共享任何引用。
copy.deepcopy()
总结:
4. 装饰器的作用
在 Python 中,**装饰器(Decorator)**是一种函数或类,用于在不改变原有函数或类的基础上,动态地修改或增强其功能。装饰器常用于:
- 代码复用:在多个地方使用相同的功能而不重复编写代码。
- 增强功能:向现有函数或方法添加新的功能或行为(例如日志、权限验证、性能监控等)。
- 分离关注点:将一些横切关注点(如缓存、身份验证、日志记录等)与主要业务逻辑分离开来。
装饰器的基本结构
- 装饰器通常是一个接受函数作为参数并返回一个新函数的函数。它利用了函数作为第一类对象的特性,即函数可以作为参数传递给另一个函数,也可以从另一个函数返回。
def decorator(func):def wrapper():print("Before calling the function")func() # 调用原函数print("After calling the function")return wrapper # 返回包装函数@decorator
def say_hello():print("Hello!")
解释:
@decorator 是装饰器的语法糖,它实际上是 say_hello = decorator(say_hello) 的简写。
装饰器的主要作用:
- 功能增强:你可以在不修改原函数代码的情况下,为其添加额外功能(如日志记录、性能计时、权限检查等)。
- 简化代码:通过将跨多个函数共享的逻辑(如缓存、验证等)提取到装饰器中,减少代码重复。
- 提高代码可读性:将与核心功能无关的代码抽象出来,使主业务逻辑更加简洁明了。
5. 装饰器的内层函数返回的是什么?
在装饰器中,内层函数(通常称为“包装函数”)的作用是接收原函数作为输入并返回一个新的函数,通常是对原函数的增强版或修改版。内层函数返回的通常是一个函数对象,即一个可以被调用的函数。
内层函数的工作机制:
- 包装原函数:内层函数通常会在执行某些附加操作后调用原函数。这些操作可能包括日志记录、异常处理、参数验证等。
- 返回新的函数对象:内层函数返回的是一个新的函数,这个函数通常是原始函数的增强版本。
def decorator(func):def wrapper(*args, **kwargs): # 这个是内层函数print("Before calling the function")result = func(*args, **kwargs) # 调用原函数print("After calling the function")return result # 返回原函数的结果return wrapper # 返回包装函数@decorator
def add(a, b):return a + b
- 返回值:装饰器内层函数返回的通常是原函数的结果,除非你显式地改变它。
- 函数签名:在装饰器中,内层函数需要接受和原函数相同的参数,并返回原函数的返回值(如果你不做其他操作的话)。如果原函数有返回值,内层函数应该返回它。
外层函数通常返回的是内