I want to delay the evaluation of a call to a member function of an instance of a class until this instance actually exists.
Minimum working example:
class TestClass:
def __init__(self, variable_0):
self.__variable_0 = variable_0
def get_variable_0(self):
return self.__variable_0
delayed_evaluation_0 = test_class.get_variable_0() # What should I change here to delay the evaluation?
test_class = TestClass(3)
print(delayed_evaluation_0.__next__) # Here, 'delayed_evaluation_0' should be evaluated for the first time.
I tried using lambda, yield and generator parentheses () but I can't seem to get this simple example to work.
How do I solve this problem?
a simple lambda works. When called, the function will fetch test_class variable from the current scope, and if it finds it, that will work, like below:
delayed_evaluation_0 = lambda : test_class.get_variable_0()
test_class = TestClass(3)
print(delayed_evaluation_0())
prints 3
Related
I recently studied how decorators work in python, and found an example which integrates decorators with nested functions.
The code is here :
def integer_check(method):
def inner(ref):
if not isinstance(ref._val1, int) or not isinstance(ref._val2, int):
raise TypeError('val1 and val2 must be integers')
else:
return method(ref)
return inner
class NumericalOps(object):
def __init__(self, val1, val2):
self._val1 = val1
self._val2 = val2
#integer_check
def multiply_together(self):
return self._val1 * self._val2
def power(self, exponent):
return self.multiply_together() ** exponent
y = NumericalOps(1, 2)
print(y.multiply_together())
print(y.power(3))
My question is how the inner function argument("ref") accesses the instance attributes (ref._val1 and ref._val2)?
It seems like ref equals the instance but i have no idea how it happenes.
Let's first recall how a decorator works:
Decorating the method multiply_together with the decorator #integer_check is equivalent to adding the line: multiply_together = integer_check(multiply_together), and by the definition of multiply_together, this is equivalent to multiply_together = inner.
Now, when you call the method multiply_together, since this is an instance method, Python implicitly adds the class instance used to invoke the method as its first (an only, in this case) argument. But multiply_togethet is, actually,inner, so, in fact, inner is invoked with the class instance as an argument. This instance is mapped to the parameter ref, and through this parameter the function gets access to the required instance attributes.
well one explanation I found some time ago about the self argument was that this:
y.multiply_together()
is roughly the same as
NumericalOps.multiply_together(y)
So now that you use that decorator it returns the function inner which requires the ref argument so I see that roughly happen like this (on a lower level):
NumericalOps.inner(y)
Because inner "substitutes" multiply_together while also adding the extra functionality
inner replaces the original function as the value of the class attribute.
#integer_check
def multiply_together(self):
return self._val1 * self._val2
# def multiply_together(self):
# ...
#
# multiply_together = integer_check(multiply_together)
first defines a function and binds it to the name multiply_together. That function is then passed as the argument to integer_check, and then the return value of integer_check is bound to the name multiply_together. The original function is now only refernced by the name ref that is local to inner/multiply_together.
The definition of inner implies that integer_check can only be applied to functions whose first argument will have attributes named _val1 and _val2.
I wrote the following code to learn closures and decorators in python.
The code executes fine in Pythonista on iPad.
But the decorator doesn’t work like I thought it would. The decorator is intended to cause the function to print out with a unique random color with each call. But it looks like the decorator is only called once for all calls to the function. Can someone explain why ?
import random
import console
def random_color(func):
r = random.random()
g = random.random()
b = random.random()
print(f'console.set_color({r},{g},{b})')
console.set_color(r,g,b)
return func
#random_color # run set_tag function through decorator function.
def set_tag(tag):
def enclose_text(text):
print( f'<{tag}>{text}</{tag}>')
return enclose_text
# save enclose_text function with a remembered tag
h1 = set_tag('h1')
p = set_tag('p')
br = set_tag('br')
# execute enclose_text with different text strings
h1('Chapter One')
p('It was a dreary day. The rain had begun to set in ...')
br('')
h1('Chapter Two')
p('By the second day, the sun had returned to full strength.')
The output of all lines are the same color. The next time I run it, all the lines have the same color - but a different color than from the first time it’s executed. I expected the decorator to cause each tag to have a random color.
Can someone explain what this is not the case ?
Below is the output:
<h1>Chapter One</h1>
<p>It was a dreary day. The rain had begun to set in ...</p>
<br></br>
<h1>Chapter Two</h1>
<p>By the second day, the sun had returned to full strength.</p>
The decorator executes when the function is defined; decorator syntax is just syntactic sugar for function application.
#random_color # run set_tag function through decorator function.
def set_tag(tag):
def enclose_text(text):
print( f'<{tag}>{text}</{tag}>')
return enclose_text
is equivalent to
def set_tag(tag):
def enclose_text(text):
print( f'<{tag}>{text}</{tag}>')
return enclose_text
set_tag = random_color(set_tag)
You should define your decorator like this instead:
def random_color(func):
def wrapper(*args, **kwargs):
r = random.random()
g = random.random()
b = random.random()
print(f'console.set_color({r},{g},{b})')
console.set_color(r,g,b)
return func(*args, **kwargs)
return wrapper
That is, random_color should return a function which sets the console color, then calls the original function.
In addition, set_tag isn't the function you want to decorate: it's the function that set_tag creates:
def set_tag(tag):
#random_color
def enclose_text(text):
print( f'<{tag}>{text}</{tag}>')
return enclose_text
Before, set_tag was a function that would pick a random color, set the console to use that color, then return a function that would generate a tag. I assuming that the call to set_color affects the terminal at this point, not when print eventually gets called. Now, it's a function that returns a function that both picks a random color and generates a tag using that color.
I am very new to python and I've been trying to do this code where i use a tkinter button command to run a function, it works but the append() is not executing, meaning it does not append to the list.
The list and the function containing the append is outside the class and is then classed within a class through the use of tkinter button command
I've tried putting the function inside the class, it works but the append is not adding into the list again.
This is the code I've made that is somewhat similar to real one
prices = []
f = True
class firstclass():
def __init__(self):
while f == True:
my_function()
f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print(sum(prices))
the sample of real code is in this link, please take this into consideration as well
python: Appending a value to a list outside the class, function with append also outside the class, but function is called within a class
I expected that it would print the appended value which is 70, but it still printed 0
A few issues you need to deal with. First assigning f=True outside the class won't change the value inside, so if you instantiated the class it would just throw an UnboundLocalError complaining that f isn't initialized. You can try this yourself by instantiating the class with
fc = firstclass()
Without instantiation, you have no hope of it giving you the value you want. It is printing zero because of the function secondclass, which has a print statement that is not contained within a method, so it prints the value sum(prices) which the class is declared. That value is from the original declared value of prices which is []. At least that is the way you have shown it in your question. I'm not sure whether you meant to indent the print statement, which would mean it is part of secondclass. However, if you didn't indent you would get the same result as you haven't instantiated firstclass.
To correct this, see below. This code will output 70 as you intended.
prices = []
class firstclass():
def __init__(self):
my_function()
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print('before instantiation', sum(prices))
fc = firstclass()
print('after instantiation', sum(prices))
fc is now an object of type firstclass and the __init__ method has called my_function to append the value 70 to prices.
There are two reasons this is happening.
You never called firstclass to actually initialize the
constructor.
You are trying to assign False to the variable f
which does not belong to the scope of the class. If you still assign
it, it's considered local. And at the moment the interpreter
detects that you assigned it, the while loop does not have any local
reference of f since you did not define it under the constructor.
See this answer for more details.
Here is the completed code:
prices = []
class firstclass():
f = True
def __init__(self):
while self.f:
my_function()
self.f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
firstclass()
print(sum(prices))
I'm in Python 2.7. I have two classes and one namedtuple. One class houses a dictionary as an instance attribute and a function that assigns to that dictionary. (This is a very simplified version of the situation). The namedtuple is simple enough. The other class is one that adds entries into test_dict via the add_to_test_dict function call.
Then I instantiate DictManipulator and call the test function:
from collections import namedtuple
class DictHolder(object):
def __init__(self):
self.test_dict = {}
def add_to_test_dict(self, key, val):
self.test_dict[key] = val
TestTuple = namedtuple('TestTuple', 'name data')
class DictManipulator(object):
def test(self):
named_tuple_list = [TestTuple(name='key1', data=1), TestTuple(name='key2', data=1000)]
self.my_dh = DictHolder()
for item in named_tuple_list:
self.my_dh.add_to_test_dict(item.name, lambda: item.data)
my_dm = DictManipulator()
my_dm.test()
print('key1 value: ', my_dm.my_dh.test_dict['key1']())
print('key2 value: ', my_dm.my_dh.test_dict['key2']())
# ('key1 value: ', 1000)
# ('key2 value: ', 1000)
Why do both keys return the same value there? I have experimented enough to say that the original named_tuple_list is not updated, and I've tried to use lambda: copy.deepcopy(item.data), but that doesn't work either. Thanks very much, folks.
This is a typical late binding issue (see common gotchas): when the functions (being lambda/anonymous has nothing to do with it) are called, they access the current value of item, which is the last one from the loop. Try
lambda x=item: x.data
in your loop instead. This works since default arguments are bound to a function at definition time while common local variables are evaluated at calling time.
Similar (possible duplicate) question: Python Lambda in a loop
I have a class. This class has a list of functions that are to be evaluated by a different program.
class SomeClass(object):
def __init__(self, context):
self.functions_to_evaluate = []
There is a function that adds functions to an instance of SomeClass, via something like:
new_function = check_number(5)
SomeClassInstance.functions_to_evaluate.append(new_function)
Where check_number is a function that will check if number is greater than 10, let's say.
If I take SomeClassInstance.functions_to_evaluate and print it, I get a bunch of python objects, like so:
<some_library.check_number object at 0x07B35B90>
I am wondering if it is possible for me to extract the input given to check_number, so something like:
SomeClassInstance.functions_to_evaluate[0].python_feature() that will return "5" or whatever the input to check_number was to me.
You can use the standard library functools.partial, which creates a new partially applied function *.
>>> from functools import partial
>>> def check_number(input):
... return input > 10
>>> fn = partial(check_number, 5)
>>> fn.args # this attribute gives you back the bound arguments, as a tuple.
(5,)
>>> fn() # calls the function with the bound arguments.
False
*: actually the partial object is not a function instance, but it is a callable, and from a duck-type perspective it's a function.
If new_function = check_number(5) is a closure, then you can extract this value using __closure__[0].cell_contents:
Example:
def foo(x):
def inn(y):
return x
return inn
s = foo(5)
print(s.__closure__[0].cell_contents)
Output:
5
I understand your confusion, but:
new_function = check_number(5)
Is calling the function, and the new_function variable gets assigned the return value of the function.
If you have this check_number function:
def check_number(input):
return input > 10
Then it will return False, and new_function will be False. Never <some_library.check_number object at 0x07B35B90>.
If you're getting <some_library.check_number object at 0x07B35B90> then your check_number() function is returning something else.
There are probably several ways to skin this cat. But I'd observe first and foremost that you're not adding python function objects to the functions_to_evaluate list, you're adding the evaluations of functions.
You could simply add a tuple of function, args to the list:
SomeClassInstace.functions_to_evaluate.append((check_number, 5))
And then you can:
for f, args in SomeClassInstance.functions_to_evaluate:
print(args)