python问题笔记

01 python的GIL是什么?

GIL 是 Global Interpreter Lock(全局解释器锁)的缩写,是 Python CPython 解释器(Python 的主流实现)中的一个技术术语。GIL 是一个互斥锁,用于在任何时刻只允许一个线程执行 Python 字节码。这意味着在多线程的环境中,即使在多核心的机器上,只有一个线程在给定的时间内被执行。
想象你有一个咖啡店,而这家咖啡店只有一个咖啡机。GIL 就像这个咖啡店的规矩:一次只允许一个员工使用咖啡机。

  1. 如果有很多顾客来买咖啡,即使你雇佣了多个员工(这里的员工可以想象为线程),由于这个“一次只允许一个员工使用咖啡机”的规矩,其他的员工都必须等待,直到咖啡机空闲下来。这就是为什么即使你有很多线程,但在 CPU 密集型任务上,它们还是一个接一个地执行,而不是同时执行。

  2. 但是,如果员工在为客户做咖啡的时候,需要等待咖啡豆磨成咖啡粉(可以看作 I/O 操作,如读取文件或网络请求),那么这个员工可以让出咖啡机,允许其他员工来使用。这就是为什么在 I/O 密集型任务上,多线程仍然是有效的,因为线程在等待的时候可以释放 GIL,让其他线程运行。

所以,GIL 就像一个规定,确保一次只有一个线程执行任务,而其他线程必须等待。这对于保护数据是有帮助的,但在多核 CPU 上,它限制了多线程程序的并发性能。

希望这个比喻能让你更好地理解 GIL 的概念。

02 python列表去重

在 Python 中,有多种方法可以实现列表去重。以下是几种常见的方法:

  1. 使用集合(Set):将列表转换为集合,集合会自动去除重复元素,然后再将它转换回列表。
my_list = [1, 2, 2, 3, 4, 4, 5]
unique_list = list(set(my_list))
print(unique_list)

输出:

[1, 2, 3, 4, 5]

03 fun(args,**kwargs)中的args,**kwargs什么意思?

以下是一个简单的例子来说明它们的用法:

def example_function(*args, **kwargs):
    print("args: ", args)
    print("kwargs: ", kwargs)

# 调用函数
example_function(1, 2, 3, a=4, b=5, c=6)

输出:

args:  (1, 2, 3)
kwargs:  {'a': 4, 'b': 5, 'c': 6}

从上面的例子可以看出:

  • args 捕获了所有位置参数,并将它们存储为一个元组。
  • kwargs 捕获了所有的关键字参数,并将它们存储为一个字典。

这两种语法允许函数接受任意数量和类型的参数,使得函数更加灵活。

04 元组和列表

当然可以。让我们先讨论 Python 中的元组(tuple)和列表(list)。

  1. 列表 (list)

    • 列表是一个有序的元素集合。
    • 列表是可变的,这意味着你可以在创建后修改、添加或删除列表中的元素。
    • 它使用方括号 [] 进行定义。
    • 例如:fruits = ['apple', 'banana', 'cherry']
  2. 元组 (tuple)

    • 元组也是一个有序的元素集合,但与列表不同,元组是不可变的。这意味着一旦你创建了元组,就不能再修改、添加或删除其中的元素。
    • 它使用圆括号 () 进行定义。
    • 例如:colors = ('red', 'green', 'blue')

以下是一个使用元组的示例,这个示例中我们使用元组来表示一个二维的点 (x, y):

def compute_distance(point1, point2):
    """计算两个点之间的欧几里得距离"""
    x1, y1 = point1
    x2, y2 = point2
    return ((x2 - x1)**2 + (y2 - y1)**2)**0.5

# 定义两个点,每个点都是一个元组
point_A = (1, 2)
point_B = (4, 6)

# 计算这两个点之间的距离
distance = compute_distance(point_A, point_B)
print(f"The distance between point A and point B is {
     distance:.2f}")

在上述代码中:

  • 我们使用元组 point_Apoint_B 来分别表示两个二维点。
  • 我们定义了一个函数 compute_distance() 来计算这两个点之间的欧几里得距离。
  • 由于元组是不可变的,我们可以确保在函数中不会意外地修改这两个点的坐标。

