How can I create an automatically updated variable in Python 3+? - python

Code mock-up & expected results:
X = 10
Y = (X-10)/2
print(Y)
X = 12
print(Y)
I want this to print "0" and then "1", but obviously Y is not dynamically assigned.
I have tried utilizing lambda functions (a la Y = lambda i: (X-10)/2) to get this functionality, but I keep getting <function <lambda> at 0x7f5f6356eea0>.
This is just to avoid needing to run a function or redefine Y at the end of any function that alters the value of X.
Thanks in advance!

Alternatively, you can use properties as well:
class P:
def __init__(self, x):
self.__x = x
self.__y = x
#property
def x(self):
return self.__x
#property
def y(self):
return (self.__x - 10) / 2
#x.setter
def x(self, x):
self.__x = x
You will have to access the values through an instance of the P class, though.
p = P(10)
print(p.y)
p.x = 12
print(p.y)

I have tried utilizing lambda functions (a la Y = lambda i: (X-10)/2)
You need to call the function:
print(Y())
As for having print(Y) print the updated value? Mostly impossible, and what workarounds exist aren't anywhere near worth it. Just be explicit about recomputing the value.

You need to call the lambda:
print(Y())
Assigning a lamda to a variable is essentially the same as defining a function:
def Y():
return (X-10)/2
You can't do what you want with ordinary variables. Assigning a variable copies the value into it, it doesn't create a reference to the expression that was used.

You need to provide x argument to your lambda function. In your case this is 10 or 12.
y = lambda x: (x-10)/2
print(y(10))
>>> 0.0

Use a lambda with a dict to keep track of it:
>>> vars={}
>>> vars['x']=10
>>> vars['y']=lambda :(vars['x']-10.0)/2.0
>>> vars['y']()
0.0
>>> vars['x']=12.0
>>> vars['y']()
1.0

To assign the value using your lambda expression, you need to call it. You can do it in one line:
Y = (lambda i: (i-10)/2)(X)
There is no need for defining additional classes or functions, just add the parentheses and the argument.
The reason you are getting <function <lambda> at 0x7f5f6356eea0> is that a lambda expression produces a function, not the result of executing the function.

Related

Are functions and helper functions treated differently in python?

Over here, the main function is g(x) and the helper function is h(). I noticed I can get the output for g(3), simply by binding x=3 and then doing any of the three
print(g(x))
g(x)
z=g(x)
But on the other hand, I noticed h() is outputted only when I type "print(h())". Are my observations correct or did I make a mistake? And also what is the logic behind this weird discrimination?
I like to think of it this way. Usually, if you had a line like "5" or "x=5", python doesn't give an output of 5. But functions have been given a special feature where they are invoked in any of the 3 ways. It's only that this special feature is being 'withdrawn' in the case of helper functions
The code you have written is equivalent to this:
def g(x):
def h():
any_name_you_want = 'abc'
return any_name_you_want
x += 1
print("in g(x)", x)
print(h())
return x
You cannot assign to a non-local variable inside a function. When Python creates the namespace for h, x is local to h because the assignment requires python to add the namespace for x at runtime.
Hence your code is also equivalent to :
def g(x):
def h():
return 'abc'
x += 1
print("in g(x)", x)
print(h())
return x
To get a sense of what is happening, run the following and then read up on UnboundLocalError:
def g(x):
def h():
x = x
return x
x += 1
print("in g(x)", x)
print(h())
return x

iterating through a function's sub functions python

The goal is to try and access any function's sub functions. I've looked around and I'm not too sure there is a way to do it. When I've tried using
functions = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isfunction)]
which returns the functions in some module (in the above __name__==__main__). When I have used that method, it doesn't return any sub functions. However I'd like to access sub functions that look something like
def f(x):
def y(x):
return x += 3
def z(x):
return x**2 - 1
x += y(x)
x += z(x)
return x
So it seems to me like there should be some way to access them with a magic method of f or some attribute of f. I have a hard time believing that those sub functions aren't stored as some attribute of f, but I have no idea.
In the end, what I need to do is to iterate through the sub functions of some function, so I thought the solution would look something like
for subfunc in f.__method_that_returns_subfuncs__():
if 'my_string' == subfunc.__name__:
out = subfunc(args)
I just need to be able to compare a string to a subfunction name then call that subfunction.
Thanks
There's no implicit list of functions to iterate over. You need to define it yourself. Simply functions can be assigned directly to a list by defining them with lambda expressions; more complex functions will need to be defined first, then added. Examples of each:
def f(x):
funcs = []
def y(x):
return x += 3
f.append(y)
f.append(lambda x: x**2 - 1)
for func in funcs:
x = func(x)
return x
If you care about the name, you can access it via the function object's __name__ attribute.
for func in funcs:
if func.__name__ == "some_func":
x = func(x)

