简体   繁体   中英

sys.modules[__name__] = _classname(). What does it actually do?

I am reading this piece of code by Alex Martelli mentioned in this question . I understand that sys.modules[__name__] tells you what module you are currently at, but this line of code at the end of his constant.py really confuses me. What is the meaning and the point of having such a statement that declares the current module by the end of the file?

# Put in const.py...:
class _const:
    class ConstError(TypeError): pass
    def __setattr__(self,name,value):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't rebind const(%s)"%name
        self.__dict__[name]=value
import sys
sys.modules[__name__]=_const() #this I don't understand
# that's all -- now any client-code can
import const

Basically, my question is that in my opinion this line of code does not do anything; am I understanding it wrong? Since in Python you don't have to put class definitions in separate files, I argue that I don't really need two modules unless I want to reuse the class "const." Then in this case sys.moldules[__name__]=_const() is not necessary either... Am I understanding it correctly?

I believe it is binding an instance to the module. So when you do import const , you actually get an instance of the class _const .

This allows you to call methods on it. Like, for example, the __setattr__ , where in this case it checks that you only bind a variable once.

This is described by Guido van Rossum as a hack that is sometimes recommended:

https://mail.python.org/pipermail/python-ideas/2012-May/014969.html

# foo.py
import sys

class Foo:
    def funct1(self, <args>): <code>
    def funct2(self, <args>): <code>

sys.modules[__name__] = Foo()

This works because the import machinery is actively enabling this hack, and as its final step pulls the actual module out of sys.modules, after loading it. (This is no accident. The hack was proposed long ago and we decided we liked enough to support it in the import machinery.)

You can easily override __getattr__ / __getattribute__ / __setattr__ this way. It also makes "subclassing" the module a little easier (although accessing the class to be used as a base class is a little tricky: you'd have to use foo.__class__ ). But of course the kind of API that Greg was griping about would never be implemented this way, so that's fairly useless. And if you were designing a module as an inheritable class right from the start you're much better off just using a class instead of the above hack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM