Antoon Pardon wrote: > On 4/09/19 17:46, Peter Otten wrote: >> Antoon Pardon wrote: >> >>> What I am trying to do is the following. >>> >>> class MyClass (...) : >>> @register >>> def MyFunction(...) >>> ... >>> >>> What I would want is for the register decorator to somehow create/mutate >>> class variable(s) of MyClass. >>> >>> Is that possible or do I have to rethink my approach? >> If you are willing to delegate the actual work to the metaclass call: >> >> def register(f): >> f.registered = True >> return f >> >> def registered(name, bases, namespace): >> namespace["my_cool_functions"] = [ >> n for n, v in namespace.items() >> if getattr(v, "registered", False) >> ] >> return type(name, bases, namespace) >> >> class MyClass(metaclass=registered) : >> @register >> def foo(self): >> pass >> @register >> def bar(self): >> pass >> def other(self): >> pass >> >> print(MyClass.my_cool_functions) > > I have been playing with this idea and it looks promising. I was wondering > about two points. > > 1) I guess I can add extra methods to my class through the metaclass by > having something like the following in the registered function: > > def registered(name, bases, namespace): > namespace["my_cool_functions"] = [ > n for n, v in namespace.items() > if getattr(v, "registered", False) > ] > namespace["__getitem__"] = lambda self, index: > self.my_cool_functions[index]
Methods are just functions as class attributes, so yes. Problems may arise with __private attributes and super(). > > 2) Is it possible to make MyClass automatically a subclass of an other > class > through the metaclass? > While you can modify `bases` before passing it on to `type` this starts to get a bit messy. Maybe you need a real metaclass which unlike the registered function above is shared by the subclasses... import random def register(f): f.registered = True return f class Foo: pass class Bar: pass class RegisterMeta(type): def __new__(cls, name, bases, namespace): namespace["my_cool_functions"] = [ n for n, v in namespace.items() if getattr(v, "registered", False) ] return type.__new__( cls, name, bases + (random.choice([Foo, Bar]),), namespace ) class RegisterBase(metaclass=RegisterMeta): def __getitem__(self, i): return self.my_cool_functions[i] class MyClass(RegisterBase): @register def foo(self): pass @register def bar(self): pass def other(self): pass print(MyClass.my_cool_functions) print(MyClass()[0]) print(MyClass.my_cool_functions is RegisterBase.my_cool_functions) # False print(MyClass.__bases__, RegisterBase.__bases__) ...or something else entirely. Can you provide some context? -- https://mail.python.org/mailman/listinfo/python-list