I think it is a bad idea.
Its a very odd use of meta classes which will contribute to confusion of anyone trying to follow your code. In order to make it worth using this technique, you need the advantages to outweigh that confusion.
As for your reasons:
- Creating an accesible Foo class that can be instantiated, but doesn't actually work like a typical object is much more prone to misuse than an internal class that you know you aren't supposed to call.
- Don't name the base class with an underscore. If its intended to be inherited by other modules, it shouldn't be named that way.
- There already is a method to implement static classes in python,
staticmethod
or classmethod
. As noted, its not hard to implement a staticproperty
In general, there is a theme in your approach of trying to prevent client code from doing the wrong thing. That's not a pythonic attitude. The pythonic approach is to trust your client code. If they want to do something crazy, let them. Don't try to prevent client from instantiating your internal object, there may well be a good reason to do that.
I'm a bit of a purist and think that you shouldn't be storing state like this. So the very fact that you are asking the question means you're already doing it wrong. If you have state, I think it should be in an object. I think storing any sort of state at the module level should be avoided. I think its only a good idea to implement something like this if you have no changing state.
To close off, I'd like to plug the Code Review Stack Exchange, where I'm a moderator. If you post your code there you can get suggestions on how to make it better. I think you may get some helpful suggestions for how to restructure your code to avoid this question from even coming up.
When you need different values depending of the environment, there are several things you can rely on:
- A command line argument such as
--db-path=...
- An system environment variable such as
$MYAPP_DB_PATH
- A fixed path local file (on unix systems, they are usually located at
/etc
).
Usually, I go for a fixed path local file, they are easier to handle in the program and can be extended easily. It's also always possible to add later on the flexibility to specify the path of that file by command line or system environment variable. The file should contain the variables of your logical environment. The code you run should never know which environment it runs in, because that would then mean you can't test your production code (which is a very bad idea).
This is a general advice and not particularily tied to Python, but this is an example of how you would do it the simple way in that language (i don't really know S3 buckets, I will just use plain json files for clarity purpose):
Code.py:
import json
with open('mycfg.json') as f:
env_vars = json.loads(f.read())
do_something(env_vars)
mycfg_dev.json:
{
"path": "/tmp",
"ip": "127.0.0.1",
"login": "root",
"password": "root"
}
mycfg_prod.json:
{
"path": "/var/www",
"ip": "192.168.1.44",
"login": "myapp",
"password": "aunriseqvoa"
}
You would version the two files somewhere, encrypted if necessary (for example in an ansible vault). Be very careful of not commiting plain text production credentials in your repo since it will be hard to erase from git later on.
When you deploy, simply rename the one you need when running your module, or provide it to the run command, based on your implementation. Note that if that is practical, the cfg file can redirect to another data container (such as S3) if it brings any advantage over a plain file.
Generally speaking this is how I handle environment variables, but maybe I understood something wrong about your requirements.
Best Answer
Instead of keeping 3 member fields and synchronizing them, you only need to store one actual value in memory - the radius is a good choice in this example - and always use it:
This solution seems too obvious though - is there a specific reason you want to have separate member fields? You can usually find a smaller number of values you can calculate the rest from...