Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python variable and filename conflicts

Tags:

python

This is my project structure:

a
├── b.py
└── __init__.py
  • File b.py is empty.

  • File __init__.py is one line:

    b = 'this is a str'
    

Then the following program gives inconsistent result of a.b:

import a
print(a.b)    # str
import a.b
print(a.b)    # module

What is the best way of detecting this kind of name conflict between a variable and a filename?

like image 350
Cyker Avatar asked Mar 16 '16 11:03

Cyker


1 Answers

"The following program gives inconsistent result of print(a.b)"

I'd like to point out that while the results may be different, in fact, Python isn't doing anything inconsistent here. Without going into too much detail, here's what's happening at each step in your program.

import a

Python searches the directories on sys.path until it finds one of these: a file called "a.py", or a directory called "a" containing a file called __init__.py. Python then imports your package. Notably, Python does not look through package "a" and automatically import all ".py" files from it (this saves memory and time).

print (a.b)

Python looks up the attribute b of a, which it finds in a's __dict__ attribute. The value of b is 'this is a string', which is printed.

import a.b

Python imports your module. With this statement, the value corresponding to key b within a's __dict__ becomes the module object a.b.

print (a.b)

Python looks up the attribute b. The value of b is the module object a.b, which is printed.

"What is the best way of detecting this kind of name conflict?"

You could write a script to list the names of all the modules in your package, as well as all the variables (local and global), and determine if there are any conflicts. However, IMHO, an ounce of prevention is worth a pound of cure in this case; good naming conventions in Python (a great resource - PEP8) are the best ways to prevent errors like this in the first place.

like image 199
Daniel Avatar answered Oct 02 '22 11:10

Daniel