Python面试题1

1、列表(list)和元组(tuple)有什么区别?

  1. 列表可变,元组不可变
  2. 列表有序,表示同一类的对象;元组可用来表示不同数据类型的数据结构如(2, “Ema”, “2020–04–16”)(#id, 名称,创建日期)。

2、如何进行字符串插值?

  • % 格式化
print("My name is %s and I am %d years old." % (name, age))
  • str.format()
print("My name is {} and I am {} years old.".format(name, age))
  • ​f-strings
print(f"My name is {name} and I am {age} years old.")

print(f"In 10 years, I will be {age + 10} years old.")

3、“is”和“==”有什么区别?

==检查两个变量存储的数据是否相同,调用对象的 __eq__() 方法(可被重载)

is(身份运算符)​比较两个对象的内存地址是否相同​(即是否是同一个对象)

4. 什么是装饰器(decorator)?

一个可调用对象​(通常是函数或类),它接受一个函数作为参数,并返回一个新的函数

带参数的装饰器

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, ​**kwargs):
            for _ in range(num_times):
                result = func(*args, ​**kwargs)
            return result
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello {name}")

greet("Alice")

输出:

Hello Alice
Hello Alice
Hello Alice

类装饰器

装饰器也可以是一个类:

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, ​**kwargs):
        self.num_calls += 1
        print(f"调用次数: {self.num_calls}")
        return self.func(*args, ​**kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

输出:

调用次数: 1
Hello!
调用次数: 2
Hello!

内置装饰器

Python提供了一些内置装饰器:

  1. @property - 将方法转换为属性
  2. @classmethod - 定义类方法
  3. @staticmethod - 定义静态方法

装饰器的执行顺序

当多个装饰器应用于同一个函数时,它们是从下往上执行的:

@decorator1
@decorator2
@decorator3
def func():
    pass

等同于:func = decorator1(decorator2(decorator3(func)))

保留函数元信息

使用装饰器后,原函数的__name____doc__等元信息会被覆盖。可以使用functools.wraps来保留:

from functools import wraps

def my_decorator(func):
    @wraps(func) #将原始函数的元信息复制到包装函数上,这样装饰后的函数会保留原始函数的名称、文档字符串等元数据。
    def wrapper(*args, ​**kwargs):
        """Wrapper docstring"""
        print("装饰器操作")
        return func(*args, ​**kwargs)
    return wrapper

@my_decorator
def say_hello():
    """原始函数文档"""
    print("Hello!")

print(say_hello.__name__)  # 输出: say_hello
print(say_hello.__doc__)   # 输出: 原始函数文档

装饰器是Python中非常强大且灵活的特性,合理使用可以大大提高代码的可重用性和可维护性。

5、什么是闭包(Closure)?

指 ​一个函数​ 能够 ​记住并访问其定义时的作用域,即使该函数在定义的作用域之外执行。闭包允许函数访问其创建时的环境变量,即使这些变量在函数执行时已经不在当前作用域中。

1. 闭包的基本结构

闭包通常由 ​嵌套函数​ 构成:

  1. 外层函数​(outer)定义了一个变量(x)。
  2. 内层函数​(inner)引用了这个变量(x)。
  3. 外层函数返回内层函数​(return inner)。
  4. 即使外层函数执行完毕,内层函数仍然可以访问外层函数的变量。

示例代码

def outer(x):          # 1. 外层函数定义变量 x
    def inner(y):      # 2. 内层函数引用 x
        return x + y   # 3. 内层函数可以访问 x
    return inner       # 4. 返回内层函数

closure = outer(10)    # 调用 outer,返回 inner,此时 x=10
print(closure(5))      # 输出 15(10 + 5)

解释​:

  • outer(10) 执行后返回 inner,此时 x=10 被闭包记住。
  • 即使 outer 已经执行完毕,inner 仍然可以访问 x
  • closure(5) 相当于 inner(5),计算 10 + 5 = 15

2. 闭包的特点

  1. 记住外部变量​:即使外层函数执行完毕,内层函数仍然可以访问外层函数的变量
  2. 延长变量的生命周期​:闭包可以让局部变量不被销毁,即使外层函数已经执行完毕。
  3. 实现数据封装​:闭包可以隐藏变量,避免全局污染。

3. 闭包的经典应用

​(1) 计数器(保持状态)​

def counter():
    count = 0
    def increment():
        nonlocal count  # 声明 count 不是局部变量
        count += 1
        return count
    return increment

c = counter()
print(c())  # 1
print(c())  # 2
print(c())  # 3


count 的初始化(count = 0)只在 counter() 被调用时执行一次(即 c = counter() 时)。
之后每次调用 c() 都是调用 increment,而 increment 不会重新初始化 count,它只是修改闭包中已经存在的 count。
闭包机制使得 count 的状态在函数调用之间得以保留。

解释​:

  • counter() 返回 incrementcount 被闭包记住。
  • 每次调用 c()count 都会递增,而不是重新初始化。

​(2) 缓存(记忆化)​

def cache(func):
    memo = {}
    def wrapper(n):
        if n not in memo:
            memo[n] = func(n)
        return memo[n]
    return wrapper

@cache
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))  # 55(缓存优化,避免重复计算)

解释​:

  • cache 是一个装饰器,它用闭包记住 memo 字典。
  • fibonacci 的计算结果会被缓存,避免重复计算。

4. 闭包 vs 类(面向对象)​

闭包可以实现类似 ​类的私有变量​ 的功能:

# 用闭包实现类似类的功能
def person(name):
    age = 0
    def get_age():
        return age
    def set_age(new_age):
        nonlocal age
        age = new_age
    return get_age, set_age

get_age, set_age = person("Alice")
set_age(25)
print(get_age())  # 25

对比类实现​:

class Person:
    def __init__(self, name):
        self.name = name
        self._age = 0
    def get_age(self):
        return self._age
    def set_age(self, new_age):
        self._age = new_age

p = Person("Alice")
p.set_age(25)
print(p.get_age())  # 25

区别​:

  • 闭包更轻量级,适合简单场景。
  • 类更适合复杂逻辑,支持继承和多态。

5. 闭包的注意事项

  1. ​**nonlocal 关键字**​:如果要在闭包内修改外部变量,必须用 nonlocal 声明(Python 3+)。
  2. 内存泄漏风险​:闭包会保持外部变量的引用,可能导致内存无法释放。
  3. 调试困难​:闭包变量不像类属性那样直观,调试时可能较难追踪。

总结

特性 闭包
数据封装 ✅(通过闭包变量) ✅(通过 self.xxx
状态保持 ✅(变量不会被销毁) ✅(实例变量)
适用场景 简单逻辑、函数式编程 复杂逻辑、面向对象
性能 更轻量级 稍重(需要实例化)

闭包的核心思想​:​函数 + 环境变量,让函数可以记住定义时的作用域。

你可能感兴趣的:(面试,python,开发语言)