how to create top-level module function from another function? - python

Given a module mymodule with an __init__.py file how can I define a functions of mymodule from another function within that file?
__init__.py code outline:
def a():
THISMODULE.__dict__["b"] = lambda: print("this is not weird")
a()
b() # Expect "this is not weird" output
mymodule comes as a replacement for anothermodule and I want to make the code change as simple as replacing import anothermodule as thething with import mymodule as thething. Since I don't implement all the functions of anothermodule just yet, I would like to send the user a notification about it instead of crashing with "not defined".

__name__ is a module attribute set by the import machinery, which evaluates to the name of the current module. Adding this to the top of your file:
import sys
THISMODULE = sys.modules[__name__]
And the rest of what you already have should work correctly.

Related

Python how to use function in imported file defined in importing file?

Sometimes, I see examples like this, but I don't understand how do they work. Imported module uses function without any places in which this function is set to use. Please can someone explain me how to use them.
Example:
from some_package import *
def some_func():
# do_something
pass
imported_func()
And then imported_func somehow defines some_func and uses it. How is this implemented?
When I tried to call some_func from module.py I received an error. Again: idea is to use function from imported file which was defined in importing file. I couldn't find answer in google.
I tried:
from f.module import *
obj = cls()
def some_func():
for _ in range(100):
print("smth")
obj.imported_func()
Code in main.py
class cls:
#staticmethod
def imported_func():
some_func()
Code in module.py
I have main.py and folder f in one directory. In folder f I have module.py
The way to do this is at first import __main__ then call __main__.some_func(), but remember, it's not a good practice because at least you are reserving name, what can become common reason for errors.

In Python, how to find out which module imports a specific module

For example, I have a module called "Abc". Inside Abc, I need to find out which other module imports 'Abc'. If another module called "Egf" import "Abc", is it possible to print out "Egf" inside of 'Abc'? If so how?
I know a lib called https://github.com/thebjorn/pydeps/blob/master/pydeps/depgraph.py. It can build a graph by reading pyc file, but this is not what I am looking for.
Disclaimer: This might not be a good idea and I don't know much about the internals, so I cannot guarantee that it does not break anything or works in all cases.
Imports happen only once, so if the modules Def and Ghi both include import Abc, the code in Abc will be executed just once.
Thus we need to globally modify how imports are performed.
import Abc evaluated to builtins.__import__("Abc", ...), so we can override that function to check if the module to import is Abc and act accordingly.
We can see the import statements in inspect.stack(), but are only provided with the filename of the import statement, not the module. So if Def.py calls import Abc, we get the absolute path to Def.py, but do not know if it really is the submodule Jkl.Def.
My answer ignores that case and just reports Def in that case.
You could try this approach to get the actual module if Def is just a submodule.
Assuming the absolute path to be /home/testuser/modules/module1/Def.py and the actual module is module1.Def
Try __import__("Def"). If it works, Def is likely to be the importing module (or there exists another module Def in the search path...)
In our case that should fail, so we now call __import__("module1.Def"). This should succeed, so we can assume that the importing module was module1.Def.
Abc.py
import builtins
from builtins import __import__ as builtin_import
import inspect
import os
def my_import(*args):
"""This function is intended to globally override builtins.__import__"""
module_to_import = args[0]
if module_to_import == "Abc":
# for indirect imports we need to find the actual import statement in the stack
for stackframe in inspect.stack():
if stackframe.code_context is None:
continue
code = stackframe.code_context[0]
if code.startswith(("import Abc", "from Abc")):
# name of importing file
importing_file = stackframe.filename # absolute path
importing_module = os.path.basename(importing_file).split(".")[0]
print("Imported Abc from module", importing_module)
break
else:
# This should not happen...
print("Abc was imported but I didn't find the import statement in the stack")
# perform the actual import
builtin_import(*args)
# globally replace __import__
builtins.__import__ = my_import
# the first import does not use the patched __import__, so we need to do it manually
__import__("Abc")
print("I am Abc")
Def.py
import Abc
print("I am Def")
Ghi.py
import Abc
print("I am Ghi")
main.py
import Abc
import Def
import Ghi
Result
$ python3 main.py
Imported Abc from module main
I am Abc
Imported Abc from module Def
I am Def
Imported Abc from module Ghi
I am Ghi

Python Etiquette: Importing Modules

Say I have two Python modules:
module1.py:
import module2
def myFunct(): print "called from module1"
module2.py:
def myFunct(): print "called from module2"
def someFunct(): print "also called from module2"
If I import module1, is it better etiquette to re-import module2, or just refer to it as module1.module2?
For example (someotherfile.py):
import module1
module1.myFunct() # prints "called from module1"
module1.module2.myFunct() # prints "called from module2"
I can also do this: module2 = module1.module2. Now, I can directly call module2.myFunct().
However, I can change module1.py to:
from module2 import *
def myFunct(): print "called from module1"
Now, in someotherfile.py, I can do this:
import module1
module1.myFunct() # prints "called from module1"; overrides module2
module1.someFunct() # prints "also called from module2"
Also, by importing *, help('module1') shows all of the functions from module2.
On the other hand, (assuming module1.py uses import module2), I can do:
someotherfile.py:
import module1, module2
module1.myFunct() # prints "called from module1"
module2.myFunct() # prints "called from module2"
Again, which is better etiquette and practice? To import module2 again, or to just refer to module1's importation?
Quoting the PEP 8 style guide:
When importing a class from a class-containing module, it's usually okay to spell this:
from myclass import MyClass
from foo.bar.yourclass import YourClass
If this spelling causes local name clashes, then spell them
import myclass
import foo.bar.yourclass
Emphasis mine.
Don't use module1.module2; you are relying on the internal implementation details of module1, which may later change what imports it is using. You can import module2 directly, so do so unless otherwise documented by the module author.
You can use the __all__ convention to limit what is imported from a module with from modulename import *; the help() command honours that list as well. Listing the names you explicitly export in __all__ helps clean up the help() text presentation:
The public names defined by a module are determined by checking the module’s namespace for a variable named __all__; if defined, it must be a sequence of strings which are names defined or imported by that module. The names given in __all__ are all considered public and are required to exist. If __all__ is not defined, the set of public names includes all names found in the module’s namespace which do not begin with an underscore character ('_'). __all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module).
Just import module2. Re-importing is relatively costless, since Python caches module objects in sys.modules.
Moreover, chaining dots as in module1.module2.myFunct is a violation of the Law of Demeter. Perhaps some day you will want to replace module1 with some other module module1a which does not import module2. By using import module2, you will avoid having to rewrite all occurrences of module1.module2.myFunct.
from module2 import * is generally a bad practice since it makes it hard to trace where variables come from. And mixing module namespaces can create variable-name conflicts. For example, from numpy import * is a definite no-no, since doing so would override Python's builtin sum, min, max, any, all, abs and round.

