Skip to content

Instantly share code, notes, and snippets.

@DasIch
Created January 31, 2014 23:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DasIch/8745405 to your computer and use it in GitHub Desktop.
Save DasIch/8745405 to your computer and use it in GitHub Desktop.
import sys
import dis
import inspect
NO_ATTRIBUTE = object()
class SeparateNamedspacedMeta(type):
def __new__(cls, name, bases, attributes):
_methods = {}
for name, attribute in attributes.iteritems():
if name.startswith('__') and name.endswith('__'):
continue
if inspect.isfunction(attribute):
_methods[name] = attribute
attributes[name] = AttributeOrMethodDescriptor(name)
attributes['_methods'] = _methods
return type.__new__(cls, name, bases, attributes)
class AttributeOrMethodDescriptor(object):
def __init__(self, name):
self.name = name
self.attribute_value = NO_ATTRIBUTE
def __get__(self, instance, owner):
if instance is None or self.attribute_value is NO_ATTRIBUTE:
return owner._methods[self.name].__get__(instance, owner)
calling_frame = sys._getframe(1)
next_opcode = ord(calling_frame.f_code.co_code[calling_frame.f_lasti + 3])
if dis.opname[next_opcode] == 'CALL_FUNCTION':
return owner._methods[self.name].__get__(instance, owner)
return self.attribute_value
def __set__(self, instance, value):
self.attribute_value = value
def __delete__(self, instance):
self.attribute_value = NO_ATTRIBUTE
class SeparateNamespacedClass(object):
__metaclass__ = SeparateNamedspacedMeta
def __init__(self):
self.spam = 'attribute'
def spam(self):
return 'method'
foo = SeparateNamespacedClass()
print SeparateNamespacedClass.spam # <unbound method spam.spam>
print foo.spam # attribute
print foo.spam() # method
@mattupstate
Copy link

Practical use case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment