Created
May 12, 2013 06:20
-
-
Save DasIch/5562625 to your computer and use it in GitHub Desktop.
__prepare__ for Python 2.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import print_function | |
from collections import OrderedDict | |
from prepareable import Prepareable | |
from six import with_metaclass, iteritems | |
class FooMeta(with_metaclass(Prepareable, type)): | |
def __new__(cls, name, bases, attributes): | |
assert isinstance(attributes, OrderedDict) | |
for name, attribute in iteritems(attributes): | |
if isinstance(attribute, Something): | |
print(name, attribute) | |
return super(FooMeta, cls).__new__(cls, name, bases, attributes) | |
def __prepare__(name, bases, **kwargs): | |
return OrderedDict() | |
class Something(object): | |
pass | |
class Foo(with_metaclass(FooMeta)): | |
a = Something() | |
b = Something() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import inspect | |
from functools import wraps | |
import six | |
class Prepareable(type): | |
if not six.PY3: | |
def __new__(cls, name, bases, attributes): | |
try: | |
constructor = attributes["__new__"] | |
except KeyError: | |
return type.__new__(cls, name, bases, attributes) | |
def preparing_constructor(cls, name, bases, attributes): | |
try: | |
cls.__prepare__ | |
except AttributeError: | |
return constructor(cls, name, bases, attributes) | |
namespace = cls.__prepare__.im_func(name, bases) | |
defining_frame = sys._getframe(1) | |
for constant in reversed(defining_frame.f_code.co_consts): | |
if inspect.iscode(constant) and constant.co_name == name: | |
def get_index(attribute_name, _names=constant.co_names): | |
try: | |
return _names.index(attribute_name) | |
except ValueError: | |
return 0 | |
break | |
by_appearance = sorted( | |
attributes.items(), key=lambda item: get_index(item[0]) | |
) | |
for key, value in by_appearance: | |
namespace[key] = value | |
return constructor(cls, name, bases, namespace) | |
attributes["__new__"] = wraps(constructor)(preparing_constructor) | |
return type.__new__(cls, name, bases, attributes) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very nice--I was just trying to think about whether there was a way to do this.