Have you ever tried to add a @property
to a module?
I was working on a authentication_manager. And I wanted to usage of the module to be like so:
1 2 3 4 5 6 |
|
current_user
is going to return the current User if it exists. In other words it needs to call a function.
This would be pretty trivial if I would be okay with using parens all over the place
1 2 3 4 5 6 |
|
But that makes me want to barf. Luckily python gives us the tools to clean this up. We are going to use the Proxy pattern to solve it. At its simplest we can do something like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
With this we have come close to achieving our goal:
1 2 3 4 5 6 |
|
This simple Proxy class that we defined. Takes a function, stores in a local variable, and then when it is accessed it is executed with names and arguments passed through to it. __getattr__
is a pretty special feature of python.
The big gotcha with this is that current_user does not return a User object (like the built-in @property will return), it is going to return the Proxy object. So without a little bit of additional care you might run into issues.
The werkzeug team has developed a fully featured Proxy within the werkzerg project. If you are using werkzeug, you can find it: from werkzeug.local import LocalProxy
Its takes the proxy pattern further by overwriting all of the python object
methods such as __eq__, __le__, __str__ and so on, to use the proxied object as the underlying target.
If you are not using werkzeug I have created a mini library where you can get the extracted proxy code. You can find it here: (http://github.com/jtushman/proxy_tools)
Or install it like so:
1
|
|
And use it like so:
1 2 3 4 5 6 7 8 9 10 |
|
Now — I am sure there was a very good reason why the python-powers-that-be chose not add the @property
syntax to modules. But for the time being I have found it useful and elegant.