Python: How to access a variable in calling module?

Say I have a main module app.py which defines a global variable GLOBVAR = 123. Additionally this module imports a class bar located in another module foo:
from foo import bar
In the main module app I now call a method from the class bar. Within that method I want to access the value GLOBVAR from the main module app.
One straight-forward way would be to simply pass GLOBVAR to the method as parameter. But is there also another solution in Python that allows me to access GLOBVAR directly?
In module foo I tried one of the following:
from app import GLOBVAR # option 1
import app.GLOBVAR # option 2
However, both options lead to the following error at runtime:
ImportError: cannot import name bar
I understand this leads to a cyclic import between app and foo. So, is there a solution to this in Python, or do I have to pass the value as parameter to the function?
There are many ways to solve the same problem, and passing parameters is generally to be recommended. But if you do have some package wide global constants you can do that too. You will want to put these in a whole other module and import that module from both app and foo modules. If you build a package globals you can even put these in the __init__.py ... but another named module like settings or config can also be used.
For instance if you package layout is:
mypackage/
__init__.py
app.py
foo.py
config.py
Then:
config.py
GLOBVAR = 'something'
app.py
from mypackage.config import GLOBVAR
foo.py
from mypackage.config import GLOBVAR
if you just put the GLOBVAR in __init__.py then you would do from mypackage import GLOBVAR which could be prettier if you go for that sort of thing.
EDIT I'd also recommend using absolute imports even if you are using python 2, and always use the package name explicitly rather than relative imports for readability and because it makes things easier to split out later if you need to move something to a new different package
You can import a variable from the __main__ module like this:
""" main module """
import foo
name = "Joe"
foo.say_hi()
and foo.py:
""" foo module, to be imported from __main__ """
import __main__
def say_hi():
print "Hi, %s!" % __main__.name
and it looks like this:
$ python main.py
Hi, Joe!
Of course you can not access the variable before you define it. So you may need to put the access to __main__.name at function level, where it is evaluated after the import. In contrast to the module level, which is evaluated at the time of the import (where the variable not yet exists).
You should just write import line before where you want to use GLOBVAR this will prevent cycle!
In foo.py, the line
from app import GLOBVAR
must be after the bar class definition.
You can put GLOBVAR in a third module, import it into foo, and inside app import it from foo.
glob.py:
GLOBVAR=None
foo.py:
class bar:
global GLOBVAR
from glob.py import GLOBVAR
app.py:
from foo import GLOBVAR
import foo

How to import another external python module?

this is probably a dumb question, but wasnt too sure what else to do.
main.py
import module2
global x
hello="Hello"
x=module2.message()
x.say()
module2.py
class message:
def say():
print hello
When I print hello, i am referring to the hello variable in main.py however this method will return an error. Does anyone know the solution? (i would prefer not to pipe the hello variable into the function)
The only reliable solution is called encapsulation.
So, basically, you could change your code to look like that:
main.py
import module2
global x
hello="Hello"
x=module2.message(hello)
x.say()
module2.py
class message:
def __init__(self, hello):
self.hello = hello
def say():
print self.hello
Plus try to follow coding style of Python - life of you and future developers of your code will be easier.
Multiple options, but do note that one module cannot ever access the calling module directly.
Simply pass hello as a variable (def say(msg): print msg)
Pass all variables in main.py to module2: def say(g): print g['hello'] and say(globals())
Store it somewhere, then extract it when you need it.
Since main.py imports module2.py, you can access the globals defined in moule2 in main.
In your case since module2 is not importing main, so the globals in main is not accessed in module2.
one solution is that defined by #Tadeck
In this particular example, it's totally OK for module2.py to import main.py, there are some gotcha's though.
The most obvious is that main.py is probably being run from the command line, like python main.py, which has the effect of making that file think it's called __main__. You could import that module in module2, but that's sort of unusual; it's called "main.py" and you want to import main. Doing so will cause the module to be imported a second time.
For that to be OK, you have to arrange for importing the file to have no side effects unless it's imported as __main__. A very common idiom in python is to test that condition at the end of a module.
import module2
global x
hello="Hello"
def main():
x=module2.message()
x.say()
if __name__ == '__main__':
main()
And now it's just fine for module2.py to actually import main. On the other hand, importing variables from one module into another gets hard to predict when the imports can be recursive, you may not have that variable yet because the module is already trying to import you. On the other hand, it's always safe to refer to a variable in a module using dotted syntax. So your module2.py should be:
import main
class message:
def say():
print main.hello
which also makes it more obvious just where hello came from.

Categories

Resources