Re: How do I give a decorator acces to the class of a decorated function

2019-09-05 Thread Chris Angelico
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

2019-09-05 Thread Serhiy Storchaka

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

2019-09-05 Thread Peter Otten
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

2019-09-05 Thread Antoon Pardon
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

2019-09-05 Thread Peter Otten
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

2019-09-05 Thread Antoon Pardon
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

2019-09-05 Thread Antoon Pardon
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

2019-09-04 Thread dieter
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

2019-09-04 Thread Peter Otten
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

2019-09-04 Thread Chris Angelico
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

2019-09-04 Thread Rhodri James

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

2019-09-04 Thread 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?

-- 
Antoon Pardon.

-- 
https://mail.python.org/mailman/listinfo/python-list