Python: Do string substitution with variables at function definition time [duplicate] - python

This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 5 years ago.
I have a situation like the following:
functions = []
some_list = [('a', 'b'), ('c', 'd')]
for x, y in some_list:
def foo(z):
# do some things
return "{} {} {}".format(x, y, z)
functions.append(foo)
But obviously this doesn't work, as x and y will always have the last values they had in the loop, i.e. 'c' and 'd', i.e. both functions in the functions list will return '{} c d'.format(z) in practice.
How do I make it so that it does the string substitution immediately, so that on the first loop it defines foo(z) as the equivalent to
def foo(z):
# do some things
return "{} a b".format(z)
without any reference to the variables x and y?
EDIT: I now realize I also need to store a copy of foo in functions, not foo itself, but the rest of the question stll stands.

You could bind the loop values to local variables at function definition time:
for x, y in some_list:
def foo(z, a=x, b=y):
return "{} {} {}".format(a, b, z)
functions.append(foo)
functions[0]('foo')
'a b foo'
functions[1]('foo')
'c d foo'

Related

How in the world is this a list if it uses ()? [duplicate]

This question already has answers here:
How to create a "singleton" tuple with only one element
(4 answers)
Closed 1 year ago.
So in python I have this tuple, or at least it SHOULD be a tuple:
listOfNames = ([(name, 'male') for name in names.words('male.txt')] + [(name, 'female') for name in names.words('female.txt')])
Yet when I run type(listOfNames), it returns "list". But why? There are clearly parentheses on the outside. Is this some new convention I am not aware of?
A single () with no separators passes through whatever is inside it
>>> "something"
'something'
>>> ("something")
'something'
>>> ("something",)
('something',)
To make a tuple, you need a trailing comma or to explicitly cast to a tuple tuple()
(x) # just x
(x,) # tuple containing x
If you want to create a tuple directly, you can skip creating the intermediate list, and form a generator expression
You actually already do this when forming the list in your question, but it may come with a different name
[x for x in my_iterable if some_condition(x)] # list comprehension
(x for x in my_iterable if some_condition(x)) # generator expression
tuple(x for x in my_iterable if some_condition(x)) # tuple from generator

apply a function over each element of an iterable with sublists [duplicate]

This question already has answers here:
Apply a function to every item of an arbitrarily nested list
(2 answers)
Closed 2 years ago.
I'm trying to apply a function to every element of a list containing arbitrary sub-levels of sublists. Like so.
a = [1,2,3]
b = [[1,2,3],[4,5,6]]
c = [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]
function = lambda x: x+1
def apply(iterable,f):
# do stuff here
print(apply(a,function)) # [2,3,4]
print(apply(b,function)) # [[2,3,4],[5,6,7]]
print(apply(c,function)) # [[[2,3,4],[5,6,7]],[[8,9,10],[11,12,13]]]
basically i can't find a way to write the apply function. I tried with numpy, but that's not the solution, of course, because the contents of the list could also be strings, objects ...
Sounds like recursion should be able to solve that:
a = [1,2,3]
b = [[1,2,3], [4,5,6]]
c = [[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]]]
f = lambda x : x+1
def apply(iterable, f):
# suggestion by Jérôme:
# from collections.abc import Iterable and use
# isinstance(iterable, collections.abc.Iterable) so it works for tuples etc.
if isinstance(iterable, list):
# apply function to each element
return [apply(w, f) for w in iterable]
else:
return f(iterable)
print(apply(a, f)) # [2,3,4]
print(apply(b, f)) # [[2,3,4],[5,6,7]]
print(apply(c, f)) # [[[2,3,4],[5,6,7]],[[8,9,10],[11,12,13]]]
Here is one way to do it. Note that strings are also iterable so depending on your use case you might need to add more checking.
def apply(iterable, f):
try:
iterator = iter(iterable)
for i in iterator:
apply(i, f)
except Exception as e:
f(iterable)
c = [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]
apply(c, print)
If all your nested lists are the same shape you should be able to do this with numpy:
import numpy as np
ary = np.array([['a', 'b'], ['c', 'd'], ['e', 'f']])
res = np.vectorize(lambda c: c + ':)')(ary)
print(res)
# [['a:)' 'b:)']
# ['c:)' 'd:)']
# ['e:)' 'f:)']]
Give this recursion a shot:
def apply(it, func):
try:
return [apply(e) for e in it]
except TypeError:
return func(it)
Note that this will iterate over any iterable unless you specify otherwise, for example you can check in the beginning if it is a dict and just apply it the func on it.. add
if isinstance(it,dict):
func(it)

Testing an index in a for loop - Python [duplicate]

