0

The following test shows Python interprets A as dir.a.A. How can I make Python interprets A as dir.A?

$ find * -name "*.py"
dir/a.py
dir/__init__.py
main.py


$ cat dir/a.py
class A():
    pass


$ cat dir/__init__.py
from .a import A


$ cat main.py
from dir import A
print(A)


$ python3 main.py
<class 'dir.a.A'>

I know the following can yield the result I want, but I want to achieve it without changing the directory/file structure.

$ ls
dir.py main.py


$ cat dir.py
class A():
    pass


$ cat main.py
from dir import A
print(A)


$ python3 main.py
<class 'dir.A'>

Or, shouldn't I care about this? (I'm a newbie to Python.)

Shubham
  • 2,847
  • 4
  • 24
  • 37
Takahiko Kawasaki
  • 18,118
  • 9
  • 62
  • 105
  • 1
    I don't understand the question. `dir.A` and `dir.a.A` are the same thing. – Aran-Fey Jun 02 '18 at 22:49
  • I don't understand *why* you want to the module part of the fully qualified class name, and why you don't want to change the file structure. That's just an information for humans. Both of your code samples seem fine to me. – phihag Jun 02 '18 at 22:51
  • 1
    Why *do* you care about this? – Daniel Roseman Jun 02 '18 at 22:51
  • Haven't tested it, but try adding the line `__all__ = ['A']` in `dir/__init__.py`. ([related question](https://stackoverflow.com/questions/44834/can-someone-explain-all-in-python)) – mkrieger1 Jun 02 '18 at 22:53
  • The reason I don't want to change the dir/file structure is that I'm going to create many classes and I don't want to pack them into one file (`dir.py`). Regarding the class name, if Python engineers didn't care the difference, it would be okay as an answer although in other languages `dir.A` and `dir.a.A` are different. – Takahiko Kawasaki Jun 02 '18 at 22:57
  • You shouldn't care, because you are confusing the name of the module with the Python identifier bound to the module. You could write `from dir import A as foobar`, and `print(foobar)` would still print `` Try `import os.path; print(os.path)` sometime. – chepner Jun 03 '18 at 03:28

1 Answers1

1

First of all: You don't need to do this, and you probably don't want to do this. The standard library is full of examples where what the documentation uses as the import location and the actual module information on the object differ:

>>> from unittest import TestCase
>>> TestCase
<class 'unittest.case.TestCase'>

The full module location is used by tools like pickle (to store only a reference to the class when serialising instances).

You can set the __module__ attribute if you feel you must change it; it is a string that names the full module path:

>>> class A():
...     pass
...
>>> A
<class '__main__.A'>
>>> A.__module__
'__main__'
>>> A.__module__ = 'dir'
>>> A
<class 'dir.A'>

This is the same value as the __name__ attribute on the module. It is available as a global inside a module, in __init__ you could use

from .a import A

A.__module__ = __name__  # rehome here. 

For tools like pickle that's still fine because you actually have a dir.A reference in the dir module.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343