如何将一个方法定义为实例方法和 class 方法(共享相同的名称),每个方法都有不同的参数?
How to define one method as both instance method and class method (sharing the same name), each with different arguments?
本质上,我正在尝试完成以下操作,但 bar
和 baz
具有相同的句柄(例如 bar
),而不是两个不同名称的函数.
定义
import numpy as np
foo = np.add # For example; real function will be different in every instance
class MyClass(object):
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.arg2 = arg2
def bar(self):
return foo(self.arg1, self.arg2)
@classmethod
def baz(cls, arg1, arg2):
return foo(arg1, arg2)
用法示例
a, b = 1, 2
mine = MyClass(a, b)
print(mine.bar())
>>> 3
x, y = 3, 4
print(MyClass.baz(x, y))
>>> 7
为了清晰起见,我正在尝试这样做。真正的函数名称很长,带有许多下划线,并且为我想要执行此操作的每个函数制作两个名称略有不同的函数(例如,在一个函数名称前加上 _
)只会混淆已经很复杂的函数情况。
该函数将主要在内部使用,但我希望能够在静态上下文中使用可能不一定与 MyClass
的给定对象的实例变量匹配的临时参数调用该函数(事实上 ,如果它们不匹配,我只会这样称呼它)。我使用 @classmethod
而不是 @staticmethod
因为实际函数使用一些内部 class 变量。
我已经尝试用 bar
为两个函数名称简单地实现上述内容,但正如预期的那样,实例方法已被 class 方法覆盖。
我想一个笨拙的解决方案是将
bar
定义为:def bar(self, arg1=None, arg2=None): if arg1 is None: arg1 = self.arg1 if arg2 is None: arg2 = self.arg2 return foo(arg1, arg2)
然后,如果我想在别处静态调用它,我需要使用:
# Assuming that a specific object of MyClass does not exist yet useless = "not", "used" mine = MyClass(*useless) x, y = 6, 9 print(mine.bar(x, y))
我不太喜欢这个,因为它需要我从
MyClass
的特定对象调用bar
。如果我已经在某个地方有一个MyClass
的实例,这在技术上不是问题,但我想要一个 class 方法是有原因的:bar
在这种情况下不依赖于任何实例变量(尽管它对 class 变量起作用)。另一种可能的解决方案是为这个函数(和其他函数)创建一个单独的 class:
class Functions(object): @classmethod def bar(cls, arg1, arg2): return foo(arg1, arg2)
并在
MyClass
内将其称为Functions.bar(self.arg1, self.arg2)
,在外部称为Functions.bar(arg1, arg2)
我也不太热衷于此,因为我将
bar
和类似功能放在MyClass
中是有原因的:它们在概念上与MyClass
相关。
我看到了一些使用描述符的类似 SO 帖子的答案,但我希望可能有更优雅的解决方案。
这里有聪明的 Python 向导有建议吗?
你也可以让self
有一个默认参数,这样你就可以区分mine.bar()
和MyClass.bar()
。代价是其他两个参数必须是关键字参数。
class MyClass:
_sentinel = object()
def bar(self=None, *, arg1=_sentinel, arg2=_sentinel):
if self is not None:
if arg1 is _sentinel:
arg1 = self.arg1
if arg2 is _sentinel:
arg2 = self.arg2
else:
if arg1 is _sentinel:
raise ValueError("Missing required arg1")
if arg2 is _sentinel:
raise ValueError("Missing required arg2")
return foo(arg1, arg2)
mine.bar() # self is mine, arg1 is _sentinel, arg2 is _sentinel
MyClass.bar(arg1=3, arg2=4)