1

There are many times that I want to use same packages in my scripts, I mostly copy paste packages I want from my last script. I want to stop this work and run all of theme with one simple function, Today i try this:

def econometrics():
    print("Econometrics is starting")
    import pandas as pd
    import numpy as np
    import statsmodels.formula.api as smf
    import statsmodels.api as sm
    import matplotlib.pyplot as plt
    print("Econometrics is started")

econometrics()

the function runs without error but when I call some method from packages, I get errors like this: name 'plt' is not defined

What is wrong with that code? is there anyway to define function to do that?

Mehdi
  • 1,260
  • 2
  • 16
  • 36
  • Indeed, the modules work just fine inside econometrics(), while not outside its scope. I struggled with the same work and decided to create my own toolbox module so, that I can `code from tbx.acustics import reverb` and get all my desired imports from there. – krysopath Apr 24 '16 at 11:32

4 Answers4

7

What is wrong with that code?

Simple answer: Variable scope. plt (and the others) are only accessible from within the econometrics method.


Try making one file, named importer.py, for example

import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
import statsmodels.api as sm
import matplotlib.pyplot as plt

Then in your other code (that is in the same directory),

from importer import *

Using an __init__.py is probably the recommended way to approach that, though, but it wasn't clear if you have a module/package layout, or not.

If you do, then use

Relative import (same directory): from . import *
Absolute import (use module name): from some_module import *

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • thanks cricket I absolutely have a package layout , I try this and I call you what is the result! – Mehdi Apr 24 '16 at 11:34
  • I wouldn't define that as `__init__.py` of a package, but rather a simple `.py` module. – zmo Apr 24 '16 at 11:41
  • @zmo Probably not. I just listed as an option – OneCricketeer Apr 24 '16 at 11:42
  • He can put this importer file inside one of the Python import paths to be free for all of scripts, anywhere. (To get rid off moving it inside every script directory) – EbraHim Apr 24 '16 at 11:48
  • Preferably with a `setup.py` to have it installed properly, as I suggest within my answer! – zmo Apr 24 '16 at 11:49
2

Your intent is wrong in python's grammar. Because within your code, the variables range are scoped within the function. So, when you do your imports, you're creating a bunch of variables within the econometrics function range, and thus your variables are only in reach within that function.

So, let's take a simpler example:

>>> def foobar():
...   a = 1
...   b = 2
...
>>> foobar()
>>> a
NameError: name 'a' is not defined

here a and b only exist within foobar's function scope, so it's out of scope at the main scope.

To do what you want, the way you want it, you should declare your variable as belonging to the global scope:

def econometrics():
    global pd, np, smf, sm, plt
    print("Econometrics is starting")
    import pandas as pd
    import numpy as np
    import statsmodels.formula.api as smf
    import statsmodels.api as sm
    import matplotlib.pyplot as plt
    print("Econometrics is started")

econometrics()

So to get back to the foobar example:

>>> def foobar():
...   global a, b
...   a = 1
...   b = 2
...
>>> foobar()
>>> a
1
>>> b
2

Though, I do not really like that way of doing things, as it's doing things implicitely. Considering you have a python module with just the econometrics function defined, people reading the following code:

from econometrics import econometrics
econometrics()

plt.something()

wouldn't necessary understand that plt has been made available through the econometrics function call. Adding a comment would help, but still is an unnecessary extra step.

Generally speaking, doing globals within any language is wrong, and there's most of the time always a better way to do it. Within the "Zen of python", it is stated that "Explicit is better than implicit", so I believe a more elegant way would be to create a module that does the import, and then you'd import what you need from the module:

econometrics.py:

import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
import statsmodels.api as sm
import matplotlib.pyplot as plt

and in your code you'd then import only what you need:

from econometrics import pd, plt

plt.something()

which would be much more elegant and explicit! Then, you'd just have to drop that file in any projects you need your mathematics modules to have all your beloved modules that need - and only them - available in your code!

Then as a step further, you could define your own python module, with a full blown setup.py, and with your econometrics.py file being a __init__.py in the econometrics package directory, to then have it installed as a python package through:

python setup.py install

at the root of your sources. So then any code you work out can be using econometrics as a python package. You might even consider making it a package on pypi!

HTH

Community
  • 1
  • 1
zmo
  • 24,463
  • 4
  • 54
  • 90
0

You imported the packages into the scope of the function. If you want to use them in the global scope, you have to tell python

def importfunc():
    global np
    import numpy as np

importfunc()
print np.version.version

On a side note: Are you using some kind of toolchain? I'd think it would be better to use an IDE or to write a script which sets up new projects for you.

rikisa
  • 301
  • 2
  • 9
0

The various imports are performed when you call the function, but the names pd, np, etc are local to the function, so they can't be referenced outside the function.

I suppose you could return those names, but importing modules in a function like that makes your code a little harder for readers to follow, IMHO.

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182