Closures in python

  • Thread starter Kasper B. Graversen
  • Start date
K

Kasper B. Graversen

Having played with Smalltalk for the past month, I'm getting used to
passing code as arguments to methods... how easy is it to do this in
python? I haven't seen any recent postings on this subject here...

\kasper
 
L

Ladvánszky Károly

Try this.

def f(n):
return n*2

def t(fnc_prm, n):
return fnc_prm(n)

t(f, 2)

I hope it helps.

Károly
 
S

Syver Enstad

Having played with Smalltalk for the past month, I'm getting used to
passing code as arguments to methods... how easy is it to do this in
python? I haven't seen any recent postings on this subject here...

It is fairly straightforward:

import sys

def funcThatTakesCallable(aCallable):
aCallable('SomeString')

class MyClass:
def myFunc():
def myCallable(arg):
print arg
funcThatTakesCallable(myCallable)
funcThatTakesCallable(self.anotherCallable)
funcThatTakesCallable(lambda arg: sys.stdout.write('%s\n' % arg))

def anotherCallable(self, arg):
print 'another', arg


The major difference is that the anonymous form of a function (lambda)
isn't allowed to contain statements, only an expression. This is
rather crippling for Smalltalk/Ruby style coding and seems to lead to
warts like list comprehensions instead of having simple methods in the
collection interface that takes a block/lambda and calls this for each
element of the collection.

Example:

newCollection = [each for each in collection if each != 'Sausage']

newCollection = collection.select(lambda each: each != 'Sausage')
 
D

Daniel Dittmar

Kasper said:
Having played with Smalltalk for the past month, I'm getting used to
passing code as arguments to methods... how easy is it to do this in
python? I haven't seen any recent postings on this subject here...

There is no direct equivalent of code blocks in Python. Use Callables
instead. Callables are

- functions
def mywrite (text):
sys.stdout.write (text)
variable = mywrite
variable ('printed text')

- bound methods, a method bound to a specific object
variable = sys.stdout.write
variable ('printed text')

- lambda, unnamed functions, which can contain only one expression
variable = lambda text: sys.stdout.write (text)
variable ('printed text')

- classes implementing the __call__ method
class Writer:
def __call__ (self, text):
sys.stdout.write (text)
variable = Writer ()
variable ('printed text')

Daniel
 
H

Hallvard B Furuseth

'closure' is a much-abused word.
This is a closure over foo's x variable:

def foo():
x = 3
def bar():
x += 1
return x
return bar

f = foo()
print f() # print 4
g = foo()
print f() # print 5
print g() # print 4

....or it would be, if it worked.
 
L

Ladvánszky Károly

Try this.

def f(n):
return n*2

def t(fnc_prm, n):
return fnc_prm(n)

t(f, 2)

I hope it helps.

Károly
 
A

Anton Vredegoor

Hallvard B Furuseth said:
'closure' is a much-abused word.
This is a closure over foo's x variable:

How about namespaces?
def foo():
x = 3
def bar():
x += 1
return x
return bar

f = foo()
print f() # print 4
g = foo()
print f() # print 5
print g() # print 4

...or it would be, if it worked.

This works:

def foo():
class ns:pass
ns.x = 3
def bar():
ns.x += 1
return ns.x
return bar

Anton
 
J

JCM

Hallvard B Furuseth said:
'closure' is a much-abused word.
This is a closure over foo's x variable:
def foo():
x = 3
def bar():
x += 1
return x
return bar
f = foo()
print f() # print 4
g = foo()
print f() # print 5
print g() # print 4
...or it would be, if it worked.

Python does have closures; the trouble is you can't rebind variables
defined in arbitrary scopes--you can only rebind locals and globals.
So you need some indirection for it to work:
... x = [3]
... def bar():
... x[0] += 1
... return x[0]
... return bar
... 4

This is actually one of my biggest complaints about Python. I'd like
syntactic disambiguation between definition and assignment in order to
have control over which scope you're assigning into.
 
H

Hallvard B Furuseth

Anton said:
How about namespaces?
(...)

Nice! Being a Python newbie I needed JCM's explanation to figure out
how it worked, though. Nothing magic about classes at all...
 
H

Hallvard B Furuseth

JCM said:
... x = [3]
... def bar():
... x[0] += 1
(...)

This is actually one of my biggest complaints about Python. I'd like
syntactic disambiguation between definition and assignment in order to
have control over which scope you're assigning into.

Maybe Python could be changed to let 'foo.x' inside function foo mean
the x variable in foo?
 
A

Alex Martelli

nospam said:
JCM said:
def foo():
... x = [3]
... def bar():
... x[0] += 1
(...)

This is actually one of my biggest complaints about Python. I'd like
syntactic disambiguation between definition and assignment in order to
have control over which scope you're assigning into.

Maybe Python could be changed to let 'foo.x' inside function foo mean
the x variable in foo?

That would be backwards-incompatible, since foo.x already means
something -- the attribute x of object foo (yep, functions are objects
and can have attributes), which has no connection whatsoever with
the local variable x inside (some of the potentially many currently
active instances of) functions named foo.


Alex
 
D

David Eppstein

Hallvard B Furuseth said:
JCM said:
def foo():
... x = [3]
... def bar():
... x[0] += 1
(...)

This is actually one of my biggest complaints about Python. I'd like
syntactic disambiguation between definition and assignment in order to
have control over which scope you're assigning into.

Maybe Python could be changed to let 'foo.x' inside function foo mean
the x variable in foo?

But the x variable does not live on the foo function object, it lives on
the stack frame created by the current call to foo.

So something more indirect, like scope(foo).x, would make more sense,
where scope() inspects the call stack looking for calls to foo and
returns an object with appropriate __getattr__ and __setattr__ methods.
This may be implementable now, by someone who knows more about python
introspection than I do. I tried doing it with inspect.stack, but it
doesn't work -- I can find the right frame and get it's f_locals
dictionary, but this gives read-only access to the true frame's locals.
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top