forgetting to declare variables - python

If inside a loop, is it possible to instantiate objects to be manipulated during subsequent iterations of the loop, and still available when the scope of the loop has been left?
Here is a simple example of what I thought might work:
>>> for i in range(2):
... r = [] if r is None else r
... r.append[i]
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'r' is not defined
And here's my second attempt using a NameError exception:
>>> for i in range(2):
... try:
... r = r
... except NameError:
... r = []
... r.append(i)
...
>>>
I suspect that what I have been trying to do is actually prohibited, but I don't understand why it would be.
Can someone throw some light on this for me please?
Edit:
So the second way works, but it's very long winded. Is there a quick way?

It's not prohibited, but it is actively discouraged. NameError should never be caught barring extreme circumstances; always bind the name outside the loop even if to None.

You can find out if the name is in your locals like this: name in locals() Regarding your question:
>>> 'r' in locals()
False
>>> for i in range(2):
if 'r' not in locals(): r = []
r.append(i)
>>> r
[0, 1]
>>>
I agree with Ignacio Vazquez-Abrams; this is not good style. Please do what you need to before looping.

Related

How to get function object inside a function (Python)

I want to have something like
def x():
print get_def_name()
but not necessarily know the name of x.
Ideally it would return 'x' where x would be the name of the function.
You can do this by using Python's built-in inspect library.
You can read more of its documentation if you want to handle more complicated cases, but this snippet will work for you:
from inspect import getframeinfo, currentframe
def test_func_name():
return getframeinfo(currentframe()).function
print(test_func_name())
Functions in Python are objects, and as it happens those objects do have an attribute containing the name they were defined with:
>>> def x():
... pass
...
>>> print x.__name__
x
So, a naïve approach might be this:
>>> def x():
... print x.__name__
...
>>> x()
x
That seems to work. However, since you had to know the name of x inside the function in order to do that, you haven't really gained anything; you might have well just have done this:
def x():
print "x"
In fact, though, it's worse than that, because the __name__ attribute only refers to the name the function was defined with. If it gets bound to another name, it won't behave as you expect:
>>> y = x
>>> y()
x
Even worse, if the original name is no longer around, it won't work at all:
>>> del x
>>> y()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in x
NameError: global name 'x' is not defined
This second problem is one you can actually get around, although it's not pretty. The trick is to write a decorator that can pass the function's name into it as an argument:
>>> from functools import wraps
>>> def introspective(func):
... __name__ = func.__name__
... #wraps(func)
... def wrapper(*args, **kwargs):
... return func(__name__=__name__, *args, **kwargs)
... return wrapper
...
>>> #introspective
... def x(__name__):
... print __name__
...
>>> x()
x
>>> y = x
>>> y()
x
>>> del x
>>> y()
x
... although as you can see, you're still only getting back the name the function was defined with, not the one it happens to be bound to right now.
In practice, the short (and correct) answer is "don't do that". It's a fundamental fact of Python that objects don't know what name (or names) they're bound to - if you think your function needs that information, you're doing something wrong.
This sounds like you want to declare an anonymous function and it would return a reference to the new function object.
In Python, you can get a trivial anonymous function object with lambda but for a complex function it must have a name. But any function object is in fact an object and you can pass references around to it, so the name doesn't matter.
# lambda
sqr = lambda n: n**2
assert sqr(2) == 4
assert sqr(3) == 9
# named function
def f(n):
return n**2
sqr = f
assert sqr(2) == 4
assert sqr(3) == 9
Note that this function does have a name, f, but the name doesn't really matter here. We set the name sqr to the function object reference and use that name. We could put the function reference into a list or other data structure if we wanted to.
You could re-use the name of the function:
def f(n):
return n**2
sqr = f
def f(n):
return n**3
cube = f
So, while Python doesn't really support full anonymous functions, you can get the same effect. It's not really a problem that you have to give functions a name.
If you really don't want the function to have a name, you can unbind the name:
def f(n):
return n**2
lst = [f] # save function reference in a list
del(f) # unbind the name
Now the only way to access this function is through the list; the name of the function is gone.
I found a similar solution as Vazirani's, but I did a step forward to get the function object based on the name. Here is my solution:
import inspect
def named_func():
func_name = inspect.stack()[0].function
func_obj = inspect.stack()[1].frame.f_locals[func_name]
print(func_name, func_obj, func_obj.xxx)
named_func.xxx = 15
named_func()
Output is
named_func <function named_func at 0x7f3bc84622f0> 15
Unfortunately I cannot do this with lambda function. I keep trying.

In Python, why can a lambda expression refer to the variable being defined but not a list?

This is more a curiosity than anything, but I just noticed the following. If I am defining a self-referential lambda, I can do it easily:
>>> f = lambda: f
>>> f() is f
True
But if I am defining a self-referential list, I have to do it in more than one statement:
>>> a = [a]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> a = []
>>> a.append(a)
>>> a[0] is a
True
>>> a
[[...]]
I also noticed that this is not limited to lists but seems like any other expression other than a lambda can not reference the variable left of the assignment. For example, if you have a cyclic linked-list with one node, you can't simply go:
>>> class Node(object):
... def __init__(self, next_node):
... self.next = next_node
...
>>> n = Node(n)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
Instead, you have to do it in two statements:
>>> n = Node(None)
>>> n.next = n
>>> n is n.next
True
Does anyone know what the philosophy behind this difference is? I understand that a recursive lambda are used much more frequently, and hence supporting self-reference is important for lambdas, but why not allow it for any assignment?
EDIT: The answers below clarify this quite nicely. The reason is that variables in lambdas in Python are evaluated each time the lambda is called, not when it's defined. In this sense they are exactly like functions defined using def. I wrote the following bit of code to experiment with how this works, both with lambdas and def functions in case it might help clarify it for anyone.
>>> f = lambda: f
>>> f() is f
True
>>> g = f
>>> f = "something else"
>>> g()
'something else'
>>> f = "hello"
>>> g()
'hello'
>>> f = g
>>> g() is f
True
>>> def f():
... print(f)
...
>>> f()
<function f at 0x10d125560>
>>> g = f
>>> g()
<function f at 0x10d125560>
>>> f = "test"
>>> g()
test
>>> f = "something else"
>>> g()
something else
The expression inside a lambda is evaluated when the function is called, not when it is defined.
In other words, Python will not evaluate the f inside your lambda until you call it. And, by then, f is already defined in the current scope (it is the lambda itself). Hence, no NameError is raised.
Note that this is not the case for a line like this:
a = [a]
When Python interprets this type of line (known as an assignment statement), it will evaluate the expression on the right of the = immediately. Moreover, a NameError will be raised for any name used on the right that is undefined in the current scope.
Because a lambda is a function, and the function body is not executed until the function is called.
In other words, the other way to do it is this:
def f():
return f
But you're correct that you can't do it in an expression because def is a statement, so it can't be used in an expression.
We can see when we disassemble the lambda function (this is identical output in Python 2.6 and 3.3)
>>> import dis
>>> f = lambda: f
>>> dis.dis(f)
1 0 LOAD_GLOBAL 0 (f)
3 RETURN_VALUE
We demonstrate that we do not need to load f until it is called, whereupon it is already defined globally, and therefore stored, so this works:
>>> f is f()
True
But when we do:
>>> a = [a]
We have an error (if a is previously undefined), and if we disassemble Python's implementation of this.
>>> def foo():
... a = [a]
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (a)
3 BUILD_LIST 1
6 STORE_FAST 0 (a)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
we see that we attempt to load a before we have stored it.
There's no special-casing required to make this happen; it's just how it works.
A lambda expression is not any different from a normal function, really. Meaning, I can do this:
x = 1
def f():
print x + 2
f()
3
x = 2
f()
4
As you can see, inside the function, the value of x does not have a predefined value - it's looked up when we actually run f. This includes the value of the function itself: We don't look up what f represents until we actually run it, and by then it exists.
Doing that as a lambda doesn't work any differently:
del x
f = lambda: x+2
f()
NameError: global name 'x' is not defined
x = 2
f()
4
works similarly. In this case, I went ahead and deleted x so it was no longer in the scope when f was defined, and running f in this case correctly shows that x doesn't exist. But after we define x, then f works again.
This is different in the list case, because we are actually generating an object right now, and so everything on the right side has to be bound, right now. The way python works (as i understand it, and at least in practice this has been useful) is to consider that everything on the right side is deferenced & bound and then processed, and only after that's all complete are the value(s) on the left side bound and assigned.
Since the same value is on the right side and the left, when python tries to bind the name on the right side, it doesn't exist yet.

What's the difference between locals() and globals()

I don't understand what's wrong with in this code.
Please let me know how I write to solve this problem.
I'd thought that this might had been good, but it caused the error.
>>> def L():
... for i in range(3):
... locals()["str" + str(i)] = 1
... print str0
...
>>> L()
If I execute it, the following error happened.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in a
NameError: global name 'str0' is not defined
However, if I use globals(), the error didn't happen(like the following)
>>> def G():
... for i in range(3):
... globals()["str" + str(i)] = 1
... print str0
...
>>> G()
1
But!!! If I don't use for statement, I can write like this and works well.
>>> def LL():
... locals()["str" + str(0)] = 1
... print str0
...
>>> LL()
1
I want to get the result by using variables set in the method after the above code was executed.
>>> str0
1
>>> str1
1
>>> str2
1
From the documentation of locals()
Note:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

Can we access inner function outside its scope of outer function in python using outer function?

Just for the sake of curiosity I wanna know this..
I know scope of inner function is limited to outer function body only, but still is there any way so that we can access the inner function variable outside its scope or call the inner function outside its scope ?
In [7]: def main():
...: def sub():
...: a=5
...: print a
...:
In [8]: main()
In [9]: main.sub()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/dubizzle/webapps/django/dubizzle/<ipython-input-9-3920726955bd> in <module>()
----> 1 main.sub()
AttributeError: 'function' object has no attribute 'sub'
In [10]:
>>> def main():
... def sub():
... a=5
... print a
...
>>> main.__code__.co_consts
(None, <code object sub at 0x2111ad0, file "<stdin>", line 2>)
>>> exec main.__code__.co_consts[1]
5
You can if you return the inner function as a value
>>> def main():
... def sub():
... a = 5
... print a
... return sub
...
>>> inner = main()
>>> inner()
5
or you can attach it to main as a property (functions are objects after all):
>>> def main():
... def sub():
... a = 5
... print a
... main.mysub = sub
...
>>> main()
>>> main.mysub()
5
but you better document your very good reason for doing this, since it will almost certainly surprise anyone reading your code :-)
No, you can't. The inner function is not an attribute of the outer function.
The inner function only exists after its def statement is executed (while the outer function is executed), and it stops to exist when the function exits.
You could return the inner function, of course.
A function is just another object in Python and can be introspected.
You can get the outer function body at runtime and parse/eval it to make the function available in the current namespace.
>>> import inspect
>>> def outer():
def inner():
print "hello!"
>>> inspect.getsourcelines(outer)
([u'def outer():\n', u' def inner():\n', u' print "hello!"\n'], 1)
Not really the same thing as calling outer.inner(), but if you are not making the inner function explicitly available outside the scope of the outer function, I guess it is the the only possibility.
For example, a very naive eval attempt could be:
>>> exec('\n'.join([ line[4:] for line in inspect.getsourcelines(outer)[0][1:] ]))
>>> inner()
hello!
An inner function is just a local variable like any other so the same rules apply. If you want to access it you have to return it.

Need to add an element at the start of an iterator in python

I have a program as follows:
a=reader.next()
if *some condition holds*:
#Do some processing and continue the iteration
else:
#Append the variable a back to the iterator
#That is nullify the operation *a=reader.next()*
How do I add an element to the start of the iterator?
(Or is there an easier way to do this?)
EDIT: OK let me put it this way. I need the next element in an iterator without removing it.
How do I do this>?
You're looking for itertools.chain:
import itertools
values = iter([1,2,3]) # the iterator
value = 0 # the value to prepend to the iterator
together = itertools.chain([value], values) # there it is
list(together)
# -> [0, 1, 2, 3]
Python iterators, as such, have very limited functionality -- no "appending" or anything like that. You'll need to wrap the generic iterator in a wrapper adding that functionality. E.g.:
class Wrapper(object):
def __init__(self, it):
self.it = it
self.pushedback = []
def __iter__(self):
return self
def next(self):
if self.pushedback:
return self.pushedback.pop()
else:
return self.it.next()
def pushback(self, val):
self.pushedback.append(val)
This is Python 2.5 (should work in 2.6 too) -- slight variants advised for 2.6 and mandatory for 3.any (use next(self.it) instead of self.it.next() and define __next__ instead of next).
Edit: the OP now says what they need is "peek ahead without consuming". Wrapping is still the best option, but an alternative is:
import itertools
...
o, peek = itertools.tee(o)
if isneat(peek.next()): ...
this doesn't advance o (remember to advance it if and when you decide you DO want to;-).
By design (in general development concepts) iterators are intended to be read-only, and any attempt to change them would break.
Alternatively, you could read the iterator backwards, and add it to the end of hte element (which is actually the start :) )?
This isn't too close what you asked for, but if you have control over the generator and you don't need to "peek" before the value is generated (and any side effects have occurred), you can use the generator.send method to tell the generator to repeat the last value it yielded:
>>> def a():
... for x in (1,2,3):
... rcvd = yield x
... if rcvd is not None:
... yield x
...
>>> gen = a()
>>> gen.send("just checking")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> gen.next()
1
>>> gen.send("just checking")
1
>>> gen.next()
2
>>> gen.next()
3
>>> gen.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Categories

Resources