5

In python what is the equivalent of the quote operator? I am finding the need to delay evaluation. For example, suppose in the following lisp psuedocode I have:

a = '(func, 'g)
g = something
(eval a)

What I am doing is deferring evaluation of g till a later time. This is necessary because I want to define g later. What is the equivalent idea of this psuedocode in python?

CodeKingPlusPlus
  • 15,383
  • 51
  • 135
  • 216
  • 3
    Usually, if you're trying to translate something to Python, and it isn't obvious how to do so, you're doing something deeply unpythonic, and need to step back a level to find the Pythonic way to do what you're actually trying to do. In particular, any code that uses `eval` probably shouldn't be written in the first place. – abarnert Aug 15 '13 at 19:41
  • 1
    I definitely will be trying to switch to clojure in the next few days... – CodeKingPlusPlus Aug 15 '13 at 19:54
  • 8
    To be honest, even in Lisp, `eval` is _not_ the correct way to delay the evaluation of an expression. Generally, you wrap the expression in a `lambda` and call it later on. Scheme also offers `delay`/`force`, which provides memoisation of the `lambda`'s result. – C. K. Young Aug 15 '13 at 19:56

2 Answers2

8
a = lambda: func(g)
g = something
a()

This isn't quite the most literal translation - the most literal translation would use a string and eval - but it's probably the best fit. Quoting probably isn't what you wanted in Lisp anyway; you probably wanted to delay something or create a lambda. Note that func and g are closure variables in the lambda function, rather than symbols, so if you call a from an environment with different bindings for func or g, it'll still use the variables from a's environment of definition.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 4
    +1 As I mentioned to the OP, even in Lisp, `eval` is the wrong answer to most questions, including delayed evaluation. (EDIT: You just made an edit to say the same thing. :-D) – C. K. Young Aug 15 '13 at 20:01
  • Note that python also has promise/delay libraries. – Marcin Aug 15 '13 at 21:31
4

Using eval for delaying evaluation is bad, both in Lisp and Python.

in Python, and in Lisp, you can delay evaluation using a closure:

def print_it(x):
    def f():
        print g(x)
    return f

f = print_it(42)

def g(x):
   return x * x

f()

Please note that what is captured in a closure is not the value of a variable, but the variable itself and this is sometimes surprising:

fa = []

for x in range(10):
    def g():
        print x
    fa.append(g)

for f in fa:
    f() # all of them will print 9

x = 42

fa[0]() # the output will be 42

to solve this problem (that can also be present in Common Lisp) you may see things like:

for x in range(10):
    def g(x = x):
        print x
    fa.append(g)

or (in CL) things like

(let ((a a))
  (lambda () (print a)))

Python also has a lambda special form for anonymous functions, but they are limited to one single expression and cannot contain any statement. A locally def-ined function instead is a regular function without any limitations.

for x in range(10):
    # print is a statement in Python 2.x and cannot be in a lambda
    fa.append(lambda x=x: sys.stdout.write(str(x) + "\n"))

Finally Python 2.x has a syntax limitation and closed-over variables are read-only because if there is an assignment (or augmented-assignment) in a function there are only two possibilities:

  1. The variable is a global (and has been previously declared so with global x)
  2. The variable is a local

and in particular it's ruled out that a variable being assigned could be a local of an enclosing function scope.

Python 3.x removed this limitation by providing a new possible declaration nonlocal x and now the famous adder example can be implemented as

def adder(x):
    def f(y):
        nonlocal x
        x += y
        return x
    return f
6502
  • 112,025
  • 15
  • 165
  • 265