面试题答案
一键面试实现思路
- 定义元类:在Python中,元类是用于创建类的类。通过定义一个元类,我们可以在类创建时修改类的行为。
- 遍历类的属性:在元类的
__new__
方法中,获取类的所有属性,筛选出非魔术方法(不以__
开头和结尾的方法)。 - 为方法添加缓存功能:使用装饰器为筛选出的方法添加缓存功能。可以使用
functools.lru_cache
来实现缓存,它是Python标准库中提供的一个用于实现LRU(最近最少使用)缓存的装饰器。
代码实现
import functools
def cache_method(func):
cached = functools.lru_cache()(func)
def wrapper(*args, **kwargs):
return cached(*args, **kwargs)
return wrapper
class CacheMeta(type):
def __new__(mcs, name, bases, namespace):
for attr_name, attr_value in namespace.items():
if callable(attr_value) and not attr_name.startswith('__') and not attr_name.endswith('__'):
namespace[attr_name] = cache_method(attr_value)
return super().__new__(mcs, name, bases, namespace)
可以这样使用这个元类:
class MyClass(metaclass=CacheMeta):
def expensive_method(self, a, b):
print(f"Calculating {a} + {b}")
return a + b
obj = MyClass()
print(obj.expensive_method(1, 2))
print(obj.expensive_method(1, 2))
应用场景
- 提高性能:对于计算量较大且参数固定的方法,缓存结果可以显著提高程序的运行速度,减少重复计算。例如在科学计算、数据分析等领域,某些复杂的计算函数可能会被多次调用且参数不变,缓存可以避免重复计算,节省时间和资源。
- API调用:如果类中的方法涉及到外部API调用,且相同参数的调用频繁发生,缓存结果可以减少对API的请求次数,降低API调用的成本,同时也能提高响应速度。
潜在风险
- 内存消耗:缓存会占用额外的内存空间,如果缓存的结果数据量较大且缓存的方法调用频繁,可能会导致内存占用过高,甚至引发内存溢出问题。
- 数据一致性:如果被缓存的方法依赖于外部状态(如数据库中的数据、文件内容等),并且这些外部状态可能发生变化,缓存的结果可能会变得过时,导致数据不一致。
- 缓存失效策略:
functools.lru_cache
采用的是LRU策略,可能并不适用于所有场景。如果需要自定义缓存失效策略(如基于时间的失效、基于特定事件的失效等),则需要自行实现更为复杂的缓存逻辑。