如何让函数同时可被类和实例调用?以Storage类的uniques方法为例
如何让函数同时可被类和实例调用?以Storage类的uniques方法为例
嘿,我懂你的需求——想让uniques既能作为类方法直接用Storage.uniques(data)调用,又能作为实例的属性/方法,用实例自己的data来计算结果对吧?你的原代码之所以会报错,问题出在这:当你用实例调用storage.uniques()时,@classmethod会把cls绑定成Storage类本身,但cls.data根本不存在啊!data是你初始化实例时才创建的实例属性,不是类属性,自然会抛出AttributeError。
下面给你两种可行的解决方案,按需选就行:
方案一:灵活的通用方法(支持类/实例调用,实例可传参覆盖)
这种方式不需要特殊装饰器,直接通过判断调用上下文来处理:
class Storage: def __init__(self, data): self.data = data def uniques(self, data=None): # 检查是不是通过类调用的(此时self是Storage类) if isinstance(self, type): cls = self if data is None: raise ValueError("调用类方法时必须传入data参数哦") target_data = data else: # 实例调用,优先用传入的data,没有就用自身的data target_data = data if data is not None else self.data # 核心逻辑不变 return [list(set(item)) for item in target_data]
调用效果:
data = [["apple", "banana", "apple"], ["cat", "dog", "dog"], ["red", "blue", "red"]] # 类调用,必须传data print(Storage.uniques(data)) # 输出:[{'banana', 'apple'}, {'cat', 'dog'}, {'red', 'blue'}](顺序可能因set特性略有不同) # 实例调用,用自身的data storage = Storage(data) print(storage.uniques()) # 输出同上 # 实例调用也可以传参覆盖自身data other_data = [["a", "a", "b"], ["x", "y", "x"]] print(storage.uniques(other_data)) # 输出:[{'a', 'b'}, {'x', 'y'}]
方案二:用自定义描述符实现「类方法+实例属性」双模式
如果你希望实例调用时不用加括号,直接把uniques当成属性用,同时类调用时保持方法形式,可以用Python的描述符机制来实现:
class ClassMethodOrProperty: def __init__(self, func): self.func = func def __get__(self, instance, owner): if instance is None: # 类层面访问,返回需要传data的类方法 return lambda data: self.func(owner, data) else: # 实例层面访问,直接返回计算后的结果(作为属性) return self.func(owner, instance.data) class Storage: def __init__(self, data): self.data = data @ClassMethodOrProperty def uniques(cls, data): return [list(set(item)) for item in data]
调用效果:
data = [["apple", "banana", "apple"], ["cat", "dog", "dog"], ["red", "blue", "red"]] # 类调用,传data参数 print(Storage.uniques(data)) # 输出符合预期 # 实例调用,直接作为属性访问,不用加括号 storage = Storage(data) print(storage.uniques) # 输出同上
两种方案都能解决你的核心需求,具体选哪种看你更倾向于实例调用的方式是方法还是属性~
备注:内容来源于stack exchange,提问作者VERBOSE
相关产品推荐
相关产品推荐

