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.par...@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"} -- https://mail.python.org/mailman/listinfo/python-list