Using non-dict namespaces in functions

S

Steven D'Aprano

Inspired by the new collections.ChainMap in Python 3.3

http://docs.python.org/dev/library/collections.html#collections.ChainMap

I would like to experiment with similar non-dictionary namespaces in
Python 3.2.

My starting point is these two recipes, adapted for Python 3.2:

http://code.activestate.com/recipes/305268/
http://code.activestate.com/recipes/577434/

Or for simplicity, here's a mock version:


from collections import Mapping
class MockChainMap(Mapping):
def __getitem__(self, key):
if key == 'a': return 1
elif key == 'b': return 2
raise KeyError(key)
def __len__(self):
return 2
def __iter__(self):
yield 'a'
yield 'b'

Note that it is important for my purposes that MockChainMap does not
inherit from dict.

Now I try to create a function that uses a MockChainMap instead of a dict
for its globals:

function = type(lambda: None)
f = lambda x: (a+b+x)
g = function(f.__code__, MockChainMap(), 'g')

And that's where I get into trouble:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() argument 2 must be dict, not MockChainMap


How do I build a function with globals set to a non-dict mapping?

If this can't be done, any suggestions for how I might proceed?
 
E

Eric Snow

Note that it is important for my purposes that MockChainMap does not
inherit from dict.

Care to elaborate?
Now I try to create a function that uses a MockChainMap instead of a dict
for its globals:

function = type(lambda: None)
f = lambda x: (a+b+x)
g = function(f.__code__, MockChainMap(), 'g')

And that's where I get into trouble:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: function() argument 2 must be dict, not MockChainMap


How do I build a function with globals set to a non-dict mapping?

If this can't be done, any suggestions for how I might proceed?

This looks like one of those cases where there is strict type checking
(of a Python object) at the C level. You may consider bringing this
up in a tracker ticket. Unless there are performance implications,
it's likely a case of no one having bothered to change this spot to be
more duck-type friendly. There are quite a few of those in CPython
and I've seen at least a couple updated when someone brought it up.

Regardless, you could also implement __call__() on a function
look-alike class to get what you're after. It may not be as
performant though.

-eric
 
S

Steven D'Aprano

Care to elaborate?

I want to use collections.ChainMap, or something very like it, and I
don't want to be forced into an unnatural is-a relationship with dict if
I don't have to.


[...]
Regardless, you could also implement __call__() on a function look-alike
class to get what you're after. It may not be as performant though.

I don't think that can work, because __call__ itself is a function, and I
would need to change *its* globals. Which brings me back exactly where I
started, trying to change globals in a function to a non-dict.
 
P

Peter Otten

Steven said:
Care to elaborate?

I want to use collections.ChainMap, or something very like it, and I
don't want to be forced into an unnatural is-a relationship with dict if
I don't have to.


[...]
Regardless, you could also implement __call__() on a function look-alike
class to get what you're after. It may not be as performant though.

I don't think that can work, because __call__ itself is a function, and I
would need to change *its* globals. Which brings me back exactly where I
started, trying to change globals in a function to a non-dict.

The key lookup code in ceval.c is inlined, so even subclassing dict and
overriding __getitem__() won't help. Instead of

def f(a):
return a + b # b taken from some custom namespace

you have to resort to the conventional approach

def f(a, ns=magic()):
return a + ns["b"]

or

def f(self, a):
return a + self.b
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top