[Python-Dev] Adding a builtins parameter to eval(), exec() and __import__().

Guido van Rossum guido at python.org
Fri Mar 9 01:39:12 CET 2012


On Thu, Mar 8, 2012 at 4:33 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> On Fri, Mar 9, 2012 at 3:31 AM, Guido van Rossum <guido at python.org> wrote:
>> But the __builtins__ that are actually used by any particular piece of
>> code is *not* taken by importing builtins. It is taken from what the
>> globals store under the key __builtins__.
>>
>> This is a feature that was added specifically for sandboxing purposes,
>> but I believe it has found other uses too.
>
> Agreed, but swapping out builtins for a different namespace is still
> the exception rather than the rule. My Impression of Mark's proposal
> was that this approach would become the *preferred* way of doing
> things, and that's the part I don't like at a conceptual level.
>
>>>> The key point is that every piece of code already inherits locals, globals
>>>> and builtins from somewhere else.
>>>> We can already control locals (by which parameters are passed in) and
>>>> globals via exec, eval, __import__, and runpy (any others?)
>>>> but we can't control builtins.
>>>
>>> Correct - because controlling builtins is the domain of sandboxes.
>>
>> Incorrect (unless I misunderstand the context) -- when you control the
>> globals you control the __builtins__ set there.
>
> And this is where I don't like the idea at a practical level. We
> already have a way to swap in a different set of builtins for a
> certain execution context (i.e. set "__builtins__" in the global
> namespace) for a small chunk of code, as well as allowing
> collections.ChainMap to insert additional namespaces into the name
> lookup path.
>
> This proposal suggests adding an additional mapping argument to every
> API that currently accepts a locals and/or globals mapping, thus
> achieving... well, nothing substantial, as far as I can tell (aside
> from a lot of pointless churn in a bunch of APIs, not all of which are
> under our direct control).
>
>> In any case, the locals / globals / builtins chain is a
>> simplification; there are also any number of intermediate scopes
>> (between locals and globals) from which "nonlocal" variables may be
>> used. Like optimized function globals, these don't use a dict lookup
>> at all, they are determined by compile-time analysis.
>
> Acknowledged, but code executed via the exec API with both locals and
> globals passed in is actually one of the few places where that lookup
> chain survives in its original form (module level class definitions
> being the other).
>
> Now, rereading Mark's original message, a simpler proposal of having
> *function objects* do an early lookup of
> "self.__globals__['__builtins__']" at creation time and caching that
> somewhere such that the frame objects can get hold of it (rather than
> having to do the lookup every time the function gets called or a
> builtin gets referenced) might be a nice micro-optimisation. It's the
> gratuitous API changes that I'm objecting to, not the underlying idea
> of binding the reference to the builtins namespace earlier in the
> function definition process. I'd even be OK with leaving the default
> builtins reference *out* of the globals namespace in favour of storing
> a hidden reference on the frame objects.

Agreed on the gratuitous API changes. I'd like to hear Mark's response.

-- 
--Guido van Rossum (python.org/~guido)


More information about the Python-Dev mailing list