This question already has answers here:
How can I iterate over overlapping (current, next) pairs of values from a list?
(12 answers)
Closed 8 years ago.
Very simple problem, although I am having quite a tough time solving it.
Take a look at the code and I will explain below:
def printc(some_text):
split_text = list(some_text)
for x in split_text:
if x is '{'
# this is what i need help with
printc("{CCyan, {RRed, {YYello)
The idea behind this and it is still very early in the code development, but what I am trying to do is create an iterator that searches through "split_text" and finds the character '{' then i want to test what character is situated right next to it. How would i go about doing that?
For example is searches through split_text and finds the first { i want to see if the character next to it is either A, B, C, etc...
Any ideas?
Much easier with a single regex.
import re
re.findall('{(.)', some_text)
outputs:
['C', 'R', 'Y']
for x, y in zip(some_text, some_text[1:]):
if x == '{':
print y
you could even make it simpler:
chars = [y for (x, y) in zip(some_text, some_text[1:]) if x == '{']
I usually iterate in pairs if I need something like this:
from itertools import tee, izip
def pairwise(iterable):
"""Iterate in pairs
>>> list(pairwise([0, 1, 2, 3]))
[(0, 1), (1, 2), (2, 3)]
>>> tuple(pairwise([])) == tuple(pairwise('x')) == ()
True
"""
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Usage is like:
for left, right in pairwise(iterable):
...

What does 'x, y =' mean in python syntax? [duplicate]

This question already has answers here:
How are tuples unpacked in for loops?
(8 answers)
Closed 9 years ago.
I'm new to python and trying to work my way through http://yuji.wordpress.com/2011/06/22/python-imaplib-imap-example-with-gmail/ which has the following line:
result, data = mail.uid('search', None, "ALL") # search and return uids instead
Could someone explain this line?
Thank you.
It means that the function you have called returns an iterable, and the index 0 of the iterable is assigned to x and the index 1 is assigned to y. This is called tuple unpacking.
Eg)
>>> def func(a,b):
... return b,a
...
>>> a = 5
>>> b = 7
>>> a,b = func(a,b)
>>> a
7
>>> b
5
>>> x = func(a,b)
>>> x
(5, 7)
Edit to show that returning multiple values, they are packed as tuple by default and then unpacked at the other end. Since there is only one variable x here, the tuple is assigned to x.
Simple function for swapping two variables(Just for an example) that answers your question
At least, as of python 2.7.x, the function will unpack a tuple of 2 arguments returned from a function. If it returns anything other than 2 arguments in the tuple, I believe it will throw an error if you try to unpack more than this. If it returns 3 arguments and you unpack 2, for example, you will get an exception.
For example:
def func(a):
return (a,a+1,a*2)
a,b,c = func(7)
print a,b
==> 7 8 # NOTE Values
a = func(3)
print a
==> (3, 4, 6) # NOTE: TUPLE
a,b = func(9)
print a,b
==> Exception - ValueError: too many values to unpack
This may be different in 3.0+.
The other answer, that "the function you have called returns an iterable" is a good one. That is what is happening in your specific example. This is what is called "unpacking" in python. The following are examples of unpacking and assignment related to your question:
>>> a,b = 1,2
>>> a
1
>>> b
2
>>> a,b,c = ['do', 're', 'mi']
>>> a
'do'
>>> b
're'
>>> c
'mi'
>>>
This is one of the pretty features of Python syntax. If I am not mistaken, it is also optimized - i.e. the fastest way to achieve the result.

Getting list of parameter names inside python function [duplicate]

This question already has answers here:
How to get method parameter names?
(20 answers)
Closed last month.
Is there an easy way to be inside a python function and get a list of the parameter names?
For example:
def func(a,b,c):
print magic_that_does_what_I_want()
>>> func()
['a','b','c']
Thanks
Well we don't actually need inspect here.
>>> func = lambda x, y: (x, y)
>>>
>>> func.__code__.co_argcount
2
>>> func.__code__.co_varnames
('x', 'y')
>>>
>>> def func2(x,y=3):
... print(func2.__code__.co_varnames)
... pass # Other things
...
>>> func2(3,3)
('x', 'y')
>>>
>>> func2.__defaults__
(3,)
For Python 2.5 and older, use func_code instead of __code__, and func_defaults instead of __defaults__.
locals() returns a dictionary with local names:
def func(a, b, c):
print(locals().keys())
prints the list of parameters. If you use other local variables those will be included in this list. But you could make a copy at the beginning of your function.
If you also want the values you can use the inspect module
import inspect
def func(a, b, c):
frame = inspect.currentframe()
args, _, _, values = inspect.getargvalues(frame)
print 'function name "%s"' % inspect.getframeinfo(frame)[2]
for i in args:
print " %s = %s" % (i, values[i])
return [(i, values[i]) for i in args]
>>> func(1, 2, 3)
function name "func"
a = 1
b = 2
c = 3
[('a', 1), ('b', 2), ('c', 3)]
import inspect
def func(a,b,c=5):
pass
inspect.getargspec(func) # inspect.signature(func) in Python 3
(['a', 'b', 'c'], None, None, (5,))

Categories

Resources