Home > Net >  Generate module attributes in python
Generate module attributes in python

Time:07-15

I want to create a module with many attributes (in my case, SI units with prefixes, like mm, cm, km, ...). The obvious way would be to specify them one by one, like

# module.py

mm = "mm"
cm = "cm"
km = "km"
# and so on

Currently I want to have about 600 attributes of this kind, so to me it seems wrong to do it this way. Therefore I was wondering if it is possible to generate those attributes programatically instead. I start with a list of units and a list of prefixes and want to combine each unit with each prefix. As a simple example, consider the following:

# module.py

_prefixes = ["m", "c", "k"]
_names = ["m", "g"]

# Automate this
mm = "mm"
cm = "cm"
km = "km"
mg = "mg"
cg = "cg"
kg = "kg"

If I wanted those to be the attributes of a class, I could use setattr(class, prefix name, prefix name), but so far I did not find a way to translate this to module attributes.

I am aware that I could use a dict or something similar instead of attributes, but I want to allow imports like from module import km, which to my knowledge is only possible with direct attributes.

Is there a way to generate those attributes programatically? And if so, should I use it or define the attributes one by one nontheless (for example using a script generating the python code for me)?

CodePudding user response:

The attributes of a python module are anything you put in the global namespace regardless of whether it is done programatically or via manually typed code. You will often see the following statements used to add module attributes:

  • import: A line like from itertools import product will create a module attribute product in your module.
  • def and class. These keywords create special types of objects whose names appear in the global namespace as well.
  • Regular assignments with =. Anything you assign outside a function or class body also becomes a module attribute.

If you want to generate a bunch of attribues, you can access the module __dict__ via globals():

from itertools import product

_prefixes = ["m", "c", "k"]
_names = ["m", "g"]

for prefix, name in product(_prefixes, _names):
    globals()[prefix   name] = prefix   name

This module will have attributes product, prefix, name, _prefixes and _names, which you may not want. You can clean them up with del at the end of the code, when they are no longer necessary:

del product
del prefix
del name

All that being said, this is a terribly inefficient way of doing things. You likely don't need a separate attribute for each string. If you ever want to do any sort of manipulation or lookup on these units, or use them for something other than just "being there", you will want them in some sort of a data structure, like a list or dict.

Another item is that instead of generating or hard coding the names in your code, you might consider placing them in a configuration file that users can edit somewhere. The module would then contain code to locate and load the text file.

CodePudding user response:

So this option will not have any autocomplete, but in my IDE at least (Pycharm) it doesn't complain.

units.py


class Units:
    prefixes = ["m", "c", "k"]
    names = ["m", "g"]

    def __init__(self, foo):
        self.foo = foo

        for p in self.prefixes:
            for n in self.names:
                setattr(self, p   n, p   n)

unit = Units(foo='bar')

Import the instance unit in main.py

from units import unit


if __name__ == '__main__':
    print(unit.mm)
    print(unit.kg)
    print(unit.cm)
    print(unit.foo)

Output:

$ python main.py
mm
kg
cm
bar

CodePudding user response:

like this?

_prefixes = ["m", "c", "k"]
_names = ["m", "g"]
new_list = []

for i in _prefixes:
    for a in _names:
        new_list.append(i   a)

Editing this again as I know what you mean. so the above makes a list then to create the variables you use globals as shown below.

for v in new_list:
    globals()[f'{v}'] = v

print(km)
print(mm)
  • Related