Function object in Python - python

I want to create a list of functions consisting of function objects created by a fixed base function but with different input parameters. I have written such code:
def f_base(name):
print "I am %s" % name
f_list = []
for name in ['A', 'B']:
f_list.append(
lambda : f_base(name)
)
f_list[0]()
f_list[1]()
The result is:
I am B
I am B
But I want to get:
I am A
I am B
Can someone explain why Python produces such output and what is the easiest way to get the result I need?

All you're doing with the lambda functions now is calling f_base on the variable name in the body. The name variable is determined at the time you call those lambda functions and not at the time you create each function.
The variable name refers to 'B' after you finish looping since python keeps variables defined in for loops around after the loop is done.
This is particularly obvious if you do,
name = 'C'
after the loop and before calling the functions. Then you get,
I am C
I am C
To do what you want you need to create a closure function or, probably better, use functools.partial.
import functools
def f_base(name):
print "I am %s" % name
f_list = []
for name in ['A', 'B']:
f_list.append(
functools.partial(f_base, name)
)
f_list[0]()
f_list[1]()
Which produces,
I am A
I am B

You can create closure:
def f_base(name):
def closure():
print "I am %s" % name
return closure
f_list = []
for name in ['A', 'B']:
f_list.append( f_base(name) )

Related

Why do I have to 'return' a function? [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Python difference between mutating and re-assigning a list ( _list = and _list[:] = )
(3 answers)
Closed 6 months ago.
I created a function and I want to append a number to the list:
def num(f):
list1.append(i)
return list1
list1 = []
i = 1
print "Now list1 is %s and i is %d" % (list1, i)
num(list1)
i += 1
print "Now list1 is %s and i is %d" % (list1, i)
num(list1)
i += 1
print "Now list1 is %s and i is %d" % (list1, i)
print list1
print i
Why do I have to return a function? It works with and without the return.
I was told that the function returns None if no return-statement was reached. But the function, mentioned above, works even if I don't type this return-statement.
I see you don't understand how functions work, so I added comments to your code to explain a little, but I suggest you to read Python tutorial about functions and wiki article further to gain understanding.
Also, I omitted many details not to overload the explanation. Important thing is there're immutable (i.e. integer, i in your example) and mutable (i.e. list, list1 in your example) types in Python and depending on this the behavior will be different.
def num(f):
#Here the argument you pass to the function is named 'f'
#and you don't use it
#The next line uses 'list1', that is defined in global scope
#since you didn't redefined this name inside the function
#Variable 'i' is also the one in global scope for same reasons
list1.append(i)
#Here you return 'list1', though you don't use this value
#further in your program. Indeed, you would not write a return
#statement the function would return 'None' as the return value
return list1
#Here you define 'list1' in global scope, and it will be used
#inside 'num' function, even without providing it as the argument
list1 = []
#Here you define 'i' in global scope, and it will be used
#inside 'num' function
i = 1
#Here you print 'i' and 'list' from global scope
print "Now list1 is %s and i is %d" % (list1, i)
#Here you call 'num' function and 'list1' provided as argument
#is assigned to 'f' inside the function, but you didn't used it and
#and instead used names from global scope - that's why it works in
#this way (however it is wrong use of function)
#With 'list1.append(i)' the 'list1' is modified in place so it
#doesn't matter if it is returned or not
num(list1)
#As to 'num' return value, it will be the same value as 'list1', but
#you don't use it here, to use it it needs to be assigned with '=' to
#some variable, i.e. 'list2=num(list1)', though in fact 'list1' and 'list2'
#will be the same all the time due to Python internals, but let's skip the
#details of this.
#You can see that the value returned is not 'None' - add the
#following line here:
print(num(list1))
#and run your program, the output will show you that it's a list returned.
#then remove the 'return' line in your function and run program again
#the output here will show, that is's 'None' that was returned.
So to fix the obvious mistake in the function:
def num(f):
f.append(i)
return f
but i is still used from global scope and not passed as argument, so even better:
def num(f_var,i_var):
f_var.append(i_var)
return f_var
Though the list will be modified inplace and you don't really have to return it
in you particular example, so:
def num(f_var,i_var):
f_var.append(i_var)
list1=[]
i=1
num(list1,i)
will work too.
In the provided example, returning a value is unnecessary because the append list method, and by extension your function as well, operates by side effect. Functions called only for side effects are not functions in the mathematical sense (mappings of domain values to codomain values), they serve to change state of mutable objects, in this case by appending an item to a list. While such functions can return a value, Python has a convention that functions invoked purely for side effect, such as list.append, only return None, denoting no useful return value.
If your function were side-effect-free, you would need to have a return statement for it to be useful at all. As an example, compare:
def add(a, b):
return a + b
...with the syntactically just as legal, but pretty useless:
def add(a, b):
a + b
# without a return statement, None is returned,
# and the calculated sum discarded
You don't use the return value, so it makes no difference, what you return. You also don't use the argument. You probably wanted to write
def append_num(f, i):
f.append(i)
and use two arguments:
append_num(list1, i)

How to use a variable as function name in Python

Would it be possible to use a variable as a function name in python?
For example:
list = [one, two, three]
for item in list:
def item():
some_stuff()
The trick is to use globals():
globals()['use_variable_as_function_name']()
will be equivalent to
use_variable_as_function_name()
found at: George Sakkis https://bytes.com/topic/python/answers/792283-calling-variable-function-name
The following is a useful application of the above questioning I needed right now (that's why I came here): apply special functions to URLs depending on their nature:
l = ['condition1', 'condition2', 'condition3']
I used to write
if 'condition1.' in href:
return do_something_condition1()
if 'condition2.' in href:
return do_something_condition2()
if 'condition3.' in href:
return do_something_condition3()
and so on - my list has 19 members by now and keeps growing.
While investigating the subject and developing, the function code had been quite naturally part of the main function making it soon horrible to read, so relocating the working code into functions was a great relief already.
This clumsy code above can be substituted by:
for e in l: # this is my condition list
if e + '.' in href: # this is the mechanism to choose the right function
return globals()['do_something_' + e]()
This way the main code stays simple and legible no matter how long the list of conditions may grow.
Those functions corresponding to the condition labels have to be declared conventionally, of course, depending on the nature of the type of the URL in question:
def do_something_condition1(href):
# special code 1
print('========1=======' + href)
def do_something_condition2(href):
# special code 2
print('========2=======' + href)
def do_something_condition3(href):
# special code 3
print('========3=======' + href)
Test:
>>> href = 'https://google.com'
>>> for e in l:
... globals()['do_something_' + e](href)
...
========1=======https://google.com
========2=======https://google.com
========3=======https://google.com
Or, to model it closer to the above scenario:
success = '________processed successfully___________ '
def do_something_google(href):
# special code 1
print('========we do google-specific stuff=======')
return success + href
def do_something_bing(href):
# special code 2
print('========we do bing-specific stuff=======')
return success + href
def do_something_wikipedia(href):
# special code 3
print('========we do wikipedia-specific stuff=======')
return success + href
Test:
l = ['google', 'bing', 'wikipedia']
href = 'https://google.com'
def test(href):
for e in l:
if e + '.' in href:
return globals()['do_something_' + e](href)
>>> test(href)
========we do google-specific stuff=======
'________processed successfully___________ https://google.com'
Result:
Further elaboration on the problem now just amounts to augment the condition list one by one and write the corresponding functions depending on the argument. The above mechanism will pick the right one thereafter.
You can't define a function using a variable but you can rebind the function to the variable name. Here is an example to add them to the module's global namespace.
one = 'one'
two = 'two'
three = 'three'
l = [one, two, three]
def some_stuff():
print("i am sure some stuff")
for item in l:
def _f():
some_stuff()
globals()[item] = _f
del _f
one()
two()
three()
Functions in Python are objects that have a name referencing them, so you can pass them around, store in lists and dictionaries (common use when creating jump-tables).
I.e. this works:
def one():
print "1"
def two():
print "2"
def three():
print "3"
l = [one, two, three]
for item in l:
item()
Will print:
1
2
3
Don't use list as variable name, because this way you redefine buildin.
def is the statement that is also executed, unlike function defenitions in compiled languages. So when you call def item(): you don't define function for one, two, three, but redefine item name.
In general it is not quite clear what you're trying to do, but it doesn't look like a good idea. May be explain what you try to accomplish, or rethink the way you want to do it.
Here is a workaround wrapped in a class. It uses a dictionary for the mapping:
class function_class:
def __init__(self,fCase):
fDic = {'A':self.A, # mapping: string --> variable = function name
'B':self.B,
'C':self.C}
self.fActive = fDic[fCase]
def A(self): print('here runs function A')
def B(self): print('here runs function B')
def C(self): print('here runs function C')
def run_function(self):
self.fActive()
#---- main ----------
fList = ['A','B','C'] # list with the function names as strings
for f in fList: # run through the list
g = function_class(f)
g.run_function()
The output is:
here runs function A
here runs function B
here runs function C
You can do this:
from types import FunctionType
from copy import copy
def copy_function(fn):
return FunctionType(copy(fn.func_code), copy(fn.func_globals), name=item,
argdefs=copy(fn.func_defaults),
closure=copy(fn.func_closure))
list = ['one', 'two', 'three']
for item in list:
def _fn():
print(item)
globals()[item] = copy_function(_fn)
list = map(eval, list)
The short answer is no. When you declare a variable, you have bound a name to an object. The same is true when you declare a function. You can try it out for yourself in a python console and see what happens:
>name=1
>name
1
>def name(x): print(x+1)
>name
function name at 0x000001CE8B8122F0
Here is an updated answer from #enrico.basis:
from types import FunctionType
from copy import copy
def copy_function(fn):
return FunctionType(
code=copy(fn.__code__),
globals=copy(fn.__globals__),
name=fn.__name__,
argdefs=copy(fn.__defaults__),
closure=copy(fn.__closure__)
)
items = ['print_one', 'print_two', 'print_three']
for ele in items:
def _f():
return 'String from {}() function'.format(ele)
_f.__name__ = ele
locals()[ele] = copy_function(_f)
del _f
for ele in items:
_f = eval(ele)
print('- {}'.format(_f()))
This will give the following output:
- String from print_one() function
- String from print_two() function
- String from print_three() function

Python functions within lists

So today in computer science I asked about using a function as a variable. For example, I can create a function, such as returnMe(i) and make an array that will be used to call it. Like h = [help,returnMe] and then I can say h1 and it would call returnMe("Bob"). Sorry I was a little excited about this. My question is is there a way of calling like h.append(def function) and define a function that only exists in the array?
EDIT:
Here Is some code that I wrote with this!
So I just finished an awesome FizzBuzz with this solution thank you so much again! Here's that code as an example:
funct = []
s = ""
def newFunct(str, num):
return (lambda x: str if(x%num==0) else "")
funct.append(newFunct("Fizz",3))
funct.append(newFunct("Buzz",5))
for x in range(1,101):
for oper in funct:
s += oper(x)
s += ":"+str(x)+"\n"
print s
You can create anonymous functions using the lambda keyword.
def func(x,keyword='bar'):
return (x,keyword)
is roughly equivalent to:
func = lambda x,keyword='bar':(x,keyword)
So, if you want to create a list with functions in it:
my_list = [lambda x:x**2,lambda x:x**3]
print my_list[0](2) #4
print my_list[1](2) #8
Not really in Python. As mgilson shows, you can do this with trivial functions, but they can only contain expressions, not statements, so are very limited (you can't assign to a variable, for example).
This is of course supported in other languages: in Javascript, for example, creating substantial anonymous functions and passing them around is a very idiomatic thing to do.
You can create the functions in the original scope, assign them to the array and then delete them from their original scope. Thus, you can indeed call them from the array but not as a local variable. I am not sure if this meets your requirements.
#! /usr/bin/python3.2
def a (x): print (x * 2)
def b (x): print (x ** 2)
l = [a, b]
del a
del b
l [0] (3) #works
l [1] (3) #works
a (3) #fails epicly
You can create a list of lambda functions to increment by every number from 0 to 9 like so:
increment = [(lambda arg: (lambda x: arg + x))(i) for i in range(10)]
increment[0](1) #returns 1
increment[9](10) #returns 19
Side Note:
I think it's also important to note that this (function pointers not lambdas) is somewhat like how python holds methods in most classes, except instead of a list, it's a dictionary with function names pointing to the functions. In many but not all cases instance.func(args) is equivalent to instance.__dict__['func'](args) or type(class).__dict__['func'](args)

Aliased name of a Function in Python

I want to find the name of the function as it was called ... i.e. the name of the variable that called the function. Using the basic recipes i.e. with __name__, func_name, or inspecting the basic stack does not work for me. For example
def somefunc():
print "My name is: %s" % inspect.stack()[1][3]
a = somefunc
a()
# would output: out: "My name is: somefunc"
# whereas I want it to output: "My name is: a"
My gut says I can do this, but I can't figure it out. Any python guru's out there?
It's probably impossible to do this 100% correctly, but you could give the following a try:
import inspect
import parser
# this flatten function is by mike c fletcher
def flatten(l, ltypes=(list, tuple)):
ltype = type(l)
l = list(l)
i = 0
while i < len(l):
while isinstance(l[i], ltypes):
if not l[i]:
l.pop(i)
i -= 1
break
else:
l[i:i + 1] = l[i]
i += 1
return ltype(l)
# function we're interested in
def a():
current_func = eval(inspect.stack()[0][3])
last_frame = inspect.stack()[1]
calling_code = last_frame[4][0]
syntax_tree = parser.expr(calling_code)
syntax_tree_tuple = parser.st2tuple(syntax_tree)
flat_syntax_tree_tuple = flatten(syntax_tree_tuple)
list_of_strings = filter(lambda s: type(s)==str,flat_syntax_tree_tuple)
list_of_valid_strings = []
for string in list_of_strings:
try:
st = parser.expr(string)
list_of_valid_strings.append(string)
except:
pass
list_of_candidates = filter(lambda s: eval(s)==current_func, list_of_valid_strings)
print list_of_candidates
# other function
def c():
pass
a()
b=a
a(),b(),c()
a(),c()
c(),b()
This will print:
['a']
['a', 'b']
['a', 'b']
['a']
['b']
It's pretty ugly and complicated, but might work for what you need. It works by finding all variables used in the line that called this function and comparing them to the current function.
The problem here is indirection. You could probably do something complicated like inspect the stack, get the code for the module that called the function, parse the line number from the stack to find the label used to call the function in the local context, and then use that, but that won't necessarily give you what you want anyway. Consider:
def func(x):
print get_label_function_called_with()
def func_wrapper(func_in_func_wrapper):
return func_in_func_wrapper
func_label = func
func_from_func_wrapper = func_wrapper(func_label)
func_from_func_wrapper()
Should this print func, func_in_func_wrapper, func_label, or func_from_func_wrapper? It might seem like an obvious answer at first, but given that you never really know what sort of indirection is going on inside code you are calling, you really can't know for sure.

Python 2.7 using the input to a function as a string and variable

I would like to do the following:
print "CC =",CC
but as a function so that i only have to write the variable CC once. I can't work out how to do this in a function as it always evaluates CC as a floating point number (which it is).... Is there a way to accept the input to a function as both a string and floating point number?
I tried this:
def printme(a):
b='%s' % a
print b
return b
but of course it only prints the value of a, not its name.
You could use the inspect module (see also this SO question):
def printme(x):
import inspect
f = inspect.currentframe()
val = f.f_back.f_locals[x]
print x, '=', val
CC = 234.234
printme('CC') # <- write variable name only once
# prints: CC = 234.234
Perhaps a dictionary is a better approach to the problem. Assuming you have several name-value pairs that you want to use, you can put them in a dict:
params = {"CC": 1.2345, "ID": "Yo!", "foo": "bar"}
Then, for example, you could print all the names and values nicely formatted like this:
for key in params:
print "{0} = {1}".format(key, params[key])
But since it is still unclear why you are trying to do this, it's hard to tell whether this is the right way.
I think this is your required solution:
def printme(x):
keys_list = [key for key, value in globals().iteritems() if value == x]
print keys_list
for key in keys_list:
if id(globals()[key]) == id(x):
result = "%s = %s" %(key, x)
print result
break
return result
for example if you declare a variable:
>>> c=55.6
then result of printme(c) will be
>>> 'c = 55.6'
Note: This solution is based on globally unique id matching.
Not exactly what you want, but easy to do:
def printme(**kwargs):
for key, value in kwargs.items():
print '%s=%s' % (key, value)
return value
In [13]: printme(CC=1.23, DD=2.22)
CC=1.23
DD=2.22
Out[13]: 1.23
If I understand you correctly you want something like this?
def f(a):
print('{0}: = {1}'.format(locals().keys()[0], a))
Update:
I am aware that the example doesn't make a lot of sense, as it's basically the same as:
def f(a):
print('a: {0}'.format(a))
I merely wanted to point the OP to locals() as I didn't quite understand what he's trying to accomplish.
I guess this is more what he's looking for:
def f(**kwargs):
for k in kwargs.keys():
print('{0}: {1}'.format(k, kwargs[k]))
f(a=1, b=2)
If I understand you correctly you want a shorthand for printing a variable name and its value in the current scope? This is in general impossible without using the interpreters trace function or sys._getframe, which should in general only be used if you know what you're doing. The reason for this is that the print function has no other way of getting the locals from the calling scope:
def a():
x = 1
magic_print("x") #will not work without accessing the current frame
What you CAN do without these is explicitly pass the locals to a function like this:
def printNameAndValue(varname, values):
print("%s=%s" % (varname, values[varname]))
def a():
x = 1
printNameAndValue("x", locals()) #prints 'x=1'
EDIT:
See the answer by catchemifyoutry for a solution using the inspect module (which internally uses sys._getframe). For completeness a solution using the trace function directly - useful if you're using python 2.0 and inspect isn't available ;)
from sys import settrace
__v = {} #global dictionary that holds the variables
def __trace(frame, event, arg):
""" a trace function saving the locals on every function call """
global __v
if not event == "call":
return __trace
__v.update(frame.f_back.f_locals)
def enableTrace(f):
""" a wrapper decorator setting and removing the trace """
def _f(*a, **kwa):
settrace(__trace)
try:
f(*a, **kwa)
finally:
settrace(None)
return _f
def printv(vname):
""" the function doing the printing """
global __v
print "%s=%s" % (vname, __v[vname])
Save it in a module and use like this:
from modulenamehere import enableTrace, printv
#enableTrace
def somefunction():
x = 1
[...]
printv("x")
used a global variable to achieve this,func.__globals__.keys() contains all the variables passed to func, so I filtered out the name startin with __ and stored them in a list.
with every call to func() the func.__globals__.keys() gets updated with the new variable name,so compare the new varn with the older glo results in the new variable that was just added.
glo=[]
def func(x):
global glo
varn=[x for x in func.__globals__.keys() if not x.startswith('__') and x!=func.__name__]
new=list(set(varn)^set(glo))
print("{0}={1}".format(new[0],x))
glo=varn[:]
output:
>>> a=10
>>> func(a)
a=10
>>> b=20
>>> func(20)
b=20
>>> foo='cat'
>>> func(foo)
foo=cat
>>> bar=1000
>>> func(bar)
bar=1000

Categories