In essence, I'm trying to accomplish the below but where bar
and baz
have the same handle (e.g. just bar
) rather than being two differently-named functions.
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
I'm trying to do this for intelligibility's sake. The real function names are long with many underscores, and making two slightly differently-named functions (e.g. prepending one function name with a _
) for every function to which I want to do this is only going to confuse an already complicated situation.
The function will mostly be used internally, but I'd like the ability to call the function in a static context with ad hoc parameters that might not necessarily match the instance variables of a given object of MyClass
(in fact, I would only call it this way if they didn't match). I'm using @classmethod
rather than @staticmethod
because the real functions use some internal class variables.
I've already tried simply implementing the above with bar
for both function names, but as expected, the instance method has been overridden by the class method.
I suppose one awkward solution would be to define bar
as:
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)
and then, if I wanted to call it statically elsewhere, I would need to use:
# 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))
I don't really like this because it requires me to call bar
from a specific object of MyClass
. This is technically not an issue if I already have an instance of MyClass
somewhere, but I want a class method for a reason: bar
in this context doesn't depend on any instance variables (though it does on class variables).
Another potential solution would be to make a separate class for this function (and others):
class Functions(object):
@classmethod
def bar(cls, arg1, arg2):
return foo(arg1, arg2)
and to call it within MyClass
as Functions.bar(self.arg1, self.arg2)
and externally as Functions.bar(arg1, arg2)
I'm not super keen on this either since I'm putting bar
and similar functions in MyClass
for a reason: they're relevant to MyClass
conceptually.
I saw some answers to similar SO posts that use Descriptors, but I was hoping there might be a more elegant solution.
Any wise Python wizards out here have advice?
You can let self
take a default argument as well, so that you can distinguish between mine.bar()
and MyClass.bar()
. The price is that the other two arguments must be keyword arguments.
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)