This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I can't understand how x and y are the same list. I've been trying to debug it using print statements and import code; code.interact(local=locals()) to drop into various points, but I can't figure out what on earth is going on :-(
from collections import namedtuple, OrderedDict
coordinates_2d=["x","y"]
def virtual_container(virtual_container, objects_type):
"""Used to create a virtual object given a the type of container and what it holds.
The object_type needs to only have normal values."""
if issubclass(virtual_container, list):
class my_virtual_container_class:
"""This singleton class represents the container"""
def __init__(self):
#Define the default values
__vals__=OrderedDict([(key,list()) for key in objects_type])
print(id(__vals__["x"]), id(__vals__["y"]))#ids are different: 12911896 12911968
#Then functions to access them
d={key: lambda self: self.__vals__[key] for key in objects_type}
d["__vals__"]=__vals__
#Construct a named tuple from this
self.attr=type('attr_cl',(), d)()
print(id(self.attr.x()), id(self.attr.y()))#ids are same: 32904544 32904544
#TODO: Define the operators __del__, setitem, getitem. Also append
return my_virtual_container_class()
#Nice method of handling coordinates
coordinates=virtual_container(list, coordinates_2d)
x=coordinates.attr.x()
y=coordinates.attr.y()
x.append(1)
y.append(2)
print(x, y)#Prints [1, 2] [1, 2]
The problem is with this line:
d={key: lambda self: self.__vals__[key] for key in objects_type}
The lambda uses the value of the variable key, but that value has changed by the time the lambda is called - so all lambdas will actually use the same value for the key.
This can be fixed with a little trick: Pass the key as a default parameter value to the lambda:
... lambda self, key=key: self.__vals__[key] ...
This makes sure that the value of key is bound to the one it had at the time the lambda was created.
I think the following line should look like this (but unfortunately I can't test because I don't have Python 3 available):
# Then functions to access them
d = dict((key, lambda self: self.__vals__[key]) for key in objects_type)
Related
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed last year.
I am possibly very naive, but I find the following behaviour unexpected.
Introduction: I need a wrapper to address dynamically the methods of my own class, model. I am trying to use a dict to have a separate entry for each of a given number of members of the class that are dynamically requested. I link the dict keys to the chosen members iteratively and I find that the doc string is preserved, but the methods get overwritten by the last item in the iteration, despite their distinct keys. Here is a snippet where I reproduce the behaviour with numpy, in place of my own class.
import numpy as np
name = ["sin","cos"]
bnd = {}
print('Within the defining loop, it works!\n')
for nam in name:
# useless indirect function (with doc string)
# equivalent to sin(2*pi*x)
# or to cos(2*pi*x)
bnd[nam] = lambda x, par: np.__getattribute__(nam)(x*par)
bnd[nam].__doc__ = '"""'+nam+'"""'
print('bnd doc in-loop: {} = {}'.format(nam,bnd[nam].__doc__))
print('bnd method in-loop {}(0,2*pi) = {}'.format(nam,bnd[nam](0,2*np.pi)))
print('\n However after the loop...')
print('bnd keys {}'.format(bnd.keys()))
print('\nfirst function doc: {}'.format(bnd["sin"].__doc__))
print('doc is preserved, but instead the method')
print('(should be sin(2 pi *0)) yields {}'.format(bnd["sin"](0,2*np.pi)))
print('\nsecond trial_function doc: {}'.format(bnd["cos"].__doc__))
print('doc is preserved, again, and this time the method')
print('(should be cos(2 pi *0)) yields correctly {}'.format(bnd["cos"](0,2*np.pi)))
print('\nSummary: bnd[nam] gets overwritten by the last lambda definition in the loop. \n\nWhy????')
If you run the code you get the following
Within the defining loop, it works!
bnd doc in-loop: sin = """sin"""
bnd method in-loop sin(0,2*pi) = 0.0
bnd doc in-loop: cos = """cos"""
bnd method in-loop cos(0,2*pi) = 1.0
However after the loop...
bnd keys dict_keys(['sin', 'cos'])
first function doc: """sin"""
doc is preserved, but instead the method
(should be sin(2 pi *0)) yields 1.0
second trial_function doc: """cos"""
doc is preserved, again, and this time the method
(should be cos(2 pi *0)) yields correctly 1.0
Summary: bnd[nam] gets overwritten by the last lambda definition in the loop.
Why????
which I hope is clarifying my question.
As others have explained. There is only one variable nam in your function. When you create the lambda, it doesn't capture the value of nam as it was when created the lambda. Rather all the lambdas share the same nam, and it has whatever value it had at the end of the function.
There are several get arounds. Essentially you need to capture nam as a variable.
The "official" way to do this is that you could just write:
def attribute_getter(nam):
return lambda x, par: np.__getattribute__(nam)(x*par)
bind[nam] = attribute_getter(nam)
The quick and dirty solution is:
bind[nam] = lambda x, par, nam=nam: np.__getattribute__(name)(x * par)
The variable nam is turned into an optional which is set to the current value of nam.
Edit: Changed "program" to "function".
This question already has answers here:
Local variables in nested functions
(4 answers)
Closed 2 years ago.
I have a Python class MyObject (a subclass of tuple) and another class for a set of these objects, MyObjectSet (a subclass of set). I’d like that, for any non-builtin method that I define for MyObject, a method of the same name be defined for MyObjectSet with value equal to the sum of the method over the contents of the MyObjectSet.
I had thought that something like the code below would work, but the result doesn’t match my intended outcome. In practice MyObject and MyObjectSet have a lot more to them and are justified.
class MyObject(tuple):
def stat_1(self):
return len(self)
def stat_2(self):
return sum(self)
class MyObjectSet(set):
pass
for stat_name in dir(MyObject):
if not stat_name.startswith("__"):
stat_func = getattr(MyObject, stat_name)
if callable(stat_func):
setattr(MyObjectSet, stat_name, lambda S: sum(stat_func(p) for p in S))
if __name__ == "__main__":
S = MyObjectSet(MyObject(t) for t in [(1,2), (3,4)])
result, expected = S.stat_1(), sum(p.stat_1() for p in S)
print(f"S.size() = {result}, expected {expected}")
result, expected = S.stat_2(), sum(p.stat_2() for p in S)
print(f"S.sum() = {result}, expected {expected}")
Is there any way to achieve this functionality?
replace your lambda with this:
lambda S, f=stat_func: sum(f(p) for p in S)
It copies the stat_func into f, instead of capturing a reference to it, which was what happened in your original code (so all stat_funcs inside your different lambdas ended up being the last value assigned to the stat_func in the for loop.
You can simply override __getattr__ to treat any possible method call as a summing wrapper around the object's method of the same name. This simple example will just raise an AttributeError if the underlying method doesn't exist; you may want to catch the exception and raise another error of your own.
class MyObjectSet(set):
def __getattr__(self, mn):
return lambda: sum(methodcaller(mn)(x) for x in self)
This question already has answers here:
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I want to add properties dynamically to my class as follows, however I end up creating aliases. How can I prevent this?
class A:
def __init__(self, a, b):
self._a = a
self._b = b
for attr in ('a', 'b'):
f = lambda self: getattr(self, '_'+attr)
setattr(A, attr, property(f, None))
a = A(0,1)
print(a.a)
print(a.b)
However this yields:
1
1
Edit:
The comment on closure scoping is relevant, however that leaves the question whether one can generate properties dynamically that reference some attribute of self open.
Specifically with respect to the example above: how, if at all, can I set the property such that a.a returns 0 instead of 1? If I simply try to pass the attribute argument to the lambda function, this attribute will need to be passed and thus this won't work.
In order to get your desired result, you'd need to wrap your lambda in another function, like so:
def make_fget(attr):
return lambda self: getattr(self, '_' + attr)
This way, when you call make_fget, the local name attr is bound to the argument passed.
You can call this in a loop as in your original code:
for attr in ('a', 'b'):
setattr(A, attr, property(make_fget(attr), None))
The difference here is that in your original version, the loop essentially reassigns attr every iteration, and the lambda is only looking at attr in the outer scope (the loop) at the time it is called, and it will end up with whatever was assigned in the last iteration.
By wrapping in another function, in every loop iteration you essentially create a fresh outer scope (the function call), with the name attr bound to the passed argument, for the returned lambda.
I have a class (list of dicts) and I want it to sort itself:
class Table(list):
…
def sort (self, in_col_name):
self = Table(sorted(self, key=lambda x: x[in_col_name]))
but it doesn't work at all. Why? How to avoid it? Except for sorting it externally, like:
new_table = Table(sorted(old_table, key=lambda x: x['col_name'])
Isn't it possible to manipulate the object itself? It's more meaningful to have:
class Table(list):
pass
than:
class Table(object):
l = []
…
def sort (self, in_col_name):
self.l = sorted(self.l, key=lambda x: x[in_col_name])
which, I think, works.
And in general, isn't there any way in Python which an object is able to change itself (not only an instance variable)?
You can't re-assign to self from within a method and expect it to change external references to the object.
self is just an argument that is passed to your function. It's a name that points to the instance the method was called on. "Assigning to self" is equivalent to:
def fn(a):
a = 2
a = 1
fn(a)
# a is still equal to 1
Assigning to self changes what the self name points to (from one Table instance to a new Table instance here). But that's it. It just changes the name (in the scope of your method), and does affect not the underlying object, nor other names (references) that point to it.
Just sort in place using list.sort:
def sort(self, in_col_name):
super(Table, self).sort(key=lambda x: x[in_col_name])
Python is pass by value, always. This means that assigning to a parameter will never have an effect on the outside of the function. self is just the name you chose for one of the parameters.
I was intrigued by this question because I had never thought about this. I looked for the list.sort code, to see how it's done there, but apparently it's in C. I think I see where you're getting at; what if there is no super method to invoke? Then you can do something like this:
class Table(list):
def pop_n(self, n):
for _ in range(n):
self.pop()
>>> a = Table(range(10))
>>> a.pop_n(3)
>>> print a
[0, 1, 2, 3, 4, 5, 6]
You can call self's methods, do index assignments to self and whatever else is implemented in its class (or that you implement yourself).
This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 6 years ago.
I want to select a function based on the value of a dictionary:
dict = {"func_selector":"func1", "param_value":"some_value"}
# defined a function
def func1(param):
# some function code
Now, I want to select the function based on the value of some key, so that it can achieve something like:
# calling a function based on some dict value
dict["func_selector"](dict["param_value"])
The syntax is probably wrong, but I am wondering if it is possible to do that in Python or something similar.
Try storing the value of the function in the dictionary, instead of its name:
def func1(param):
print "func1, param=%r" % (param,)
d = {"func_selector":func1, "param_value": "some value"}
Then you can say:
>>> d['func_selector'](d['param_value'])
func1, param='some value'
The best approach IMO is do it like this
def func1(param):
#code
some_value = ... #The value you need
my_dict = {"func_selector": func1, "param_value": some_value }
And then
my_dict["func_selector"](my_dict["param_value"])
Now, if you only have the name of the function you need to call getattr
And call it
getattr(my_class, my_dict["func_selector"])(my_dict["param_value"])
my_class is the class which contains the method. If it's not in a class I think you can pass self