这是一个典型的使用元组的场景,因为二维点的 x 和 y 坐标在表示一个特定的点时是固定的,不应该被修改。
如果你的数据集是固定的并且不会发生变化(例如,一周中的天数、地球上的大洲等),那么使用元组是合适的。如果数据集需要动态地更改,那么使用列表更为恰当。

05 python2和python3的range(100)的区别

在 Python 2 和 Python 3 中,range(100) 的行为有所不同。

在 Python 2 中,range(100) 返回一个列表,包含从 0 到 99 的整数值:

>>> range(100)
[0, 1, 2, 3, ..., 98, 99]

在 Python 3 中,range(100) 返回一个可迭代对象(range 对象),它表示从 0 到 99 的整数范围:

>>> range(100)
range(0, 100)

这样做的改变是出于性能优化的考虑。在 Python 2 中,range() 函数会立即生成一个完整的列表,占用大量内存,尤其是对于较大的范围。而在 Python 3 中,range() 函数返回的是一个惰性序列,只有在需要时才会生成下一个元素,节省了内存空间。

如果需要在 Python 3 中获得与 Python 2 相同的行为(返回一个列表),可以使用 list() 函数将 range() 转换为列表:

>>> list(range(100))
[0, 1, 2, 3, ..., 98, 99]

总结:Python 2 中的 range(100) 返回列表,Python 3 中的 range(100) 返回可迭代对象(range 对象),可以通过 list() 函数将其转换为列表。

06 一句话解释什么样的语言能够用装饰器?

能够使用装饰器的语言需要具备以下两个特性:支持高阶函数和支持函数作为参数或返回值。

装饰器是Python中的一种语法,用于在不修改被装饰函数源代码的情况下,为其添加额外的功能或行为。它使用了函数作为参数、闭包和函数式编程等概念。

下面是一个示例,说明了装饰器的作用和使用:

# 定义一个装饰器函数
def uppercase_decorator(func):
    def wrapper():
        result = func()  # 调用原始函数,获取结果
        return result.upper()  # 将结果转为大写并返回
    return wrapper

# 定义一个普通函数
def say_hello():
    return "Hello, World!"

# 使用装饰器来装饰函数
decorated_func = uppercase_decorator(say_hello)

# 调用被装饰后的函数
print(decorated_func())  # 输出: HELLO, WORLD!

这个例子展示了Python中装饰器的特性:函数作为参数传递给另一个函数(高阶函数)以及返回一个新的函数(闭包)。这使得我们能够在不修改原始函数代码的情况下,通过装饰器来扩展其功能。

07 简述面向对象中__new__和__init__区别

在面向对象的 Python 编程中,__new____init__ 是两个经常被提到的特殊方法,它们都与对象的创建和初始化有关,但它们的职责和执行时机是不同的。

举个例子,考虑一个简单的 Person 类:

class Person:
    def __new__(cls, *args, **kwargs):
        print("Creating an instance...")
        instance = super(Person, cls).__new__(cls)
        return instance

    def __init__(self, name, age):
        print("Initializing the instance...")
        self.name = name
        self.age = age

p = Person("Alice", 30)

输出:

Creating an instance...
Initializing the instance...

从这个例子中,我们可以看到:

  • 当我们实例化 Person 类时,首先调用了 __new__ 方法来创建实例。
  • 创建实例后,__init__ 方法被调用,初始化实例的属性。

大多数时候,我们只需要定义 __init__ 方法来初始化对象的属性,但在某些特定的场景下(如单例模式、自定义不可变对象等),我们可能需要重写 __new__ 方法。

08 列表[1,2,3,4,5],请使用map()函数输出[1,4,9,16,25],并使用列表推导式提取出大于10的数,最终输出[16,25]

使用 map() 函数和列表推导式可以实现所需的功能。以下是示例代码:

使用 map() 函数将列表中每个元素平方并返回一个新的列表:

numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda x: x ** 2, numbers))
print(squared_numbers)

输出:

[1, 4, 9, 16, 25]

使用列表推导式从 squared_numbers 列表中提取大于10的数:

filtere

你可能感兴趣的:(Python,python,笔记,开发语言)