[Patches] [ python-Patches-1402289 ] Allow mappings as globals (was: Fix dictionary subclass ...)

SourceForge.net noreply at sourceforge.net
Thu Feb 15 10:55:19 CET 2007


Patches item #1402289, was opened at 2006-01-11 01:24
Message generated for change (Comment added) made by loewis
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1402289&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Core (C code)
Group: Python 2.5
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: crutcher (crutcher_gmail)
Assigned to: Raymond Hettinger (rhettinger)
Summary: Allow mappings as globals (was: Fix dictionary subclass ...)

Initial Comment:
There is an inconsistancy in the way that dictionary
subclasses behave
when they are used as as namespaces in execs.

Basically, while python 2.4 permits the usage of
dictionary subclasses
for local environments, it still bypasses the subclass
functions and
uses the C API for global environments. The attached
patch (and
unittest!) addresses this issue.

I'm pretty sure we keep the fast path in this.

----------------------------------------------------------------------

>Comment By: Martin v. Löwis (loewis)
Date: 2007-02-15 10:55

Message:
Logged In: YES 
user_id=21627
Originator: NO

Raymond, do you think you can make it this March? If not, please unassign.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-03-30 20:12

Message:
Logged In: YES 
user_id=1424288

Are you going to get to this?

----------------------------------------------------------------------

Comment By: Raymond Hettinger (rhettinger)
Date: 2006-02-21 14:28

Message:
Logged In: YES 
user_id=80475

Crutcher, this looked good on my first read-through.  Will 
go through it in detail sometime in March.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-30 20:10

Message:
Logged In: YES 
user_id=1424288

doh, forgot to check the 'upload' box

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-30 18:08

Message:
Logged In: YES 
user_id=1424288

I have reworked and extended this patch so that arbitrary
mappings are permitted for globals, not just dictionary
subtypes. This touched a good deal more code.

Please use the updated version.

----------------------------------------------------------------------

Comment By: Armin Rigo (arigo)
Date: 2006-01-25 19:20

Message:
Logged In: YES 
user_id=4771

I will review and check-in your patch, I think it's a good
idea despite the added code complexity.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-25 04:38

Message:
Logged In: YES 
user_id=1424288

currently chasing through the PyFrame code and the EXEC_STMT
code to make globals generic mappings, will update this
patch yet again.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-22 10:19

Message:
Logged In: YES 
user_id=1424288

I've fixed up the exception case, and extended the test case
to check for it. Is there anything else I can do to get this in?

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-22 06:11

Message:
Logged In: YES 
user_id=1424288

I'm going to fix the missed exception test this weekend, and
try to get an updated patch to you.

----------------------------------------------------------------------

Comment By: Armin Rigo (arigo)
Date: 2006-01-14 10:54

Message:
Logged In: YES 
user_id=4771

Provided this can be done with no measurable performance hit,
I guess that I'm fine with the idea.  The patch needs a bit
more work, though: I don't see why it should accept dict
subclasses as globals but not arbitrary mappings (as it now
does for the locals).  This is mainly an issue of removing
a few checks in various places, like EXEC_STMT and the eval()
and execfile() built-ins.

There is a missing exception check/clear in the part about
LOAD_NAME, after the PyObject_GetItem(f->f_globals, w).

A side note: in the current trunk already, LOAD_GLOBAL
contains a couple of checks, namely PyString_CheckExact()
and hash != -1.  We might be able to prove in advance that
these two conditions are always true.  We could then remove
the checks.  Not sure the difference measurable, though.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-12 08:50

Message:
Logged In: YES 
user_id=1424288

Well, why fix it for eval but not for exec? I don't think
the time hit is noticeable, I ran 'time make test' twice
each on the trunk with and without the patch. Here are the
results:

Trunk:
real    9m17.117s
user    3m30.930s
sys     0m35.417s

real    9m9.471s
user    3m31.484s
sys     0m34.978s

Patch:
real    9m32.469s
user    3m40.134s
sys     0m36.140s

real    9m6.779s
user    3m27.529s
sys     0m34.716s


----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2006-01-12 07:11

Message:
Logged In: YES 
user_id=21627

