Re: How do I give a decorator acces to the class of a decorated function
On Fri, Sep 6, 2019 at 4:33 AM Serhiy Storchaka wrote: > > 04.09.19 17:21, Antoon Pardon пише: > > 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? > > > > You can make register() returning a descriptor with the __set_name__() > method. Was not aware of that. Cool! For those not familiar with it: https://docs.python.org/3/reference/datamodel.html#object.__set_name__ ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
04.09.19 17:21, Antoon Pardon пише: 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? You can make register() returning a descriptor with the __set_name__() method. A bit of black magic: class register: def __init__(self, func): self.func = func def __get__(self, instance, owner): return self.func.__get__(instance, owner) def __set_name__(self, owner, name): if not hasattr(owner, 'my_cool_functions'): owner.my_cool_functions = [] owner.my_cool_functions.append(name) setattr(owner, name, self.func) -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
Antoon Pardon wrote: > On 5/09/19 15:30, Peter Otten wrote: >> Can you provide some context? > > Sure I am researching the possibility of writing an easy to use > lexing/parsing tool. The idea is to write your lexer/parser as > follows: > > class Calculator(metaclass = ...): > def __init__(self): > self.names = set() > self.table = {} > > @token(r'\d+') > def NUMBER(self, st): > return int(st) > > @token(r'\w+') > def VAR(self, st): > self.names.add(st) > return st > > @production(r"VAR '=' NUMBER") > def assign(self, prd): > name = prd[0] > val = prd[1] > if name in self.names: > self.table[name] = value > else: > raise CalcError("variable (%s) not available" % name) > > calc = Calculator() > calc("a = 7") > > So the token en production decorators register a regex/prodcution with > a specific method to be called in specific circumstances when parsing > a string. > > So I need the lexing and parsing algorithms available to this class, > either by adding methods to the class or by making a subclass of the > class where they are implemented. Ok, that looks like a nice interface to me, and I don't expect the metaclass dance to make it harder to implement than necessary ;) -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
On 5/09/19 15:30, Peter Otten wrote: >> 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? Sure I am researching the possibility of writing an easy to use lexing/parsing tool. The idea is to write your lexer/parser as follows: class Calculator(metaclass = ...): def __init__(self): self.names = set() self.table = {} @token(r'\d+') def NUMBER(self, st): return int(st) @token(r'\w+') def VAR(self, st): self.names.add(st) return st @production(r"VAR '=' NUMBER") def assign(self, prd): name = prd[0] val = prd[1] if name in self.names: self.table[name] = value else: raise CalcError("variable (%s) not available" % name) calc = Calculator() calc("a = 7") So the token en production decorators register a regex/prodcution with a specific method to be called in specific circumstances when parsing a string. So I need the lexing and parsing algorithms available to this class, either by adding methods to the class or by making a subclass of the class where they are implemented. -- Antoon Pardon. -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
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
Re: How do I give a decorator acces to the class of a decorated function
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] 2) Is it possible to make MyClass automatically a subclass of an other class through the metaclass? -- Antoon. -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
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) Thanks for this idea. I think I can make this work for me. -- Antoon. -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
Antoon Pardon writes: > 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? As others have already explained: the decoration works an the function (not the method) level. A function knows nothing of a class. Others have already pointed out work arounds. I add an additional one: Instead of: class C: ... @decorate def f(...): ... ... you can use: class C: ... def f(...): ... ... decorate(C, C.f) In Python 2, "C.f" returns a method (an object with a reference to the class and the function) - there, you would not need the class parameter for "decorate". In Python 3, however, "C.f" is the function (without any reference to the class. -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
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) -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
On Thu, Sep 5, 2019 at 12:23 AM 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? > At the time when the decorator runs, the class doesn't actually exist. But if you're wrapping MyFunction (which appears to be a method), then your wrapper function will receive 'self' as its first parameter, and can access the class from that. Doesn't help at decoration time, though. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How do I give a decorator acces to the class of a decorated function
On 04/09/2019 15:21, 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? I can't see a way of doing that directly, but you could cheat by putting the "class variables" in a global dictionary? And perhaps referencing that global from a class variable? Something like: my_class_registry = {} class MyClass(...): MyClassRegistry = my_class_registry @register(my_class_registry) def MyFunction(...): ... Or you may be able to achieve what you want with dir() and some careful naming? -- Rhodri James *-* Kynesim Ltd -- https://mail.python.org/mailman/listinfo/python-list
How do I give a decorator acces to the class of a decorated function
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? -- Antoon Pardon. -- https://mail.python.org/mailman/listinfo/python-list