Python 基础面试第三弹
1. 获取当前目录下所有文件名
import os def get_all_files(directory): file_list = []
#os.walk
返回一个生成器,每次迭代时返回当前目录路径、子目录列表和文件列表 for root, dirs, files in os.walk(directory): for file in files: file_list.append(os.path.join(root, file)) return file_list # 获取当前目录下的所有文件名 current_directory = os.getcwd() files = get_all_files(current_directory) # 打印所有文件名 for file in files: print(file)
2. Python中生成器和迭代器区别
4. Python2 和 Python3主要的区别有哪些:
Python 2.x 和 Python 3.x 之间的一些主要区别:
-
打印函数:在 Python 2.x 中,打印语句是一个关键字,使用类似于
print "Hello"
的语法。而在 Python 3.x 中,print
被改造为一个内置函数,需要使用括号,例如print("Hello")
。 -
整数除法:在 Python 2.x 中,整数除法的结果会被截断为整数,例如
5 / 2
的结果是2
。而在 Python 3.x 中,整数除法的结果将保留小数部分,得到浮点数结果,例如5 / 2
的结果是2.5
。如果想要执行截断整数除法,可以使用//
运算符。 -
Unicode 字符串:在 Python 2.x 中,字符串类型分为普通字符串和 Unicode 字符串(以
u
前缀表示),这导致字符串处理的一些混乱和困惑。而在 Python 3.x 中,所有字符串都是 Unicode 字符串,普通字符串是以字节表示的,需要使用b
前缀表示。 -
xrange
替代range
:在 Python 2.x 中,range
函数返回的是一个列表,如果需要生成大范围的整数序列,会占用大量内存。而在 Python 3.x 中,range
函数的实现类似于 Python 2.x 中的xrange
,返回一个迭代器对象,节省了内存。 -
异常语法:在 Python 2.x 中,捕获异常时使用的语法是
except Exception, e
,将异常对象存储在变量e
中。而在 Python 3.x 中,使用except Exception as e
的语法,将异常对象存储在变量e
中。 -
input
函数:在 Python 2.x 中,input
函数会将用户输入的内容作为 Python 代码进行解析,存在安全风险。而在 Python 3.x 中,input
函数始终将用户输入的内容作为字符串返回,不进行解析。
除了上述主要区别之外,Python 3.x 还进行了一些其他改进,包括改进的类定义语法、更好的模块管理和导入机制、更一致的异常处理和错误机制等。然而,这也导致了 Python 2.x 代码无法直接在 Python 3.x 中运行,需要进行一些修改和调整。
5. 说说Python中多线程和多进程
-
多线程(Multithreading):
- 多线程是指在一个进程内创建多个线程,每个线程独立执行不同的任务。多线程共享进程的内存空间,因此线程之间可以方便地共享数据。
- 在 Python 中,可以使用
threading
模块来创建和管理线程。通过创建Thread
类的实例,指定要执行的函数或方法,并调用start()
方法,可以启动一个线程。 - Python 的多线程由于全局解释器锁(Global Interpreter Lock,GIL)的存在,同一时刻只允许一个线程执行 Python 字节码。这意味着多线程并不能充分利用多核处理器,并发性能受限。多线程适用于 I/O 密集型任务,如网络请求、文件读写等,但对于 CPU 密集型任务,多线程并不能提升性能。
-
多进程(Multiprocessing):
- 多进程是指创建多个独立的进程,每个进程都有自己的内存空间和系统资源。多个进程之间相互独立,可以并行执行不同的任务。每个进程都有自己的 Python 解释器,因此可以充分利用多核处理器,提高并发性能。
- 在 Python 中,可以使用
multiprocessing
模块来创建和管理进程。通过创建Process
类的实例,指定要执行的函数或方法,并调用start()
方法,可以启动一个进程。 - 多进程可以通过进程间通信(Inter-Process Communication,IPC)来实现进程之间的数据共享。Python 提供了多种 IPC 机制,如队列(Queue)、管道(Pipe)和共享内存等。
总结:
- 多线程适合处理 I/O 密集型任务,可以提高程序的响应能力和效率。
- 多进程适合处理 CPU 密集型任务,可以充分利用多核处理器提高并发性能。
- 在 Python 中,多线程受到 GIL 的限制,多进程可以绕过 GIL,实现真正的并行执行。
- 使用多线程或多进程时需要注意线程安全和进程安全的问题,避免数据竞争和共享资源的冲突。
6. Python中GIL锁:
全局解释器锁(Global Interpreter Lock,简称 GIL)是在 CPython 解释器中存在的一个特性。它是一种机制,用于保证同一时刻只有一个线程执行 Python 字节码。虽然 GIL 的存在确保了 CPython 解释器的线程安全性,但也对多线程并发执行带来了一些限制。
以下是对 GIL 的一些详细解释和理解:
-
GIL 的作用:
- GIL 的主要作用是保护 CPython 解释器内部的数据结构免受并发访问的影响,确保线程安全。
- CPython 使用引用计数(Reference Counting)作为内存管理的主要机制。GIL 保证了在修改引用计数时的原子性,避免了竞态条件(Race Condition)和内存泄漏问题。
- GIL 还可以简化 CPython 解释器的实现,使其更加简单高效。
-
GIL 的影响:
- 由于 GIL 的存在,同一时刻只有一个线程可以执行 Python 字节码,其他线程被阻塞。这意味着多线程并不能充分利用多核处理器,无法实现真正的并行执行。
- 对于 CPU 密集型任务,由于 GIL 的限制,多线程并不能提升性能。实际上,由于线程切换的开销,可能导致多线程执行速度比单线程还要慢。
- GIL 对于 I/O 密集型任务的影响相对较小,因为线程在进行 I/O 操作时会主动释放 GIL,允许其他线程执行。因此,多线程在处理 I/O 操作时仍然可以提供一定的性能优势。
-
解决 GIL 的方法:
- 采用多进程:由于每个进程都有独立的 Python 解释器和 GIL,多进程可以充分利用多核处理器,实现并行执行。
- 使用扩展模块:某些扩展模块,如 NumPy、Pandas 等,使用 C/C++ 编写,可以释放 GIL,允许多线程并行执行。
- 使用多线程库:一些第三方库,如
multiprocessing
模块、concurrent.futures
模块等,提供了替代方案,使得在某些情况下可以绕过 GIL 的限制。
需要注意的是,GIL 只存在于 CPython 解释器中,而其他实现(如 Jython、IronPython)可能没有 GIL。此外,对于许多类型的应用程序,如 I/O 密集型、并发处理不频繁的应用程序,GIL
的影响较小,可以继续使用多线程来实现并发。然而,对于 CPU 密集型任务和需要充分利用多核处理器的应用程序,考虑使用多进程或其他解决方案来规避 GIL。