473,322 Members | 1,307 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

eval's local arguement ignored?

Hello,

I would like to associate a local namespace with a lambda function. To
be more specific, here is exactly what I would want:

def foo():
a = 1
f = lambda x : a*x
return f

then if "f1 = foo()", I get a function whose parameter "a" is not in
the global scope. But my functions are not to be hard-coded. I naively
expected the following to work:

def foo(funcstring):
a = 1
f = eval(funcstring)
return f

but "f2 = foo( 'lambda x : a*x' )" won't work: "f2()" will look for
"a" in the globals.

Looking at the documentation (I did!), I was then certain replacing
the evaluation with the following would work:

f = eval(funcstring, globals(), locals())

Or, while we're at it, evaluating the whole thing outside of function
"foo":

f = eval('lambda x : a*x', globals(), {'a' : 1})

Ooops! the new function still looks for "a" in the globals... Although
I could not find any documentation about the fact, it seems the
"local" argument to "eval" has no effect in the above cases!

So for now, I'm doing something like

f = eval('lambda x : a*x', {'a' : 1})

but then my function looses access to the globals.

I know that only the very first case above gives me a function whose
"fun_closure" attribute is not "None". But still I cannot see where I
go wrong.

Thank you,

JSeb
Jul 18 '05 #1
4 2007
js**@cs.mcgill.ca (Jean-Sébastien Bolduc) wrote in message news:<56**************************@posting.google. com>...
Hello,

I would like to associate a local namespace with a lambda function. To
be more specific, here is exactly what I would want:

def foo():
a = 1
f = lambda x : a*x
return f

then if "f1 = foo()", I get a function whose parameter "a" is not in
the global scope. But my functions are not to be hard-coded. I naively
expected the following to work:

def foo(funcstring):
a = 1
f = eval(funcstring)
return f

but "f2 = foo( 'lambda x : a*x' )" won't work: "f2()" will look for
"a" in the globals.

Looking at the documentation (I did!), I was then certain replacing
the evaluation with the following would work:

f = eval(funcstring, globals(), locals())

Or, while we're at it, evaluating the whole thing outside of function
"foo":

f = eval('lambda x : a*x', globals(), {'a' : 1})

Ooops! the new function still looks for "a" in the globals... Although
I could not find any documentation about the fact, it seems the
"local" argument to "eval" has no effect in the above cases!

So for now, I'm doing something like

f = eval('lambda x : a*x', {'a' : 1})

but then my function looses access to the globals.

I know that only the very first case above gives me a function whose
"fun_closure" attribute is not "None". But still I cannot see where I
go wrong.

Thank you,

JSeb


**kwa** is the solution!

In your factory-function *foo* you have to declare *a*
keywordarguement which is initialized with a.
def foo(): .... a=1
.... f=lambda x,a=a:a*x
.... return f
f1=foo()
f1(3) 3

A global *a* doesn't affect your function. a=1000
f1(3) 3

but you even can get influence to *a*: f1(3,a=100) 300 or f1(3,100) 300
And this works too, even if you generate a lambda-function
as adhoc-function in the global scope:
!! You have to define *a* as first !! a=100
f2=lambda x,a=a:a*x
f2(3) 300

To change the global *a* doesn't affect your lambda-function! a=0
f2(3) 300

But you can give your function the additional information. f2(3,a=1) 3

or more traditional f2(3,1) 3

And the default kwa will stay resident. f2(3) 300


Regards
Peter
Jul 18 '05 #2
> **kwa** is the solution!

In your factory-function *foo* you have to declare *a*
keywordarguement which is initialized with a.
def foo():

... a=1
... f=lambda x,a=a:a*x
... return f


Not exactly what I'm looking for, I'm afraid. A more complete picture
is this: I'm writing a class such as this:

class Foo:
def __init__(self, fnc, **params):
...
def evaluate(self, val)
...

That has to be instantiated as, e.g.:

x = Foo( 'lambda x : a*x', dict( a = 2. ) )

so that "x.evaluate( 5. )" will return, in this case, "2.*5.".

The approach you describe will certainly work, but the thing is that
this class will have to be used by people who don't necessarily know
Python (yet). So I would really like the lambda function's parameter
list to always be the same, whatever you put on its RHS.

Once again, I don't understand why the "eval", as described above with
"globals" and "locals" arguments specified, will not work. Is there a
way to modify a function's closure?

Thanks,
JSeb
Jul 18 '05 #3
Jean-S?bastien Bolduc wrote:
...
is this: I'm writing a class such as this:

class Foo:
def __init__(self, fnc, **params):
...
def evaluate(self, val)
...

That has to be instantiated as, e.g.:

x = Foo( 'lambda x : a*x', dict( a = 2. ) )
Hmmm. 'a' is NOT a local in that lambda -- it's a global. locals
are [a] arguments, plus [b] variables that get re-bound within the
function (which, in a lambda, means only control variables used in
list comprehensions), PERIOD. That, if you want, is the DEFINITION
of "local variable" in Python.

So, that dict had better be in the GLOBALS, or else variable 'a' will
of course not be fond.

so that "x.evaluate( 5. )" will return, in this case, "2.*5.".

The approach you describe will certainly work, but the thing is that
this class will have to be used by people who don't necessarily know
Python (yet). So I would really like the lambda function's parameter
list to always be the same, whatever you put on its RHS.

Once again, I don't understand why the "eval", as described above with
"globals" and "locals" arguments specified, will not work. Is there a
way to modify a function's closure?


You may play with closures, yes (not really modifying a function's
closure but rather building a new function object with a code taken
from one place and a closure from another, say), but I'm not sure it
would help you.

