>>> class Foo(object): def __new__(cls, kls): class Bar(object): def __init__(self, length, width, height): try: self.length = kls.length except AttributeError: self.length = length try: self.width = kls.width except AttributeError: self.width = width self.heigth = height return Bar >>> @Foo class Buzz(object): def __init__(self, length, width): self.length = length self.width = width >>> Buzz(1, 2, 3) <__main__.Bar object at 0x00BD5390> >>> b = Buzz(1, 2, 3) >>> b.length 1 >>> b.width 2 >>> b.height 3
As you can see, 'b' is an instance of Bar, but that can be fixed by decorating Bar with the wraps decorator from the functools module.
Hmm, I just realized I'm turning class attributes into instance attributes with this code which is not something someone usually wants. I also realized that functools.wraps needs to be passed some extra arguments to work on classes, because the __doc__ attribute is read only and dictproxy objects don't have an update method.
This causes something which might become a problem: the wrapped object's dict contains the wrapper's class attributes (the ones used to preserve the default values).
Anyway, here's a different version that keeps instance attributes the way they are and also preserves their default values:
>>> class Foo(object): def __new__(self, kls): @functools.wraps(kls, assigned=('__module__', '__name__'), updated=()) class Bar(object): try: length = kls().length except AttributeError: length = 0 try: width = kls().width except AttributeError: width = 0 def __init__(self, height=0, length=length, width=width): self.length = length self.width = width self.height = height return Bar >>> @Foo class Derp(object): def __init__(self, length=8, width=9): self.length = length self.width = width >>> Derp.__name__ 'Derp'
It's not very pretty, and I can't think of a use case right now, but it's interesting as an experiment.
No comments:
Post a Comment