20 个 Python 面试题来挑战你的知识( 二 )


装饰器还可以用于其他目的,例如计时功能、验证输入数据、执行访问控制和身份验证、缓存等 。
6 — 如何正确地将数据写入文件?否则会出什么问题?
使用上下文管理器是关键 。
当你使用open没有上下文管理器的语句并且在关闭文件之前发生一些异常时(关闭文件是你在以这种方式打开文件时必须记住的事情)可能会发生内存问题并且文件可能会在此过程中损坏 。
当你with用来打开一个文件并且发生异常时,Python 保证该文件是关闭的 。
d = {"foo": 1}# bad practicef = open("./data.csv", "wb")f.write("some data")v = d["bar"] # KeyError# f.close() never executes which leads to memory issuesf.close()# good practicewith open("./data.csv", "wb") as f:f.write("some data")v = d["bar"]# python still executes f.close() even if the KeyError exception occurs7 — 函数参数是按引用传递还是按值传递?
在 Python 中,所有函数参数都是通过引用传递的:这意味着如果将参数传递给函数,则函数将获得对同一对象的引用 。
如果对象是可变的并且函数改变了它,则参数将在函数的外部范围内发生变异 。让我们看一个例子:
>>> def append_number(numbers):numbers.append(5)>>> numbers = [1, 2, 3, 4]>>> print(f"before: {numbers}"[1, 2, 3, 4]>>> append_number(numbers)>>> numbers[1, 2, 3, 4, 5]8 — 如何覆盖对象的打印方式?
使用 the__str__和__repr__dunder 方法 。
这是一个示例,它演示了 Person 类中的实例在打印到控制台时如何被很好地格式化 。
class Person:def __init__(self, first_name, last_name, age):self.first_name = first_nameself.last_name = last_nameself.age = agedef __str__(self):return f"{self.first_name} {self.last_name} ({self.age})"def __repr__(self):return f"{self.first_name} {self.last_name} ({self.age})">>> person = Person("John", "Doe", 30) # thanks to __str__John Doe (30)>>> person # thanks to __repr__John Doe (30)9 — 编写一个计算整数 n 阶乘的函数
递归是关键
def factorial(n):if n == 0:return 1else:return n * factorial(n-1)10 — is 和 == 运算符有什么区别?
==是一个测试相等性的运算符,而is是一个测试身份的运算符 。
两个对象可以具有相同的值,但不一定相同(即具有相同的内存地址) 。
请记住,这a is b是id(a) == id(b).
11 — 什么时候不应该使用 assert 语句?
assert语句对于内部测试和完整性检查很有用 。
但是,它不应该用于执行数据验证或错误处理,因为出于性能原因,它通常在生产代码中被禁用 。
想象一下,如果你使用断言检查管理员权限:这可能会在生产中引入很大的安全漏洞 。
assert你可以抛出自定义错误,而不是使用该语句 。
# Dangerous code!def delete_product(user, product_id):assert user.is_admin()user.delete_product(product_id)# Handle this properly by raising an errordef delete_product(user, product_id):if not user.is_admin():raise AuthError("User must have admin privileges")else:user.delete_product(product_id)12 — 什么是 Python 生成器?
Python 生成器是一个生成一系列项目的函数 。
生成器看起来像典型的函数,但它们的行为是不同的 。对于初学者,不使用return语句,而是使用yield语句 。
然后,调用生成器函数不会运行该函数:它只会创建一个生成器对象 。生成器的代码仅在next函数应用于生成器对象或生成器被迭代时执行(在这种情况下,next函数被隐式调用)
在生成器对象上调用函数的次数next等于yield在生成器函数中调用语句的次数 。
你可以使用 for 循环或生成器表达式定义生成器 。
>>> def repeat(n, message):for _ in range(n):yield messagerepeat_hello_five_times = repeat(5, hello)>>> for message in repeat_hello_five_times:print(message)"hello""hello""hello""hello""hello">>> repeat_hello_five_time = ("hello" for _ in range(5))>>> repeat_hello_five_timesat 0x7fb64f2362d0>>>> for message in repeat_hello_five_times:print(message)"hello""hello""hello""hello""hello"13 — 类方法和静态方法有什么区别?什么时候应该使用哪个?
静态方法是一种对调用它的类或实例有任何了解的方法 。这是一种逻辑上属于该类但没有隐式参数的方法 。
可以在类或其任何实例上调用静态方法 。


推荐阅读