Transcript
When Python imports a module, it runs all the code in that module.
A module that defines and prints things
Here we have a file called salutations.py
:
import random
salutations = ["Hello", "Hey", "Hi", "Hiya", "Howdy"]
emphatic_salutations = []
for greeting in salutations:
emphatic_salutations.append(greeting + "!")
salutations.extend(emphatic_salutations)
def greet():
"""Print a salutation."""
print(random.choice(salutations))
print("Test calling greet:", greet())
def part():
"""Print a valediction."""
print("Live long and prosper")
print("Test calling part:", part())
This salutions
module imports random
and defines a list (named salutations
). It then defines another list named emphatic_salutations
(based on the first list) and then it extends that first list.
Then it defines a function called greet
, calls that function, and prints a statement. Lastly, it defines another function called part
, calls that function, and prints another statement.
What happens when you import a module?
Now, what do you expect would happen if we were to import this salutations
module?
>>> import salutations
Normally, what happens when you import a module in Python is we'd see nothing happen. For example, if we import the math
module, we'll get a math
module object back, but we wouldn't see anything happen at import time.
But when we import salutations
, we see things printed out:
>>> import salutations
Hiya!
Test calling greet: None
Live long and prosper
Test calling part: None
That's a little weird.
This happens because when Python imports a module, it runs all the code in that module. After running the module it takes whatever variables were defined in that module, and it puts them on the module object, which in our case is salutations
.
So within our salutations
module, we have a greet
function:
>>> salutations.greet()
Hiya!
And a part
function:
>>> salutations.part()
Live long and prosper
We also have a salutations
list:
>>> salutations.salutations
['Hello', 'Hey', 'Hi', 'Hiya', 'Howdy', 'Hello!', 'Hey!', 'Hi!', 'Hiya!', 'Howdy!']
In fact we even have a greeting
variable:
>>> salutations.greeting
'Howdy'
Because
emphatic_salutations = []
for greeting in salutations:
emphatic_salutations.append(greeting + "!")
salutations.extend(emphatic_salutations)
Even the random
module is available on our salutations
module object (because salutations.py
imported the random
module):
>>> salutations.random
<module 'random' from '/home/trey/.pyenv/versions/3.9.1/lib/python3.9/random.py'>
Seeing greeting
and random
on our salutations
object is really weird, but this is just the way Python works.
Avoiding import side effects
When you import a module in Python, all the code in it will be run, and all the variables in that module will be stuck on that module object.
This normally isn't a problem unless we have side effects at import time. That's the problem in our case: our salutations
module has side effects.
We're printing a few statements at the top-level of our salutations
module:
def greet():
"""Print a salutation."""
print(random.choice(salutations))
print("Test calling greet:", greet())
def part():
"""Print a valediction."""
print("Live long and prosper")
print("Test calling part:", part())
But we probably shouldn't be printing at the top-level of our file.
If we remove those print calls:
def greet():
"""Print a salutation."""
print(random.choice(salutations))
print("Test calling greet:", greet())
def part():
"""Print a valediction."""
print("Live long and prosper")
print("Test calling part:", part())
And then we import our module in a new Python REPL, we'll see...
>>> import salutations
Nothing!
Nothing happens, except that we get a salutations
module object, and it has the variables that are available in this module.
A general guideline: when you're making a Python file (a .py
file), you shouldn't usually put print calls at the top-level of that file. Typically, the only thing you'll do at the top-level of a module is define functions, classes, or other objects (constants for example) that are meant to be used accessed on your module object (after your module has been imported). But there is one exception to this general rule: command-line programs.
When are import side effects acceptable?
The one place that you actually want to print at the top-level of your module is if you're making a command-line program (a.k.a. [a script][]).
Here we have a command-line program called greet.py
:
import random
import sys
salutations = ["Hello", "Hey", "Hi", "Hiya", "Howdy"]
def greet(name):
"""Print a salutation."""
print(random.choice(salutations), name)
arguments = sys.argv[1:]
if not arguments:
greet("")
for name in arguments:
greet(name)
This greet.py
file is meant to be used as a command-line program:
$ python3 greet.py Trey
Hi Trey
Each time it prints a random greeting to the screen (using the random
module):
$ python3 greet.py Trey
Hello Trey
$ python3 greet.py
Howdy
In this Python script we have some code that reads arguments (if they're given to us) and then calls our greet
function (which prints something out):
arguments = sys.argv[1:]
if not arguments:
greet("")
for name in arguments:
greet(name)
This code is at the top-level of our module because we want to run this code every time our program runs. This module is not mean to be imported, so print
calls at the top-level of our program are acceptable.
Summary
When you import a module, Python will run all the code that's in that module.
So if your Python file is meant to be imported as a module, be careful not to put side effects at the top-level of your .py
file.
from Planet Python
via read more
No comments:
Post a Comment