How to eval a file

Bengt Richter bokr at
Sun Feb 23 18:32:44 CET 2003

On 23 Feb 2003 14:42:34 +0100, d95-bli at (=?iso-8859-1?q?Bj=F6rn?= Lindberg) wrote:

>bokr at (Bengt Richter) writes:
>> If you'd posted a minimal example of what you did "without success,"
>> with copy/paste of the screen interaction and/or test run, I'd bet you
>> would know by now how to make it work ;-)
>I tried something like this:
>class C:
>    def m(self):
>        execfile("../collection/collection.layout")
>        self.collection = collection
>    def n(self):
>        return self.collection
>c = C()
>print c.n()
>  File "/tmp/python-2494uy", line 6, in m
>    self.collection = collection
>NameError: global name 'collection' is not defined
>The file has a line with "collection = 'bla, bla....'" in it.
Good post ;-)

UIAM, the reason it doesn't work is that at the time the code is generated
for the C.m method, the compiler can't tell that 'collection' will later be
a local variable created by execfile, so the reference defaults to global, and
code is generated to access the global, which doesn't exist and doesn't get
created, hence the NameError exception.

One way to make it work is to make it local by binding something to 'collection'
in the visible source, e.g.,

     def m(self):
         collection = None
         self.collection = collection

You probably don't want to use an actual global, since (I assume) collection is
just a temporary for the purpose of setting self.collection, but you could, by
declaring collection to be global. The surprise is _where_ you have to declare it global.

I.e., the NameError you got showed that the reference was already global, but the
execfile was binding 'collection' locally. Execfile must compile the source from
the file before it can execute it, and in _that_ source would be the place to declare
that a particular variable was global, i.e., at the top of your collection.layout file.
(This assumes you really want to direct _particular_ name bindings to global scope,
since the easy way to get them all there is just to specify globals() to execfile).

     def m(self):
         # Using a file with lines with
         # global collection
         # collection = 'bla, bla....'
         self.collection = collection # default global reference now works

Alternatively, since self is defined, you could use that explicitly in the
code of the file you are execfile-ing, and then you wouldn't need the
self.collection = collection line. E.g.,

     def m(self):
         # Using a file with line specifying self, e.g.,
         # self.collection = 'bla, bla....'

Alternatively, you can get 'collection' from the local vars by way of the vars() dict,
which should reflect current content, e.g.,

     def m(self):
         self.collection = vars()['collection']
         # or self.collection = vars().get('collection','<collection undef>')

And, as you noticed, you can also specify particular directories for execfile. If you want
all the bindings like collection = 'bla, bla....' to appear as instance attributes, you could
specify the dict that holds such attributes, e.g.,

     def m(self):
         execfile("../collection/collection.layout", self.__dict__)
         del self.__builtins__ # remove binding introduced by execfile
>>  execfile(...)
>>      execfile(filename[, globals[, locals]])
>>      Read and execute a Python script from a file.
>>      The globals and locals are dictionaries, defaulting to the current
>>      globals and locals.  If only globals is given, locals defaults to it.
>So, if the globals and locals arguments defaults to the current scope,
>why don't I have a global variable 'collection' when the execfile returns?
>However, if I include a dictionary as a second argument to execfile(),
>I can extract 'collection' from it, and it works like expected.
Yup, lots of options. There are also utility modules for dealing with config files,
and the possibility of importing the file as a module, as others have mentioned.


Bengt Richter

More information about the Python-list mailing list