MORE INFO

Cedric Adjih adjih at crepuscule.com
Mon May 1 18:49:51 EDT 2000


mdefreitas at sikorsky.com wrote:
> In article <8ehnvs$m0h$1 at ites.inria.fr>,
>   Cedric Adjih <adjih at crepuscule.com> wrote:
>> mdefreitas at sikorsky.com wrote:
>>
>> [...]
>>
>>   Indeed.
>>   PyRun_File is actually implementing most of the "execfile(...)"
>> code (see http://www.python.org/doc/current/lib/built-in-funcs.html).
>> Python source code for execfile is also an example of use for
>> PyRun_File.
>>   Passing empty dictionaries would be a way to have a "clean"
>> environment except if a script imports a Python module and fiddles
>> with its internals. Because modules will be shared among scripts.
>> But fiddling with internals is very bad style.
>>
>> -- Cedric

> Hmmm... I looked at the source code for execfile and it looks like it
> either passes PyRun_File the dictionaries that were passed into
> execfile itself, or if none was passed in, it passed PyRun_File the
> current dictionaries as default. I believe that what I need to do is
> pass in EMPTY dictionaries for the globals and locals. I tried the
> following:
>
> PyRun_File(fd, script, Py_file_input, PyDict_New(), PyDict_New());
>
> But that didn't seem to work. The top level script seemed OK, but the
> nested one didn't seem to execute. Is there something else that needs
> to be done? Is it bad to pass in an empty global dictionary? 

You're right, it's bad to pass an empty dictionnary as globals.
If you used PyErr_Print() and other functions, you'd have get
a nice traceback :-)
I guess Python tries to find builtins function from globals
(or at least __import__). Here is a better example:

------------- testpython.c

#include <assert.h>
#include <Python.h>

static PyObject* internal_pid(PyObject* self, PyObject* args)
{ return Py_BuildValue("i", getpid()); }

static PyMethodDef InternalMethods[] = {
  {"getPid",  internal_pid, METH_VARARGS},
  {NULL,      NULL}        /* Sentinel */
};

main(int argc, char**argv)
{
  FILE* f=fopen("pythonic.py", "r");
  PyObject* localDict;
  PyObject* result;
  PyObject* mainModule;
  PyObject* mainModuleDict;
  assert(f!=NULL);
	  
  /* init*/
  Py_Initialize();
	  
  /* get __main__ info */
  mainModule=PyImport_AddModule("__main__");
  if(mainModule==NULL) { PyErr_Print();
    exit(EXIT_FAILURE); }
  mainModuleDict=PyModule_GetDict(mainModule);
  if(mainModuleDict==NULL) { PyErr_Print(); exit(EXIT_FAILURE); }
  Py_InitModule("internal", InternalMethods);
	  
  /* first run */
  localDict=PyDict_New();
  result=PyRun_File(f, "pythonic.py", Py_file_input, 
      mainModuleDict, localDict);
	  
  if(result!=NULL) {
    Py_DECREF(result);
  } else {
    /*problem*/
	  
    /*<http://www.python.org/doc/current/ext/errors.html>, and
     <http://www.python.org/doc/current/api/exceptionHandling.html>:*/
    PyErr_Print();
  }
  fclose(f);
  /*<http://www.python.org/doc/current/api/refcounts.html>:*/
  Py_DECREF(localDict);
  
  /* second run */
  f=fopen("pythonic.py", "r");
  assert(f!=NULL);
  localDict=PyDict_New();
  result=PyRun_File(f, "pythonic.py", Py_file_input, 
    mainModuleDict, localDict);
  if(result!=NULL) Py_DECREF(result);
  else PyErr_Print();
  fclose(f);
	  
  /* free */
  Py_DECREF(localDict);	
  Py_DECREF(mainModuleDict);
  Py_DECREF(mainModule);
}
	  
--------------------------

#--------------------- pythonic.py
import string
import internal
    
print "-"*75
print "globals:",globals()
print "locals:", locals()
print  "dir():", dir()
		
def f(x):
  return x+1
a=5
    
print "ok", internal.getPid()
	
print "globals:",globals()
print "locals:", locals()
print  "dir():", dir()
#--------------------------------------------------
    
Variables and functions (i.e. new definitions) are put into
the locals dictionnary, which is what you want.
    
>                                                              Also, I
> noticed that there was a PyDict_New function, but not a PyDict_Delete
> function... I assume memory cleanup is automatic?

Unfortunatly, no.
You have to use the Py_INCREF/Py_DECREF functions, as documented
in http://www.python.org/doc/current/api/refcounts.html.
If you are using C++, CXX will offer wrappers (and other goodies),
that'll maintain this automatically, but CXX uses templates and require
an up-to-date C++ compiler. 
SCXX is a lighter version of the same idea without templates 
(which is what I use).

-- Cedric
 




More information about the Python-list mailing list