I have a folder for my client code, a folder for my server code, and a folder for code that is shared between them
Proj/ Client/ Client.py Server/ Server.py Common/ __init__.py Common.py
How do I import Common.py from Server.py and Client.py?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
EDIT Nov 2014 (3 years later):
Python 2.6 and 3.x supports proper relative imports, where you can avoid doing anything hacky. With this method, you know you are getting a relative import rather than an absolute import. The ‘..’ means, go to the directory above me:
from ..Common import Common
As a caveat, this will only work if you run your python as a module, from outside of the package. For example:
python -m Proj
Original hacky way
This method is still commonly used in some situations, where you aren’t actually ever ‘installing’ your package. For example, it’s popular with Django users.
You can add Common/ to your sys.path (the list of paths python looks at to import things):
import sys, os sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common')) import Common
os.path.dirname(__file__)
just gives you the directory that your current python file is in, and then we navigate to ‘Common/’ the directory and import ‘Common’ the module.
Method 2
Funny enough, a same problem I just met, and I get this work in following way:
combining with linux command ln
, we can make thing a lot simper:
1. cd Proj/Client 2. ln -s ../Common ./ 3. cd Proj/Server 4. ln -s ../Common ./
And, now if you want to import some_stuff
from file: Proj/Common/Common.py
into your file: Proj/Client/Client.py
, just like this:
# in Proj/Client/Client.py from Common.Common import some_stuff
And, the same applies to Proj/Server
, Also works for setup.py
process,
a same question discussed here, hope it helps !
Method 3
Don’t do relative import.
From PEP8:
Relative imports for intra-package imports are highly discouraged.
Put all your code into one super package (i.e. “myapp”) and use subpackages for client, server and common code.
Update:
“Python 2.6 and 3.x supports proper relative imports (…)“. See Dave’s answers for more details.
Method 4
Doing a relative import is absolulutely OK! Here’s what little ‘ol me does:
#first change the cwd to the script path scriptPath = os.path.realpath(os.path.dirname(sys.argv[0])) os.chdir(scriptPath) #append the relative location you want to import from sys.path.append("../common") #import your module stored in '../common' import common.py
Method 5
The default import method is already “relative”, from the PYTHONPATH. The PYTHONPATH is by default, to some system libraries along with the folder of the original source file. If you run with -m to run a module, the current directory gets added to the PYTHONPATH. So if the entry point of your program is inside of Proj, then using import Common.Common
should work inside both Server.py and Client.py.
Don’t do a relative import. It won’t work how you want it to.
Method 6
Approch used by me is similar to Gary Beardsley mentioned above with small change.
Filename: Server.py
import os, sys script_path = os.path.realpath(os.path.dirname(__name__)) os.chdir(script_path) sys.path.append("..") # above mentioned steps will make 1 level up module available for import # here Client, Server and Common all 3 can be imported. # below mentioned import will be relative to root project from Common import Common from Client import Client
Method 7
A simple answer for novice in Python world
Create a simple example
Assume we run ls -R
in the current working directory and this is the result:
./second_karma: enemy.py import.py __init__.py math ./second_karma/math: fibonacci.py __init__.py
And we run this command $ python3 second-karma/import.py
init.py is an empty file but it should exists.
Now let’s see what is inside the second-karma/import.py
:
from .math.fibonacci import Fibonacci
fib = Fibonacci()
print(fib.get_fibonacci(15))
And what is inside the second_karma/math/fibonacci.py
:
from ..enemy import Enemy
class Fibonacci:
enemy: Enemy
def __init__(self):
self.enemy = Enemy(150,900)
print("Class instantiated")
def get_fibonacci(self, which_index: int) -> int:
print(self.enemy.get_hp())
return 4
Now the last file is second_karma/enemy.py
:
class Enemy:
hp: int = 100
attack_low: int = 180
attack_high: int = 360
def __init__(
self,
attack_low: int,
attack_high: int) -> None:
self.attack_low = attack_low
self.attack_high = attack_high
def getAttackPower(
self) -> {"attack_low": int, "attack_high": int}:
return {
"attack_low": self.attack_low,
"attack_high": self.attack_high
}
def get_hp(self) -> int:
return self.hp
Now a simple answer why it was not working:
- Python has a concept of packages, which is basically a folder containing one or more modules, and zero-or-more packages.
- When we launch python, there are two ways of doing it:
- Asking python to execute a specific module (
python3 path/to/file.py
). - Asking python to execute a package.
- Asking python to execute a specific module (
- The issue is that
import.py
makes reference to importing.math
- The
.math
in this context means “go find a module/package in the current package with the name math” - Trouble:
- When I execute as
$ python3 second-karma/import.py
I am executing a module, not a package. thus python has no idea what.
means in this context - Fix:
python3 -m second_karma.import
- Now
import.py
is of parent packagesecond_karma
, and thus your relative import will work.
- When I execute as
- The
Important note:
Those __init__.py
are necessary and if you have not them you must create them first.
An example in github
- Read
README.md
for a better comprehension - Go back and forth between commits to observe the problem even more deeply.
- https://github.com/kasir-barati/my-python-journey/tree/main/second_karma
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0