import statement.
One of the most basic builtin libraries is
math,
which defines things
like sqrt, floor, etc. We will use
it to demonstrate an important aspect of modules: namespaces!
A namespace is the collection of global name/object bindings. When
you have (outside of any function/class body) code like:
def foo(x):
return x*x
... two things happen. First, a new function with the
fascinating ability to square things is created. Second, that
function is bound to the name foo in the current
namespace.
When you import a module as "import foobar", the
only new name introduced into the current namespace
is foobar.
All of the named objects provided by the
module, like sqrt with import math, are
only accessible as "modulename-dot-objectname". So,
for example, after import math the
name sqrt on its own does not exist in the
current namespace. You must write math.sqrt.
>>> import math >>> math.factorial(5) 120 >>> math.sqrt(42) 6.48074069840786 >>> math.pi 3.141592653589793You can choose specific name/object bindings from the module to pull into the current namespace with:
from modulename import objectname.
Note: you can actually give a comma-separated list of names if
you want more than one, or
from modulename import *
if you want them all.
>>> from math import sqrt,factorial >>> factorial(5) 120 >>> sqrt(42) 6.48074069840786 >>> pi Traceback (most recent call last): File "<stdin>", line 1, inNameError: name 'pi' is not defined
if __name__ == '__main__'imported into other code just like the builtin
modules. The name is simply the file name without the .py at
the end. So everything you write is an opportunity for future
code reuse! Consider the following example, in which the
important point is that file ex1a.py defines function
quadraticFormula that file
ex1b.py wants to use. See how we use "import" to
do that?
But there's a problem here! What if some other code wants to use the beautiful (if I do say so myself)
roots
function? If they do import ex1b to get access to
the roots function they will get all that output
about golden ratios that, presumably, they don't want!
>>> import ex1b golden ratio r = 1.618033988749895 is a root of x^2 - x - 1. check: r^2 - r - 1 = 0.0 >>> ex1b.roots("2 x^2 - 5 x + 1") # I wanted this, not that golden business! [0.21922359359558485, 2.2807764064044154]So here is the crux: We want ex1b.py to compute the "golden" stuff when we run it like "
python3 ex1b.py", but
not when we import it to use with import ex1b.
Here's how we do this: the code with the "golden" business
goes in an if-statement of the form:
if __name__ == '__main__':
You can just think of this as boilerplate. The idea is this: if the file ex1bMOD.py is the main thing the interpreter is running, its __name__ is "__main__". Otherwise, its __name__ is its module name: ex1bMOD.
Note: when you create a file full of class and function definitions that you intend to use elsewhere, you can still make a __main__ for testing code.
ex1a.py. Use it but don't modify
it! The rules are, you use it without modification, and no
code of your own reimplements the quandratic formula or
discriminants or anything like that.
Create a file rroots.py that can be run as a
standalone script (as described below)
or imported and used as part of another project
(as described below):
| as a module to be imported | as a standalone script |
When run as a module to be
imported, rroots.py
provides a function
getRealRoots(a,b,c) that returns a list of
the zero, one or two real roots of $ax^2+bx+c$.
>>> from rroots import getRealRoots >>> getRealRoots(1,2,0.5) [-1.7071067811865475, -0.2928932188134524] >>> getRealRoots(1,2,1) [-1.0] >>> getRealRoots(1,2,1.5) []Remember the rules. You cannot reimplement the quadratic formula or the discriminant. You must use ex1a.py for that (which you also cannot change!) Because floating-point computation is inexact, two roots that come back from the quadratic formula as different numbers, but are close enough (as determined by some threshold) will be considered to be one and the same root. By default that threshold should be 0.0000001. >>> from rroots import getRealRoots >>> getRealRoots(.9999,2,1.0001) [-1.0002000200022516, -0.9999999999997488] >>> getRealRoots(.999999999,2,1.000000001) [-1.000000001]Hint: You might want to import math to use math.fabs( ).
Challenge:
Can you add a |
When run as a script, rroots.py expects a
single command-line argument of the form a,b,c
and returns a list of the zero, one or two real roots of
$ax^2+bx+c$. Of course, if the user runs the command
without the argument a,b,c, a helpful usage
message should be printed out.
$ python3 rroots.py 2,-4,1 [0.2928932188134524, 1.7071067811865475] $ python3 rroots.py 2,-4,2 [1.0] $ python3 rroots.py 2,-4,2.5 [] $ python3 rroots.py usage: python3 rroots.py <a>,<b>,<c>
Hint1:
If you import the
Hint2:
The method >>> foo = "red:yellow:green:blue" >>> foo.split(":") ['red', 'yellow', 'green', 'blue'] Note: There are times when you have an array of values that you want to use as individual arguments in a function call. For example, if you have C = [1,-1,-1]... and you want to call getRealRoots using the elements of C as your a,b,c, it's a drag to write: getRealRoots(C[0],C[1],C[2])There's actually a nifty language feature that takes care of this for you, the * "unpacking" operator. >>> from rroots import getRealRoots >>> C = [1,-1,-1] >>> getRealRoots(*C) [-0.6180339887498949, 1.618033988749895] >>> getRealRoots(C[0],C[1],C[2]) [-0.6180339887498949, 1.618033988749895] |
randpoly.py
that defines a function randPolyTwoRealRoot() that
generates a quadratic polynomial with two distinct real roots whose
coefficients are chosen randomly in the range -99..99, but none
are allowed to be zero. Once again, you can use
previous code (including rroots.py), but you cannot modify it or
reimplement its functionality!