Can I find the class of a method in a decorator.
Peter Otten
__peter__ at web.de
Sat Mar 5 12:17:44 EST 2016
Antoon Pardon wrote:
> Op 05-03-16 om 16:18 schreef Chris Angelico:
>> On Sun, Mar 6, 2016 at 2:05 AM, Antoon Pardon
>> <antoon.pardon at 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.
A simple alternative would be a flag
class Forbidden(Exception):
pass
def extern(f):
f.published = True
return f
def invoke(obj, command):
try:
method = getattr(obj, command)
if not method.published:
raise Forbidden
except (AttributeError, Forbidden):
raise Forbidden("Forbidden command %r" % command)
return method()
invoke(tryout, "foo")
Or if you need the set of allowed commands:
def make_extern():
allowed = set()
def extern(f):
allowed.add(f.__name__)
return allowed, extern
class Tryout:
allowed, extern = make_extern()
@extern
def method(...): ...
Too much boilerplate? Hide it in a baseclass or metaclass:
class Meta(type):
def __prepare__(*args, **kw):
allowed = set()
def extern(f):
allowed.add(f.__name__)
return dict(allowed=allowed, extern=extern)
class Tryout(metaclass=Meta):
@extern
def foo(self): ...
@extern
def bar(self): ...
def baz(self): ...
assert Tryout.allowed == {"foo", "bar"}
More information about the Python-list
mailing list