Skip to content

Instantly share code, notes, and snippets.

@L3viathan
Last active January 7, 2019 10:19
Show Gist options
  • Select an option

  • Save L3viathan/fb430eba22bfa38bcbad7508a5b04022 to your computer and use it in GitHub Desktop.

Select an option

Save L3viathan/fb430eba22bfa38bcbad7508a5b04022 to your computer and use it in GitHub Desktop.
Metaclass to bake hybrid class/instance binding decorators into subclasses
def bind(clsname, first, second=None):
if second is None: # class binding
cls = globals()[clsname]
fn = first
name = fn.fget.__name__ if isinstance(fn, property) else fn.__name__
setattr(cls, name, fn)
else: # instance binding
self = first
fn = second
name = fn.fget.__name__ if isinstance(fn, property) else fn.__name__
setattr(self, name, partial(fn, self))
class BindableMeta(type):
def __new__(cls, name, bases, dct):
def inner(*args):
return bind(name, *args)
dct["bind"] = inner
return type.__new__(cls, name, bases, dct)
class Bindable(metaclass=BindableMeta):
pass
# Examples:
class Foo(Bindable):
pass
@Foo.bind
def bar(self):
return 5
f = Foo()
assert f.bar() == 5
@f.bind
def bat(self):
return 5
assert f.bat() == 5
g = Foo()
try:
assert g.bat() == 5
except AttributeError:
pass
else:
raise RuntimeError("shouldn't work")
@Foo.bind
@property
def prop(self):
return 5
assert f.prop == 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment