Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > eval's local arguement ignored?

Reply
Thread Tools

eval's local arguement ignored?

 
 
=?ISO-8859-1?Q?Jean-S=E9bastien_Bolduc?=
Guest
Posts: n/a
 
      09-23-2003
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
 
Reply With Quote
 
 
 
 
Peter Abel
Guest
Posts: n/a
 
      09-26-2003
http://www.velocityreviews.com/forums/(E-Mail Removed) (Jean-Sébastien Bolduc) wrote in message news:<(E-Mail Removed). 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
 
Reply With Quote
 
 
 
 
Jean-S?bastien Bolduc
Guest
Posts: n/a
 
      09-30-2003
> **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
 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      09-30-2003
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

 
Reply With Quote
 
Peter Abel
Guest
Posts: n/a
 
      09-30-2003
(E-Mail Removed) (Jean-S?bastien Bolduc) wrote in message news:<(E-Mail Removed). 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 xx*a,locals())')

will show that:
{'a': 99999, 'fn_string': 'lambda xx*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 xx*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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
trouble with FileUtils.rm() -- Invalid arguement error an an Ruby 11 02-09-2008 02:52 AM
Error:Template as friend class with different arguement list Nike C++ 7 05-22-2007 07:29 AM
Invalid Procedure Call or Arguement Matt ASP General 5 05-05-2006 09:25 PM
problem with \r\n and \n (when passing multi line string arguement) In-Ho Yi ASP .Net Web Services 1 12-11-2003 07:16 PM
Can't use 'local' to find sql server instances on local machine karim ASP .Net 1 06-26-2003 09:17 PM



Advertisments