I think I need to explain the title, not really sure how accurately title this post. Here it is a quick code:
from my_module import foobar
Where foobar is not defined in my_module module, but the code will not raise ImportError. So, it’s a module whose attributes can be imported and which does not exist within it.
I did not get this idea on my own and I don’t know who firstly got this interesting idea. I saw this in a project called pbs1, a Python subprocess wrapper. (How abbreviated as pbs?) It is written by Andrew Moffat and licensed under the MIT License.
To be honest, I am not interested in what this project can do, I don’t feel writing Python script for easy command-line access would be more productive or easier than scripting in shell script. But that’s not the point of this post and that code has many to learn from even I don’t use.
I found this project via GitHub Explore, the part of being able to import any commands caught my eyes and I was thinking: this only main code pbs.py must be hell long like traffic in <INSERT YOUR CITY>. When I clicked in, it had only around 450 lines and most of them were comments. So, I took a close look at it.
To strip it down, it could be just like (for Python 3.x and 2.x)
############# # main script ############# from my_module import attr1 print('Value of attr1: %s' % attr1) print('') from my_module import attr2 print('Value of attr2: %s' % attr2) ############## # my_module.py ############## import sys attr1 = 123 class SelfWrapper(object): def __init__(self, self_module): self.self_module = self_module def __getattr__(self, name): print('%s is being imported:' % name) if hasattr(self.self_module, name): print(' found in self_module') return getattr(self.self_module, name) elif name.startswith('__'): print(' starts with __ and not found, raising AttributeError') raise AttributeError print(' returns a generated string') return 'automatically generated ' + name sys.modules[__name__] = SelfWrapper(sys.modules[__name__])
Where attr1 is defined, but attr2 is not. The output is
__path__ is being imported: starts with __ and not found, raising AttributeError attr1 is being imported: found in self_module Value of attr1: 123 __path__ is being imported: starts with __ and not found, raising AttributeError attr2 is being imported: returns a generated string Value of attr2: automatically generated attr2
If you don’t check for __xyz__, __path__ in this case, __getattr__ will be invoked twice for attr1 and attr2. I can not answer the behind scene of module import for this __path__ part, feel free to educate me in comments.
The project is great for this idea, however I would say it’s fancy but not really necessary. I see no much trouble of using like Cmd.curl, Cmd.wget, etc. But it’s awesome to use import like that. Cool, right?
[1] | It’s later renamed to sh. |
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.