I think the history is this: it originates from
python.org/sf/215126, which requested that you can pass dict
subtypes to eval. Armin noted that eval will always produce
LOAD/STORE_NAME, so just modifying these opcodes is
sufficient to fulfil the feature request.

----------------------------------------------------------------------

Comment By: Raymond Hettinger (rhettinger)
Date: 2006-01-12 02:21

Message:
Logged In: YES 
user_id=80475

Okay, I will take it under consideration.  Also, I'll try to
remember the reason it wasn't done the first time around.

No promises though -- by itself consistency is a weak
motivation.

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-12 00:11

Message:
Logged In: YES 
user_id=1424288

Here's a more interesting example. This works fine, unless
the variables fall through to the global dictionary, or some
code marks them global.

import code

class ManagedVariable:
  def get(self):
    return None

  def set(self, value):
    pass

  def delete(self):
    # Return false to stop the delete.
    return True

class ManagedEnvironment(dict):
 def __setitem__(self, key, value):
   if self.has_key(key):
     if isinstance(dict.__getitem__(self, key),
ManagedVariable):
       dict.__getitem__(self, key).set(value)
       return
   dict.__setitem__(self, key, value)

 def __getitem__(self, key):
   if self.has_key(key):
     if isinstance(dict.__getitem__(self, key),
ManagedVariable):
       return dict.__getitem__(self, key).get()
   return dict.__getitem__(self, key)

 def __delitem__(self, key):
   if self.has_key(key):
     if isinstance(dict.__getitem__(self, key),
ManagedVariable):
       if not dict.__getitem__(self, key).delete():
         return
   dict.__delitem__(self, key)


class RangedInt(ManagedVariable):
  def __init__(self, value, (low, high)):
    self.value = value
    self.low = low
    self.high = high

  def get(self):
    return self.value

  def set(self, value):
    if value < self.low:
      value = self.low
    if value > self.high:
      value = self.high
    self.value = value


class FunctionValue(ManagedVariable):
  def __init__(self, get_func = None, set_func = None,
del_func = None):
    self.get_func = get_func
    self.set_func = set_func
    self.del_func = del_func

  def get(self):
    if self.get_func:
      return self.get_func()
    return None

  def set(self, value):
    if self.set_func:
      self.set_func(value)

  def delete(self):
    if self.del_func:
      return self.del_func()
    return True

class Constant(ManagedVariable):
  def __init__(self, value):
    self.value = value

  def get(self):
    return self.value

  def delete(self):
    return False


import time
d = ManagedEnvironment()
d['ranged'] = RangedInt(1, (0, 100))
d['time'] = FunctionValue(lambda: time.time())
d['constant'] = Constant(42)

code.interact(local=d)


----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-11 19:12

Message:
Logged In: YES 
user_id=1424288

Here's an example of a little typed environment. It's not
the most robust, but it gets you thinking.

import code
class TypedDictionary(dict):
 def __setitem__(self, key, value):
   if self.has_key(key):
     t = type(self[key])
     if t != type(value):
       try:
         value = t(value)
       except Exception:
         raise TypeError, \
             "illegal assignment to '%s':" \
             " %s cannot be coerced to %s" \
               % (key, type(value), t)
   dict.__setitem__(self, key, value)
code.interact(local=TypedDictionary())

----------------------------------------------------------------------

Comment By: crutcher (crutcher_gmail)
Date: 2006-01-11 03:16

Message:
Logged In: YES 
user_id=1424288

With the ability to use dictionary subclasses for local and
global environments, it becomes very easy to implement
execution environments with extended variable semantics for
special purposes.

This includes driving interactive processes, config file
processors, type checking, lazy object construction, and
read-only variables.

As it currently stands, the semantics are inconsistent. The
local case should not have been changed if the global case
was not going to be changed.

----------------------------------------------------------------------

Comment By: Raymond Hettinger (rhettinger)
Date: 2006-01-11 03:03

Message:
Logged In: YES 
user_id=80475

Do you have any use cases?  AFAICT, there were no unmet
needs with locals option.

Also, there was a reason that globals weren't included but I
remember what it was.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1402289&group_id=5470


More information about the Patches mailing list