I am trying to define a function in Python. It should look like this:
def myfunction(Peter_1, Amy_1, Peter_2, Amy_2, Peter_3, Amy_3,....Peter_50,Amy_50):
Peter_1 = 100
Amy_1 = 20
Peter_2 = 90
Amy_2 = 4
...
...
I am using a small software writing in Python to do optimazation. The software is like that, after I define myfunction , I should write,
parameter1 = Parameter("Peter_1", (90,100),1)
parameter2 = Parameter("Amy_1", (15,25),1)
...
...
parameter99 = Parameter("Peter_50", (70,100),1)
parameter100 = Parameter("Amy_50", (15,25),1)
Parameter is the software defined function, the first argument of Parameter should be a string, and it has to be exactly the name I defined in myfunction. Then the software knows that the first parameter which need to be optimazed is Peter_1.
I donot want to type all the 100 parameters, can anyone help me?
This is a bad code smell. You should wrap the arguments in an object. For example a dictionary.
Something like this:
def myfunction(people):
for person_name in people.iterkeys():
people[person_name] = 100
my_people = {}
my_people['Peter'] = 0
my_people['Simon'] = 0
myfunction(my_people)
print my_people
But my real concern is that you initialize the value in the function. Why not beforehand?
my_people = {}
my_people['Peter'] = 100
my_people['Simon'] = 90
That way you don't need the function.
you can even use python *args syntax. For example something like this:
def foo(*args):
for i in args:
print(i)
foo(1,2)
foo(1,2,3,4,5,6,7,8)
#output:
1
2
#second run:
1
2
3
4
5
6
7
8
Well, RvdK's answer works, but if you MUST write it the way you indicated in your question, then you should consider using the exec() function. That way you can write a small code inside your script that writes this function as a string for you. Then with exec() you can actually use the resulting string as an active part of the code.
Although, I would recommend that you use lists or tuples if that is a possibility.
Related
Is there a way to do this in Python, so that:
pr(foo) # => foo is 123
pr(fn()) # => fn() is True
pr(obj.getVal()) # => obj.getVal() is 3.14
pr(obj.a().b.c) # => obj.a().b.c is "hello"
pr(1 + calc() / 2) # => 1 + calc() / 2 is 56
that is, print out what is being printed, as well as the value. Some people will say this is not possible in any language, but it is in fact possible in C and Ruby.
try this:
a = 1
b = 2
def fnc():
return 'FUNCTION'
def pr(name):
print('{} is {}'.format(name, eval(name)))
pr('a')
pr('b')
pr('fnc()')
Output:
a is 1
b is 2
fnc() is FUNCTION
I'd want to say: "it is impossible", which is true, for certain degrees of impossible.
There is no way to make a code macro in Python such that the usual C tricks with preprocessor stringifications and such would require.
However, you still have 2 choices:
if sources are available, you can make a debug function that would dig the line in source code where it was called using the call frames. However Python bytecode only stores line numbers, not column positions on the line, so you couldn't distinguish 2 said function calls on the same line.
Use the eval trick - pass in a string that is evalled in the function in the caller's globals and locals, and then printed out.
The 2nd would be slightly less yuck and would be more portable as well:
import inspect
def pr(expr):
calling_frame = inspect.currentframe().f_back
value = eval(expr, calling_frame.f_globals, calling_frame.f_locals)
print("{} = {}".format(expr, value))
Elsewhere you just need to import this and you can do
a = 5
def func():
b = 42
pr('a, b')
func()
which prints out
a, b = (5, 42)
This is not possible. Python object not contains references to its names. If integers, lists, dicts and others needed to maintain a list of strings that represented names that referred to it... Imagine this!
I came across closures in python, and I've been tinkering around the subject.
Please Correct me if I'm wrong here, but what I understood for when to use closures (generally) is that it can be used as a replacement of small classes (q1) and to avoid the use of globals (q2).
Q1: [replacing classes]
Any instance created from the datafactory class will have it's own list of data, and hence every appending to that object's list will result in an incremental behavior. I understand the output from an OO POV.
class datafactory():
def __init__(self):
self.data = []
def __call__(self, val):
self.data.append(val)
_sum = sum(self.data)
return _sum
incrementwith = datafactory()
print(incrementwith(1))
print(incrementwith(1))
print(incrementwith(2))
OUTPUT:
1
2
4
I tried replacing this with a closure, it did the trick, but my understanding to why/how this is happening is a bit vague.
def data_factory():
data = []
def increment(val):
data.append(val)
_sum = sum(data)
return _sum
return increment
increment_with = data_factory()
print(increment_with(1))
print(increment_with(1))
print(increment_with(2))
OUTPUT:
1
2
4
What I'm getting is that the data_factory returns the function definition of the nested increment function with the data variable sent along as well, I would've understood the output if it was something like this:
1
1
2
But how exactly the data list persists with every call?
Shouldn't variables defined in a function die after the function finishes execution and get regenerated and cleared out with the next fn call?
Note: I know that this behavior exists normally in a function defined with default parameters like def func(val, l = []): where the list will not be cleared on every fn call, but rather be updated with a new element/append, which is also something that I do not fully understand.
I would really appreciate an academic explanation to what happens in both scenarios (OO and closures).
Q2: [replacing use of global]
Is there a way using closures to increment the following variable without using globals or a return statement ?
a = 0
print("Before:", a) # Before: 0
def inc(a):
a += 1
print("After:", a) # After: 0
Thank you for your time.
For the first question, I found after some digging that passing mutables as default parameters isn't really a good move to make:
https://florimond.dev/blog/articles/2018/08/python-mutable-defaults-are-the-source-of-all-evil/#:~:text=of%20this%20mess.-,The%20problem,or%20even%20a%20class%20instance.
def function(x):
x = 4
variable = 0
function(variable)
print(variable)
This would output 0 but is there a way that it outputs 4? And also it should be without return.
First of all, I'd suggest you take a look to this nice explanation about python names and values. Now, one possible way to achieve what you want would be using a mutable structure as a dictionary, so you can pass your variable inside, something similar to this would do it:
def function(dct):
dct['variable'] = 4
dct = {
'variable': 0
}
function(dct)
print(dct['variable'])
More info can be found in python docs
I am a c++ guy, learning the lambda function in python and wanna know it inside out. did some seraches before posting here. anyway, this piece of code came up to me.
<1> i dont quite understand the purpose of lambda function here. r we trying to get a function template? If so, why dont we just set up 2 parameters in the function input?
<2> also, make_incrementor(42), at this moment is equivalent to return x+42, and x is the 0,1 in f(0) and f(1)?
<3> for f(0), does it not have the same effect as >>>f = make_incrementor(42)? for f(0), what are the values for x and n respectively?
any commments are welcome! thanks.
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
Yes, this is similar to a C++ int template. However, instead of at compile time (yes, Python (at least for CPython) is "compiled"), the function is created at run time. Why the lambda is used in this specific case is unclear, probably only for demonstration that functions can be returned from other functions rather than practical use. Sometimes, however, statements like this may be necessary if you need a function taking a specified number of arguments (e.g. for map, the function must take the same number of arguments as the number of iterables given to map) but the behaviour of the function should depend on other arguments.
make_incrementor returns a function that adds n (here, 42) to any x passed to that function. In your case the x values you tried are 0 and `1``
f = make_incrementor(42) sets f to a function that returns x + 42. f(0), however, returns 0 + 42, which is 42 - the returned types and values are both different, so the different expressions don't have the same effect.
The purpose is to show a toy lambda return. It lets you create a function with data baked in. I have used this less trivial example of a similar use.
def startsWithFunc(testString):
return lambda x: x.find(testString) == 0
Then when I am parsing, I create some functions:
startsDesctription = startsWithFunc("!Sample_description")
startMatrix = startsWithFunc("!series_matrix_table_begin")
Then in code I use:
while line:
#.... other stuff
if startsDesctription(line):
#do description work
if startMatrix(line):
#do matrix start work
#other stuff ... increment line ... etc
Still perhaps trival, but it shows creating general funcitons with data baked it.
So I wrote this function from a book I am reading, and this is how it starts:
def cheese_and_crackers(cheese_count, boxes_of_crackers):
print "You have %d cheeses!" % cheese_count
print "You have %d boxes of crackers!" % boxes_of_crackers
print "Man that's enough for a party!"
print "Get a blanket.\n"
ok, makes sense. and then, this is when this function is run where I got a little confused and wanted to confirm something:
print "OR, we can use variables from our script:"
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese, amount_of_crackers)
the thing that confused me here is that the amount_of_cheese and amount_of_crackers is changing the variables (verbage? not sure if i am saying the right lingo) from cheese_count and boxes_of_crackers repectively from the first inital variable labels in the function.
so my question is, when you are using a different variable from the one that is used in the initial function you wrote, why would you change the name of the AFTER you wrote out the new variable names? how would the program know what the new variables are if it is shown after it?
i thought python reads programs top to bottom, or does it do it bottom to top?
does that make sense? i'm not sure how to explain it. thank you for any help. :)
(python 2.7)
I think you are just a bit confused on the naming rules for parameter passing.
Consider:
def foo(a, b):
print a
print b
and you can call foo as follows:
x = 1
y = 2
foo(x, y)
and you'll see:
1
2
The variable names of the arguments (a, b) in the function signature (1st line of function definition) do not have to agree with the actual variable names used when you invoke the function.
Think of it as this, when you call:
foo(x, y)
It's saying: "invoke the function foo; pass x in as a, pass y in as b". Furthermore, the arguments here are passed in as copies, so if you were to modify them inside the function, it won't change the values outside of the function, from where it was invoked. Consider the following:
def bar(a, b):
a = a + 1
b = b + 2
print a
x = 0
y = 0
bar(x, y)
print x
print y
and you'll see:
1
2
0
0
The script runs from top to bottom. The function executes when you call it, not when you define it.
I'd suggest trying to understand concepts like variables and function argument passing first.
def change(variable):
print variable
var1 = 1
change(var1)
In the above example, var1 is a variable in the main thread of execution.
When you call a function like change(), the scope changes. Variables you declared outside that function cease to exist so long as you're still in the function's scope. However, if you pass it an argument, such as var1, then you can use that value inside your function, by the name you give it in the function declaration: in this case, variable. But it is entirely separate from var! The value is the same, but it is a different variable!
Your question relates to function parameter transfer.
There are two types of parameter transfer into a function:
By value ------- value changed in function domain but not global domain
By reference ------- value changed in global domain
In python, non-atomic types are transferred by reference; atomic types (like string, integer) is transferred by value.
For example,
Case 1:
x = 20
def foo(x):
x+=10
foo()
print x // 20, rather than 30
Case 2:
d = {}
def foo(x): x['key']=20
foo(d)
print d // {'key': 20}