Can I define a Python method to be both static and instance at the same time? Something like:
class C(object):
@staticmethod
def a(self, arg1):
if self:
blah
blah
So that I can call it with both:
C.a(arg1)
C().a(arg1)
The intent is to be able to run two sets of logics. If accessed as an instance method, it would make use of instance variables and do stuff. If access as a static method, it will do without.
import functools
class static_or_instance(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return functools.partial(self.func, instance)
class C(object):
@static_or_instance
def a(self, arg):
if self is None:
print "called without self:", arg
else:
print "called with self:", arg
C.a(42)
C().a(3)
No. What would self
mean inside the method, if you could do that?
Your code will work if you remove the self
parameter to a()
. When you call it with C().a(arg1)
the instance is ignored.
But you want this method to work as both a static method and a method that receives an instance. You can't have it both ways.
formencode has a classinstancemethod
decorator, which does what what you want. It requires the method to have 2 arguments (self
and cls
, one of them could get passed None
depending on calling context)
Lifted from formencode/declarative.py
class classinstancemethod(object):
"""
Acts like a class method when called from a class, like an
instance method when called by an instance. The method should
take two arguments, 'self' and 'cls'; one of these will be None
depending on how the method was called.
"""
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
return _methodwrapper(self.func, obj=obj, type=type)
class _methodwrapper(object):
def __init__(self, func, obj, type):
self.func = func
self.obj = obj
self.type = type
def __call__(self, *args, **kw):
assert not kw.has_key('self') and not kw.has_key('cls'), (
"You cannot use 'self' or 'cls' arguments to a "
"classinstancemethod")
return self.func(*((self.obj, self.type) + args), **kw)
def __repr__(self):
if self.obj is None:
return ('<bound class method %s.%s>'
% (self.type.__name__, self.func.func_name))
else:
return ('<bound method %s.%s of %r>'
% (self.type.__name__, self.func.func_name, self.obj))
Sample usage
class A(object):
data = 5
@classinstancemethod
def print_(self=None, cls=None):
ctx = self or cls
print ctx.data
>>> A.print_()
5
>>> a = A()
>>> a.data = 4
>>> a.print_()
4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With