Skip to content

Instantly share code, notes, and snippets.

@rbistolfi
Last active August 29, 2015 14:04
Show Gist options
  • Save rbistolfi/7883392d6ba9c45fc4fa to your computer and use it in GitHub Desktop.
Save rbistolfi/7883392d6ba9c45fc4fa to your computer and use it in GitHub Desktop.
Python class and instance methods that can share a name
# coding: utf-8
"""Instance and class methods that can share a name"""
class DualMethod(object):
"""A method that can be called as instance method and as class method
>>> class Test(object):
...
... @dualmethod
... def spam(self):
... print "I am an instance method"
...
... @spam.classmethod
... def spam(cls):
... print "I am a class method"
...
...
>>> Test.spam()
I am a class method
>>> Test().spam()
I am an instance method
"""
def __init__(self, instancemethod, classmethod=None):
self.instancemethod = instancemethod
self._classmethod = classmethod
def __get__(self, obj, type=None):
"""
Return instancemethod if there is an instance. If there is no instance
and there is a type, return classmethod instead
"""
if obj:
return self.instancemethod.__get__(obj)
if type:
return self._classmethod.__get__(type)
raise TypeError("Invalid dualmethod")
def classmethod(self, func):
"setter for class methods"
self._classmethod = func
return self
def dualmethod(func):
"Convenient decorator"
return DualMethod(func)
if __name__ == "__main__":
import unittest
class DualMethodTestCase(unittest.TestCase):
def test_dualmethod(self):
class Test(object):
@dualmethod
def spam(self):
return self
@spam.classmethod
def spam(cls):
return cls
instance = Test()
self.assertIs(instance.spam(), instance)
self.assertIs(Test.spam(), Test)
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment