Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #104103 > unrolled thread
| Started by | Antoon Pardon <antoon.pardon@rece.vub.ac.be> |
|---|---|
| First post | 2016-03-05 17:21 +0100 |
| Last post | 2016-03-06 12:57 +1100 |
| Articles | 2 — 2 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: Can I find the class of a method in a decorator. Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2016-03-05 17:21 +0100
Re: Can I find the class of a method in a decorator. Steven D'Aprano <steve@pearwood.info> - 2016-03-06 12:57 +1100
| From | Antoon Pardon <antoon.pardon@rece.vub.ac.be> |
|---|---|
| Date | 2016-03-05 17:21 +0100 |
| Subject | Re: Can I find the class of a method in a decorator. |
| Message-ID | <mailman.228.1457194876.20602.python-list@python.org> |
Op 05-03-16 om 16:18 schreef Chris Angelico:
> On Sun, Mar 6, 2016 at 2:05 AM, Antoon Pardon
> <antoon.pardon@rece.vub.ac.be> wrote:
>> Using python 3.4/3.5
>>
>> Suppose I have the following class:
>>
>> class Tryout:
>>
>> @extern
>> def method(self, ...)
>>
>> Now how can I have access to the Tryout class in
>> the extern function when it is called with method
>> as argument
>>
>> def extern(f):
>> the_class = ????
>>
>> f.__class doesn't work, if I write the following
>>
>> def extern(f)
>> print(f.__class__)
>>
>> the result is: <class 'function'>, so that doesn't work.
>> Looking around I didn't find an other obvious candidate
>> to try. Anybody an idea?
>
> At the time when the function decorator is run, there isn't any class.
> You could just as effectively create your function outside the class
> and then inject it (Tryout.method = method).
>
> What is it you're trying to do? Would it be a problem to have a class
> decorator instead/as well?
>
> ChrisA
>
The idea is that some of these methods will be externally available
and others are not. So that I get an external string and can do
something of the following:
tryout = Tryout()
st = read_next_cmd()
if st in tryout.allowed:
getattr(tryout, st)()
else:
raise ValueError("%s: unallowed cmd string" % st)
And the way I wanted to populate Tryout.allowed as a class attribute
would have been with the decorator extern, which would just have put
the name of the method in the Tryout.allowed set and then return the function.
[toc] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2016-03-06 12:57 +1100 |
| Message-ID | <56db8ea7$0$1585$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #104103 |
On Sun, 6 Mar 2016 03:21 am, Antoon Pardon wrote:
> The idea is that some of these methods will be externally available
> and others are not. So that I get an external string and can do
> something of the following:
>
> tryout = Tryout()
>
> st = read_next_cmd()
>
> if st in tryout.allowed:
> getattr(tryout, st)()
> else:
> raise ValueError("%s: unallowed cmd string" % st)
>
> And the way I wanted to populate Tryout.allowed as a class attribute
The simplest way to do this is to forget about the decorator, since it's the
wrong tool for the job. The decorator doesn't have access to the class
itself, unless you pass it as an argument to the decorator. But you can't
do that *inside* the class, since it doesn't exist yet.
Instead, just keep a separate set of the names of methods. Do the simplest
thing which could possibly work, that is, maintain the set manually:
(All code following is untested.)
class Tryout:
allowed = set(['spam', 'ham', 'cheese'])
def spam(self): ...
def ham(self): ...
def eggs(self): ...
def cheese(self): ...
That suggests a way to avoid having to manually add the method name to the
set: have a decorator that adds it to a known set.
def external(aset):
def decorator(func):
aset.add(func.__name__)
return func
return decorator
class Tryout:
allowed = set()
@external(allowed)
def spam(self): ...
@external(allowed)
def ham(self): ...
def eggs(self): ...
@external(allowed)
def cheese(self): ...
Which leads us to our next improvement:
class Tryout:
allowed = set()
allow = functools.partial(external, allowed)
@allow
def spam(self): ...
@allow
def ham(self): ...
def eggs(self): ...
@allow
def cheese(self): ...
del allow
But there's another approach. A decorator cannot easily know anything about
the class that the method will belong to, but it can tag the method itself:
def allow(func):
func.allowed = True
return func
class Tryout:
@allow
def spam(self): ...
@allow
def ham(self): ...
def eggs(self): ...
@allow
def cheese(self): ...
tryout = Tryout()
st = read_next_cmd()
method = getattr(tryout, st)
if method.allowed:
method()
else:
raise ValueError("%s: unallowed cmd string" % st)
Obviously you don't write that out in full each time, you factor it into a
method or function.
--
Steven
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web