By definition, a staticmethod
is not provided with a reference to either an invoking class or instance -- that's what "static" means in Python.
You can do some hacky things to achieve this with either metaclasses or decorators.
Note that I'm using the example idea of just getting the class's name from your post, however, you can modify this example to work with any kind of function you want to have as a static function. You would just define that function inside getnameable
below, like I have defined getname
and make use of the some_class
argument below (and you'd use a different name than all the "getname" stuff I use here).
With decorators, you could do this:
def getnameable(some_class):
# Note, this could be any kind of static method that you want, not
# just for getting the name. And it can use `some_class` in whatever
# way is needed.
def getname():
return some_class.__name__
some_class.getname = staticmethod(getname)
return some_class
then this works:
In [334]: @getnameable
class SubClassA(BaseClass):
pass
.....:
In [335]: SubClassA.getname()
Out[335]: 'SubClassA'
but note that if you implemented this in BaseClass
directly, then the class name which gets bound would be BaseClass
, even in the children classes. So in this case, you'd need to put the decorator on every class you wanted.
Metaclasses offers away around that, by indicating that you want this business of decorating the class to be part of class-creation (not instance creation, mind you).
class GetNameableMeta(type):
def __new__(cls, name, bases, attrs):
temp_class = super(GetNameableMeta, cls).__new__(cls, name, bases, attrs)
return getnameable(temp_class)
class BaseClass(object):
__metaclass__ = GetNameableMeta
class SubClassA(BaseClass):
pass
Testing it out:
In [337]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:class GetNameableMeta(type):
: def __new__(cls, name, bases, attrs):
: temp_class = super(GetNameableMeta, cls).__new__(cls, name, bases, attrs)
: return getnameable(temp_class)
:
:class BaseClass(object):
: __metaclass__ = GetNameableMeta
:
:class SubClassA(BaseClass):
: pass
:--
In [338]: SubClassA.getname()
Out[338]: 'SubClassA'
In [339]: BaseClass.getname()
Out[339]: 'BaseClass'
Notice how much high-falutin code we needed to write to do this, when we had several reasonable alternatives:
- Just ask directly for the
__name__
attribute.
- Make it a
classmethod
to begin with.
- Use the decorators just where we need this and give up the inheritance part.
I suspect that in "the essence of Python" any of these is better than the machinery I describe above, since it makes for simpler, easier to understand code.