2

I would like to ask: Is there (in Python) any way, how to absolutelly stupidly include other file into source code? Without any dancings like modules etc, i.e. equivalent #include from C ? There were laid many questions about this, but all of them are turning on import modules. No, I want only insert some text lines from any file to my code without preprocess it.

For example:

Let's file mysum.py

c = a + b # there is just this one line

And I want to include to another source code: file experiment.py:

#!/usr/bin/python
# -*- coding: UTF8 -*-
import importlib
import sys
import math
 a = 1
 b = 2
 import **mysum**
 print c

Well, it does not work,

Traceback (most recent call last):
  File "./experiment.py", line 12, in <module>
    import mysum
  File "/home/rna/unix/mypok/mysum.py", line 5, in <module>
    c = a + b
NameError: name 'a' is not defined

I really need one short header file include to more different scripts, there would be definitions variables about MySQL connection and similar data, common for more scripts.

RNA
  • 41
  • 3
  • 2
    yes. make the summation a function in mysum.py and then import that – SuperStew Feb 21 '19 at 15:41
  • modules have their own scope, and that function is executed in `mysum.py`'s global scope, which has no `a` defined – C.Nivs Feb 21 '19 at 15:42
  • No, there isn't. Why would you even want that? Just use a module. That's what they are for. – juanpa.arrivillaga Feb 21 '19 at 16:08
  • 1
    Well, it was dumb example. I really want something like: ` myhost = "172.19.214.1" myuser = "mysqluser" mypasswd = "12345" ` and this import to one, two, or six scripts, whitch use access to MySQL: When the host or username changes, I need edit only one file. – RNA Feb 21 '19 at 16:26
  • @RNA yeah, you can do exactly that with your module. Again, why not just use the python import system? – juanpa.arrivillaga Feb 21 '19 at 19:41
  • @juanpa.arrivillaga because the python import system demands modules, and demands .py extensions, and demands a path. In short it is unusable outside of library work. The scope issues alone are a problem. In bash I can include to the current environment. In C the include happens at preprocessing. If we just want to include text in Python we need to preprocess separately, and that is very very poor. – mckenzm Dec 15 '21 at 02:25

2 Answers2

2

execfile used to do this in Python 2, but in Python 3 it's been replaced with:

exec(open('myfile.py').read())

This literally just reads that file (at runtime) and exec's the result. Note that this is not quite the same as what C++ does, which is that the preprocessor does all of this prior to the file being run (or compiled) at all, but it's probably the closest thing there is to it.

If you want to make this some kind of reusable function, you can do something like

import sys
def include(filename):
    with open(filename, 'r') as f:
        exec(f.read(), sys._getframe(1).f_globals, sys._getframe(1).f_locals)

include("myfile.py") # literally reads the file and evaluates it at runtime

The call to exec(f.read(), sys._getframe(1).f_locals, sys._getframe(1).f_locals) means that the exec call is run in the parent function's scope. See also the answers at What is an alternative to execfile in Python 3?

Mike Battaglia
  • 206
  • 2
  • 10
1

When you import a module, anything in global scope of the imported module is executed, this includes statements, variable definitions, class definitions, etc.

Example, if I were to modify your mysum.py

a = 1
b = 4
def some_func(a,b):
    return a+b

Then in another script run

import mysum

All of those statements would be executed. I would have access to mysum.a, mysum.b, and mysum.some_func because they were executed on import. Your c = a+b acts exactly the same way

Let's now examine the script as you have it:

c = a+b

It is important that you just look at this as a standalone script, even though you are importing it. There is no a or b defined in the entire scope of that script, so when you import, c=a+b gets evaluated, with none of those variables being defined.

I'm not sure the exact use case of what you are trying to do, but if you wanted some function to add two variables, I would do it like so:

#mysum.py

def some_add(a,b):
    return a+b

#other_module.py
import mysum
a = 2
b = 3
c = mysum.some_add(a,b)

You'll notice I didn't use a global-style call of a and b like

def some_add():
   return a+b

Because that again would require a and b be in the global scope of that module, and you'll again get NameErrors

C.Nivs
  • 12,353
  • 2
  • 19
  • 44
  • 1
    Yes, thank for answer, but I really need define and initialize some variables, then include them to more scripts. When any variable changes value, I would need make this change only in one included file. Real situation: hostname, user and password for MySQL connection. Well, I can fullfill members of list or tuple and put it as return value of function. But is it the good idea? – RNA Feb 21 '19 at 16:33
  • Usually it's best to initialize those variables in your main script that you are running, and import/define functions that will use those variables as input – C.Nivs Feb 21 '19 at 17:42
  • @C.Nivs that's bad, because then secrets are in CM'd code, and end users should not be editing code, only config files. Python is already problematic because we can't hide the code, but having people hack it is another thing entirely. – mckenzm Dec 15 '21 at 02:25
  • @mckenzm Ok, I'm saying to initialize those values somewhere, like a main script. I'm not saying to hard-code those values. I'm not sure what you're getting at anyways. *"Python is already problematic"*. Not really, expecting a compiler to hide values in your code is problematic. If unauthorized users are reading your code, you have much bigger issues on your hands – C.Nivs Dec 15 '21 at 04:34
  • @C.Nivs Cheers, for a scripting language, we don't want it in the code, hence the include, but I would rather not have to def a function just to read a .cfg file. So it does not matter if people have the code. The variables won't be populated. The adage "if they have root access you are boned anyway" applies. – mckenzm Dec 15 '21 at 18:48
  • @mckenzm maybe I'm not understanding the problem. Your config file is not in your code, ok I follow you. Good practice so far. "I'd rather not have to def a function." Not sure why there's a constraint here. "It does not matter if people have the code." I mean, if you aren't giving the user the config file, then the function/import/whatever will fail and the values won't be populated. Could you clarify a bit? – C.Nivs Dec 15 '21 at 19:35
  • @C.Nivs the user would populate the file, preferably under /etc. It seems to be the accepted way for many packages now.. I can see why json is beating yaml for this. I just wanted something quick and dirty, but there might be a proper way after all. – mckenzm Dec 16 '21 at 02:54
  • @mckenzm That could be handled a few different ways. You could use environment variables, key vaults, config files, etc – C.Nivs Dec 17 '21 at 17:35