Skip to content

Instantly share code, notes, and snippets.

@pauricthelodger
Forked from judy2k/sometimes.py
Created April 28, 2025 23:11
Show Gist options
  • Save pauricthelodger/dff1a129d2fca936d87a2041c14180c7 to your computer and use it in GitHub Desktop.
Save pauricthelodger/dff1a129d2fca936d87a2041c14180c7 to your computer and use it in GitHub Desktop.
A descriptor that wraps a method that can be called on a class or an instance.
from functools import wraps
class SometimesClassmethod:
def __init__(self, wrapped_function):
self._wrapped = wrapped_function
def __get__(self, instance, owner=None):
if instance is None:
return self._class_call(owner)
else:
return self._instance_call(instance, owner)
def _class_call(self, cls):
@wraps(self._wrapped)
def class_call(*args, **kwargs):
self._wrapped(cls, None, *args, **kwargs)
return class_call
def _instance_call(self, instance, cls):
@wraps(self._wrapped)
def instance_call(*args, **kwargs):
self._wrapped(cls, instance, *args, **kwargs)
return instance_call
def sometimes_classmethod(fn):
return SometimesClassmethod(fn)
class MyClass:
@sometimes_classmethod
def my_method(cls, self, name):
"""This is a method that can be called on a class or an instance."""
if self is None:
print(f"This was called on a class, {cls.__name__}, {name}!")
else:
print(f"This was called on an instance, {self}, {name}!")
MyClass.my_method("Mark")
mine = MyClass()
mine.my_method(name="Judy")
print(MyClass.my_method.__doc__)
print(mine.my_method.__doc__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment