Writing func_closure?

F

Fernando Perez

Hi all,

by reading through the docs, the func_closure attribute of function objects is
listed as writable. Yet, nowhere does it say _how_ to write to it. I am
trying to do a run-time modification of a function's closure, where I want to
modify the value of one of the variables in the closure. But the closure
appears as a tuple of 'cell' objects:

In [21]: def wrap(x):
....: def f(y):
....: return x+y
....: return f
....:

In [22]: f1=wrap('hello')

In [23]: f1.func_closure
Out[23]: (<cell at 0x4168bcd4: str object at 0x41bc0080>,)

My question is, how can I create one of these cell objects to stuff into the
closure (I want to do this from pure Python, not C extensions).

The docs mention this as 'possible', but don't provide a single example (though
they don't really specify if it can be done in python or only in C). The 'new'
module is equally useless, since new.function() comes without any examples:

In [25]: new.function?
Type: type
Base Class: <type 'type'>
String Form: <type 'function'>
Namespace: Interactive
Docstring:
function(code, globals[, name[, argdefs[, closure]]])

Create a function object from a code object and a dictionary.
The optional name string overrides the name from the code object.
The optional argdefs tuple specifies the default argument values.
The optional closure tuple supplies the bindings for free variables.

See that last line? Nowhere does it say what how the closure tuple is supposed
to be constructed. I tried a bunch of things, and none of my shot-in-the-dark
attempts got me anywhere.

Any help on this would be much appreciated.

Best,

f
 
M

Michael Hoffman

Fernando said:
> I am trying to do a run-time modification of a function's closure,
> where I want to modify the value of one of the variables in the closure.

Out of curiosity, why?
In [21]: def wrap(x):
....: def f(y):
....: return x+y
....: return f
....:

In [22]: f1=wrap('hello')

In [23]: f1.func_closure
Out[23]: (<cell at 0x4168bcd4: str object at 0x41bc0080>,)

My question is, how can I create one of these cell objects to stuff into the
closure (I want to do this from pure Python, not C extensions).
>>> f1.func_closure[0].__class__()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot create 'cell' instances

Hmmm, that didn't work so well.
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: readonly attribute

Closer inspection of the docs <http://docs.python.org/ref/types.html>
reveals that it is not writable after all. Therefore the only way I can
see to do it without writing an extension is to generate some dummy
function and copy the func_closure attribute from it. Luckily, you have
already produced a factory for such a function:
'howdy there'

Mix-and-match functions! What will they think of next?
 
F

Fernando Perez

Michael said:
Out of curiosity, why?

Oh, I was just trying to play a little trick inside a tight loop where I would
modify on the fly the function's closure to change a parameter. I can do it in
a million ways, but at creation time, the closure approach provides the
cleanest syntax. But at runtime, I have an algorithm that needs to modify
certain parameters many times, and the least-expensive way would be to be able
to write directly into the closure.
Closer inspection of the docs <http://docs.python.org/ref/types.html>
reveals that it is not writable after all. Therefore the only way I can

Ah, the docs have improved. I'm using 2.3.4, and the same page:

http://www.python.org/doc/2.3.4/ref/types.html

only says:

Of these, func_code, func_defaults, func_doc/__doc__, and func_dict/__dict__ may
be writable; the others can never be changed.

That's what led me to believe it could be done. Thanks for pointing me to the
2.4 docs, which are much less ambiguous.

see to do it without writing an extension is to generate some dummy
function and copy the func_closure attribute from it. Luckily, you have
already produced a factory for such a function:

Yes, I knew of the new.function() approach, but the problem is that I don't know
how to make a fresh closure for it. I can reuse the closure from a different
function, but the docs don't say how to make a valid closure tuple. This is
the typical problem of the stdlib docs, which under-specify what is supposed to
go into a call and don't give at least a specific example.

Many thanks though, I'll probably end up using a less dirty hack :)

Cheers,

f
 
G

Greg Ewing

Fernando said:
I can reuse the closure from a different
function, but the docs don't say how to make a valid closure tuple. This is
the typical problem of the stdlib docs, which under-specify what is supposed to
go into a call and don't give at least a specific example.

As far as I know, there is currently no supported way
of directly creating or modifying cell objects from Python;
it can only be done by some obscure trickery. So the docs
are telling the truth here, in a way. :)
 
F

Fernando Perez

Greg said:
As far as I know, there is currently no supported way
of directly creating or modifying cell objects from Python;
it can only be done by some obscure trickery. So the docs
are telling the truth here, in a way. :)

In a twisted, convoluted way :)

But thanks for the clarification (which IMHO belongs in the docs). Oh well, it
was a dirty hack anyways, so it's probably best not done.

Cheers,

f
 
M

Michael Hoffman

Fernando said:
Yes, I knew of the new.function() approach, but the problem is that I don't know
how to make a fresh closure for it. I can reuse the closure from a different
function, but the docs don't say how to make a valid closure tuple.
.... def _f():
.... x
.... return _f.func_closure
....(<cell at 0x4613bc: int object at 0x4a3e4c>,)

OK, that's kind of limited. God only knows what happens when there is
more than one variable, although you could add extra levels of hackery
to do with that.
Many thanks though, I'll probably end up using a less dirty hack :)

*Excellent* idea.
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top