Consider the following...:
import dis
thefunc = lambda x: a * x
dis.dis(thefunc) 1 0 LOAD_GLOBAL 0 (a)
3 LOAD_FAST 0 (x)
6 BINARY_MULTIPLY
7 RETURN_VALUE
Even if you're not familiar with Python's bytecode, I hope the simple
disassembly above is clear enough anyway: the value of 'a' is "loaded"
(onto the Python virtual machine's stack) as a *GLOBAL*, the value of
'x' is loaded via the "fast" (locals-only) route, then the multiply
happens (using the two top entries of the stack and pushing the result)
and the result is returned as the function's value.

Now, since you have the lambda available AS A STRING, you may consider:
def ff(a=99): .... return lambda x: x * a
.... thefunc1 = ff()
dis.dis(thefunc1) 2 0 LOAD_FAST 0 (x)
3 LOAD_DEREF 0 (a)
6 BINARY_MULTIPLY
7 RETURN_VALUE


Here, the Python compiler knows that a IS a local (an argument, in
this example) in an enclosing function, therefore it loads 'a' with
LOAD_DEREF, *NOT* with LOAD_GLOBAL. Because of this, and of this
only, thefunc1.closure does matter (it's a cell referencing that
int value, 99 in this case). Perhaps that might help, though it
still takes QUITE a bit of work to exploit it.

However, I do not understand why you should fight "the system" (the
fact that the Python compiler KNOWS that 'a' is global in the first
and simpler use) -- why not just supply that dict you have as (some
part of) the globals...?
Alex

Jul 18 '05 #4
js**@cs.mcgill.ca (Jean-S?bastien Bolduc) wrote in message news:<56**************************@posting.google. com>...
**kwa** is the solution!

In your factory-function *foo* you have to declare *a*
keywordarguement which is initialized with a.
>> def foo():

... a=1
... f=lambda x,a=a:a*x
... return f


Not exactly what I'm looking for, I'm afraid. A more complete picture
is this: I'm writing a class such as this:

class Foo:
def __init__(self, fnc, **params):
...
def evaluate(self, val)
...

That has to be instantiated as, e.g.:

x = Foo( 'lambda x : a*x', dict( a = 2. ) )

so that "x.evaluate( 5. )" will return, in this case, "2.*5.".

The approach you describe will certainly work, but the thing is that
this class will have to be used by people who don't necessarily know
Python (yet). So I would really like the lambda function's parameter
list to always be the same, whatever you put on its RHS.

Once again, I don't understand why the "eval", as described above with
"globals" and "locals" arguments specified, will not work. Is there a
way to modify a function's closure?

Thanks,
JSeb


Sorry, I missunderstood you.
Since your last post I learned the further more two
parameters of the eval-function. I'm even not sure
if I checked the problem entirely, but let me try to
explain what I think I may have understood.

In the following function the eval-statement doesn't
really need the locals() to evaluate the lambda-function.
It really needs to tell the lambda where is its parent's
namespace - what is by default the modules-namespace which
one calls *globals()* - where to search for variables when
not found in the locals().
def new_fn(fn_string): .... a=99999
.... print locals()
.... local_fun=eval(fn_string,globals(),locals())
.... return local_fun
....

I think the locals() are always the variables of a function's
body - in the above case of the function *new_fn*.
f=new_fn('lambda x:(x*a,locals())') will show that:
{'a': 99999, 'fn_string': 'lambda x:(x*a,locals())'}

So the following let us know what locals() means
for the lambda-function: a=0
f(10) (0, {'x': 10}) But *a* is found in the global-scope.
I'm not sure if this really helps you and the only
workaround for me is something I posted to you the last time.

What makes me more confused is the following example, where
the lambda-function is declared explicitly.
def new_fn(): .... a=99999
.... print locals()
.... local_fun=lambda x:(x*a,locals())
.... return local_fun
.... f=new_fn() {'a': 99999} a=0
f(10) (999990, {'a': 99999, 'x': 10})


But I think that's what you did already.

PS: I here someone whispering something of *nested scopes*.

Regards
Peter
Jul 18 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Peter Luciak | last post by:
Hi, I need to do something like this: def my(): a,b=1,2 func = "lambda x: a*x+b" map(eval(func),) my()
7
by: robcarlton | last post by:
hi everybody I've written this function to make a list of all of an objects attributes and methods (not for any reason, I'm just learning) def list_members(obj) l = dir(obj) return map(lambda...
2
by: dm_dal | last post by:
I have a control on my webform that I am binding to a dataset. The issue is, the field value in the dataset is encrypted and I am trying to decrypt it during the binding process: Example: ...
3
by: Jens | last post by:
Hi, has anyone an idea why the following code does not work. s = """ def a(n): return n*n
3
by: Pauljh | last post by:
Hi All, I'm running some javascript over a server side generated web page and have multiple generated empty select statements, that I want to populate when the page is loaded. As HTML doesn't do...
8
by: FAQ server | last post by:
----------------------------------------------------------------------- FAQ Topic - When should I use eval? ----------------------------------------------------------------------- The ` eval() `...
2
by: Florian Loitsch | last post by:
hi, What should be the output of the following code-snippet? === var x = "global"; function f() { var x = 0; eval("function x() { return false; }"); delete x; alert(x); }
10
by: Gordon | last post by:
I have a script that creates new objects based on the value of a form field. Basically, the code looks like this. eval ('new ' + objType.value + '(val1, val2, val3'); objType is a select with...
0
by: mag | last post by:
I have a make file that executes a perl script that takes PERL as an eval. The script executes the eval() function via an arguement to the script like this: target: script $(ARGUMENT) ...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shćllîpôpď 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.