How is `x = 42; x = lambda: x` parsed? [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
I was surprised that this assertion fails:
x = 42
x = lambda: x
assert x() == 42
It seems that x ends up recursively referring to itself, so that x(), x()(), etc. are all functions.
What is the rule used to parse this, and where is this documented?
By the way (not unexpectedly given the above), the original value of x has no references left after the lambda definition:
class X:
def __del__(self): print('deleting')
x = X()
x = lambda: x # 'deleting' is printed here
The variable x is created by the first assignment, and rebound with the second assignment.
Since the x in the lambda isn't evaluated until the lambda is called, calling it will evaluate to the most recently assigned value.
Note that this is not dynamic scoping - if it were dynamic, the following would print "99", but it prints "<function ...":
x = 42
x = lambda: x
def test(f):
x = 99
print(f())
test(x)
The first assignment is irrelevant; the x in the body of the lambda is bound late:
x = lambda: x # no need for a prior assignment
x = lambda: y # notice: no NameError occurs, *until it is called*
This is the same reason that creating lambdas in a loop is tricky, and is also used to make trees with the standard library defaultdict:
tree = lambda: defaultdict(tree)
t = tree()
t['foo']['bar']['baz'] = 'look ma, no intermediate steps'
A lambda is an anonymous function object. Python completely resolves whatever is on the right side of an equation to a single anonymous object and then resolves whatever is on the left side for assignment.
x = lambda: x
first compiles lambda: x into a function object that returns whatever happens to be in x at the time it is called. It then rebinds x with this function object, deleting whatever object happened to be there before.
Now x is a function that returns whatever is in x... which is a function that returns whatever is in x, etc... So you can write x()()()()()() as many times as you want, and still get that orginal lambda:x function object.
Python functions have a local namespace but only variables assigned in the function reside there. Since x isn't assigned in the lambda, it's resolved in the containing scope - that is, the module level "x". An identical piece of code is
def x():
return x
Contrast this with
def x():
x = 1
return x
Now, the parameter x is a local variable and is unrelated to the global x.

Can you assign variables in a lambda?

I was using a lambda statement to perform math, and happened to repeatedly use one certain value. Therefore I was wondering if it was possible to assign and use a variable within a lambda statement.
I have tried things like:
a = lambda n:(b=3+2*n) #[my math here]
However this just raises errors, and I was wondering if there was a way to do this.
Nope, you can't. Only expressions allowed in lambda:
lambda_expr ::= "lambda" [parameter_list]: expression
lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond
You could, however, define a second lambda inside the lambda and immediately call it with the parameter you want. (Whether that's really better might be another question.)
>>> a = lambda n: ((3+2*n), n*(3+2*n)) # for reference, with repetition
>>> a(42)
(87, 3654)
>>> a2 = lambda n: (lambda b: (b, n*b))(3+2*n) # lambda inside lambda
>>> a2(42)
(87, 3654)
>>> a3 = lambda n: (lambda b=3+2*n: (b, n*b))() # using default parameter
>>> a3(42)
(87, 3654)
Of course, both the outer and the inner lambda can have more than one parameter, i.e. you can define multiple "variables" at once. The benefit of this approach over, e.g., defining a second lambda outside of the first is, that you can still also use the original parameters (not possible if you invoked a with b pre-calculated) and you have to do the calculation for b only once (other than repeatedly invoking a function for the calculation of b within a).
Also, inspired by the top answer to the linked question, you could also define one or more variables as part of a list comprehension or generator within the lambda, and then get the next (first and only) result from that generator or list:
>>> a4 = lambda n: next((b, n*b) for b in [3+2*n])
>>> a4(42)
(87, 3654)
However, I think the intent behind the lambda-in-a-lambda is a bit clearer. Finally, keep in mind that instead of a one-line lambda, you could also just use a much clearer three-line def statement...
Also, starting with Python 3.8, there will be assignment expressions, which should make it possible to write something like this. (Tested with Python 3.8.10.)
>>> a5 = lambda n: ((b := 3+2*n), n*b)
You can just pass your lambda an argument which passes it along to another argument if you wish:
>>> b = lambda x: 3 + 2*x
>>> a = lambda y: y * b(y)
>>> a(1)
5
>>> a(2)
14
You can create 2 different lambda functions and pass one to the other. For example,
b = lambda x: 3+2*x
a = lambda y: [my math here using variable b(y)]
I've cooked up this recipe for python 3.8+ using PEP572 Assignment Expressions to assign arbitrary variables and execute arbitrary expressions.
# python 3.8b1
lambda a: (
(bool(b:=a**2) or 1)
and (bool(c:=a-b) or 1)
and not print(f'compute: {a} + {b} + {c}')
and (
(ret:=a + b + c) or ret)
)
)
tst(0)
# prints: "compute: 0 + 0 + 0"; returns: 0
tst(1)
# prints: "compute: 1 + 1 + 0"; returns: 2
tst(8)
# prints: "compute: 8 + 64 + -56"; returns: 16
So the pattern is:
lambda: [*vars]: (
(bool(a:=[expr(*vars)]) or 1)
and (bool([expr]) or 1)
and bool([always true expr])
and not bool([always false expr])
and (
# parentheses required so `result:=` doesn't capture the `or result` part
(result:=[result expr]) or result
)
)
This may be simplified if you know the truthiness of any particular expression.
That being said, if you want to assign a variable to reuse inside a lambda, you probably should consider writing a normal function.
Im no expert at this, but the way i did it was by modifying globals() or locals()
like this:
lambda: globals().__setitem__('some_variable', 'some value')
or if it's inside a function:
lambda: locals().__setitem__('some_variable', 'some value')
you could also use update() instead of __setitem__() if you wanted to, but that's a bit redundant.
i hope that after 4 years my late answer will be useful
Python has setattr function to set attribute of given object. You can use it in your lambda expression.
setattr is useful when you want to programmatically-correctly (sorry) set some class or class' instance. It is not used frequently because it is easier to assign variables directly with = expression. But for lambdas... It is a salvation.
Also, iterables that support settign item (such as list), you can use <iter>.__setitem__.
Option 1. If you know the name of variable you're assigning.
x = lambda nameofvar, value: setattr(__builtins__, nameofvar, value)
# abc does not exist right now. Assigning and setting it to 10
x('abc', 10)
print(abc) # output: 10
alt, if you want to set object's attribute:
class MyClass:
my_attr = False
def __init__(self, value):
self.value = value
myinstance = MyClass(25)
x = lambda obj, nameofvar, value: setattr(obj, nameofvar, value)
short_x = lambda nameofvar, value: setattr(MyClass, nameofvar, value)
# ^^^ this one works only for MyClass' attributes.
print(MyClass.my_attr) # output: False
x(MyClass, 'my_attr', True) # Changing MyClass' my_attr's value
print(MyClass.my_attr) # output: True
x(MyClass, 'my_attr2', 5) # Assigning new attribute to MyClass
print(MyClass.my_attr2) # output: 5
short_x('my_attr2', 123) # Setting MyClass' my_attr2 to 123
print(MyClass.my_attr2) # output: 123
print(myinstance.value) # output: 25
x(myinstance, 'value', 500)
print(myinstance.value) # output: 500
Option 2. Make a custom class and turn variable into its instance.
class Value:
def __init__(self, value):
self.value = value
x = lambda var, newvalue: setattr(var, 'value', newvalue)
a = Value(15)
print(a.value) # output: 15
x(a, 25)
print(a.value) # output: 25
Option 3. To set object's item.
lst = [15, 30, 45, 60, 75, 90]
x = lambda iterable, item, value: iterable.__setitem__(item, value)
print(lst) # output: [15, 30, 45, 60, 75, 90]
x(lst, 2, 1000)
print(lst) # output: [15, 30, 1000, 60, 75, 90]
You can instead use a bit of creativity, for example if you want to do some evaluation to an equation and assign the result to a variable it can be done like this:
class Results:
res = 0
clas= Results()
setattr(clas, 'res', 3+2*4)
print(clas.res)
You could rewrite this in a oop way, like this, maybe you are using an oop structure anyways so you could integrate it in there.
class example:
def __init__(self):
self.a = None
object = example()
a = lambda n:(setattr(object, "a", 3+2*n)) #[my math here]
a(2)
print(object.a)
Output:
7

Using a list from one function, inside another function python

I am new to python. This might be a simple question, but if I have many functions that are dependent on each other how would I access lists from one function to use in another.
So...
def function_1():
list_1=[]
def function_2():
list_2= [2*x for x in list_1]
def function_3():
list_3= [x * y for x, y in zip(list_1, list_2)]
That is not the exact code but that is the idea of my problem. I would just put them all together in one function but I need them to be separate.
The correct way to do this would be to use a class. A class is an object that has internal variables (in your case, the three lists), and methods (functions that can access the internal methods). So, this would be:
class Foo(object):
def __init__(self, data=None):
self.list_1 = data if not data is None else []
def function_2():
self.list_2 = [2 * x for x in self.list_1]
And so on. For calling it:
foo = Foo() # list_1 is empty
foo2 = Foo([1,2,3]) # list_1 is not empty
foo2.function_2()
print foo2.list_2
# prints [2, 4, 6]
Make them arguments and return values:
def function_1():
return []
def function_2(list_1):
return [2*x for x in list_1]
def function_3(list_1, list_2):
return [x * y for x, y in zip(list_1, list_2)]
(this suggests that function_1 isn't much worth having...)
The exact way will depend on exactly how you want things to work, but here is a simple example:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]
The key point is that functions do not generally just "do" things, they return things. If you have a value in one function that you want to use in another function, the first function should return that value. The second function should call the first function, and use its return value.
Functions are basically black boxes -- the outside world doesn't really know what goes on inside or what variables exist there. From the outside, other code only sees what goes in (the function's arguments) and what goes out (its return value).
So if your function computes some value that is to be used elsewhere, it should be returned as the result of the function.
E.g.,
def square(x):
return x * x
Takes a number, computes its square, and returns it.
Then you could do:
print(square(5))
and it will print 25.
So in your case you can return the lists and use them in the other functions, as the other answers showed:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]

Categories

Resources