Python "strange" output - python

class Foo(object):
def __init__(self,x):
self.x = x
self.is_bar = False
def __repr__(self): return str(self.x)
class Bar(object):
def __init__(self,l = []):
self.l = l
def add(self,o):
self.l += [o]
def __repr__(self): return str(self.l)
def foo_plus_foo(f1,f2):
t = Bar()
if not (f1.is_bar and f2.is_bar):
f1.is_bar = True
f2.is_bar = True
t.add(f1)
t.add(f2)
print 'HERE'
return t
if __name__ == '__main__':
li = [Foo(1), Foo(2)]
print foo_plus_foo(li[0],li[1])
print foo_plus_foo(li[0],li[1])
UNEXPECTED OUTPUT:
HERE
[1, 2]
[1, 2]
EXPECTED OUTPUT:
HERE
[1, 2]
[]
What is happening? What did I do wrong? Why is python using old value? What do I do to avoid this?
Thanks!

Never. Do. This.
def __init__(self,l = []):
Never.
One list object is reused. And it's Mutable, so that each time it's reused, the one and only [] created in your method definition is updated.
Always. Do. This.
def __init__( self, l= None ):
if l is None: l = []
That creates a fresh, new, unique list instance.

You are defining l as having a default value of [].
This is a classic Python pitfall.
class Bar(object):
def __init__(self,l = []):
Default values are evaluated at definition time not run-time.
It is evaluated only once.
So t=Bar() sets t.l to the very same list every time.
To fix this, change Bar to
class Bar(object):
def __init__(self,l = None):
if l is None:
l=[]
self.l = l
def add(self,o):
self.l += [o]
def __repr__(self): return str(self.l)

The culprit is the l=[] defined in the Bar class definition.
This list is instantiated once during class definition and is used as the default.
Super dangerous!! I and many others have been burned by this one, trust me the scarring is deep.
Problematic use of mutable.
class Bar(object):
def __init__(self,l = []):
self.l = l
def add(self,o):
self.l += [o]
def __repr__(self): return str(self.l)
Try using an immutable:
class Bar(object):
def __init__(self,l = None):
if l is None:
self.l = []
else:
self.l = l
def add(self,o):
self.l += [o]
def __repr__(self): return str(self.l)

Others have explained the problem and suggested using l=None and an explicit test for it. I'd like to suggest a different approach:
class Bar(object):
def __init__(self, l=[]):
self.l = list(l)
# and so on...
This guarantees a new blank list each time by default, and also assures that if a caller passes in a list of their own, you get a copy of that list rather than a reference to the caller's list. As an added benefit, callers can pass in anything that the list constructor can consume, such as a tuple or a string, and your code doesn't have to worry about that; it can just deal with a list.
If you just save a reference to the list the caller gives you, and later change the list named self.l, you may be inadvertently changing the list that was passed in, too (since both your class and the caller now have a reference to the same object). Similarly, if they change the list after calling your constructor, your "copy" will be changed too (since it's not actually a copy). Of course, it could be that this is behavior you want, but probably not in this case.
Although if you never manipulate the list (i.e. add, replace, or delete items), but only refer to it or replace it wholesale, copying it is usually a waste of time and memory.
The copy made using the list() constructor is shallow. That is, the list itself is a new object, but if the original list contains references to mutable objects (such as other lists or dictionaries, or instances of most other classes), the same problem can arise if you change those objects, because they are still shared between the lists. This is an issue less frequently than you might think, but if it is, you can perform a deep copy using the deepcopy() function in the copy module.

Related

Automatically extend class with methods coming from another module

Immagine that I have defined several methods acting on an object, and I have two or more different classes that cannot inherit from the same parent, having an instance of that object. I want to automatically add all the methods to the two classes, removing the first argument (the object) and replacing it with the instance owned by the class.
Is there a way to do it?
I am sure my question is not clear, so I try to give a super simplified settings. to keep things simple the object is just a list. I hope that after the example my objective is clear! Thanks in advance for your time.
# I define some methods acting on an object (just 2 useless methods acting on a list in this example)
def get_avg(input_list):
return sum(input_list) / len(input_list)
def multiply_elements(input_list, factor):
return [i * factor for i in input_list]
Then we have 2 different classes, both have an instance of our object (the list)
class A:
list_of_apples = []
def get_list_of_apples(self):
return self.list_of_apples
class B:
"""Totally different class from A(pples), also containing a list"""
list_of_bears = []
def get_list_of_bears(self):
return self.list_of_bears
Now, to call a "list" method on the lists owned by A and B instances, I would need to do the following:
b = B()
get_avg(b.get_list_of_bears())
My goal, instead, is to automatically define some wrappers (as the following ones) which would allow me to call list methods directly from instances of A and B. Here there is an example for B:
class B:
"""Totally different class from A(pples), but containing a list"""
list_of_bears = []
def get_list_of_bears(self):
return self.list_of_bears
def get_avg(self):
return get_avg(self.list_of_bears)
def multiply_elements(self, factor):
return multiply_elements(self.list_of_bears, factor)
With the extended class, I can simply do:
b = B()
b.get_avg()
b.multiply_elements(factor=10)
I would like to automatically extend A and B.
I don't know why your classes cannot inherit from a common ancestor but one solution I can think of is to make the ancestor dynamically:
def make_ancestor():
class Temp:
def get_avg(self):
input_list = getattr(self, self.list_name)
return sum(input_list) / len(input_list)
def multiply_elements(self, factor):
input_list = getattr(self, self.list_name)
return [i * factor for i in input_list]
return Temp
class A(make_ancestor()):
list_of_apples = []
list_name = 'list_of_apples'
def get_list_of_apples(self):
return self.list_of_apples
class B(make_ancestor()):
list_of_bears = []
list_name = 'list_of_bears'
def get_list_of_bears(self):
return self.list_of_bears
Now since the parent classes are being generated dynamically your child classes don't inherit from the same parent.
As a test:
print(make_ancestor() == make_ancestor()) # False

Inherit from both 'heapq' and 'deque' in python?

I'am trying to implement a 'heapq' or a 'deque' dynamically (according to user's input)
class MyClass():
def __init__(self, choose = True ):
self.Q = []
self.add = self.genAdd(choose)
self.get = self.genGet(choose)
def genAdd(self, ch):
if(ch == True):
def f(Q, elem):
return Q.append
else:
def f(Q):
return heappush
return f
and same for 'genGet'
the execution is correct on one side (x)or the other (but not both at the same time). I get things like
TypeError: f() takes exactly 1 argument (2 given)
tried multiple inhreitance but got
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
the problem is that heapq is called with
heappush(Q, elem)
and queue with
Q.append(elem)
I hope the point is clear. I think there should be a way to fix that (maybe using lambda)
Thanks
Inheritance isn't going to help here.
First, heapq isn't even a class, so you can't inherit from it. You can write a class that wraps up its functionality (or find one on the ActiveState recipes or in a PyPI package), but you have to have a class to inherit.
But, more importantly, the whole point of inheritance is to give you an "is-a" relationship. This thing you're building isn't-a deque, or a heapq-wrapping object, it's a thing with an interface that you've defined (add and get) that happens to use either a deque or a list with heapq for implementation.
So, just do that explicitly. You're trying to define a function that either calls append on a deque, or calls heapq.heappush on a list. You're not trying to write a curried function that returns a function that does the thing, just a function that does the thing.
def genAdd(self, ch):
# As a side note, you don't need to compare == True, nor
# do you need to wrap if conditions in parens.
if ch:
def f(elem):
self.Q.append(elem)
else:
def f(elem):
heappush(self.Q, elem)
return f
There are a few other problems here. First, you definitely need to set self.Q = deque() instead of self.Q = [] if you wanted a deque. And you probably want to wrap these functions up as a types.MethodType instead of using self as a closure variable (this will work, it's just less readable, because it may not be clear to many people why it works). And so on. But this is the fundamental problem.
For example:
from collections import deque
from heapq import heappush
class MyClass(object):
def __init__(self, choose=True):
self.Q = deque() if choose else []
self.add = self.genAdd(choose)
def genAdd(self, ch):
if ch:
def f(elem):
self.Q.append(elem)
else:
def f(elem):
heappush(self.Q, elem)
return f
d = MyClass(True)
d.add(3)
d.add(2)
print(d.Q)
h = MyClass(False)
h.add(3)
h.add(2)
print(h.Q)
This will print:
deque([3, 2])
[2, 3]
That being said, there's probably a much better design: Create a class that wraps a deque in your interface. Create another class that wraps a list with heapq in your interface. Create a factory function that returns one or the other:
class _MyClassDeque(object):
def __init__(self):
self.Q = deque()
def add(self, elem):
self.Q.append(elem)
class _MyClassHeap(object):
def __init__(self):
self.Q = []
def add(self, elem):
heappush(self.Q, elem)
def MyClass(choose=True):
return _MyClassDeque() if choose else _MyClassHeap()
Now you get the same results, but the code is a lot easier to understand (and slightly more efficient, if you careā€¦).

Storing a reference to a reference in Python?

Using Python, is there any way to store a reference to a reference, so that I can change what that reference refers to in another context? For example, suppose I have the following class:
class Foo:
def __init__(self):
self.standalone = 3
self.lst = [4, 5, 6]
I would like to create something analogous to the following:
class Reassigner:
def __init__(self, target):
self.target = target
def reassign(self, value):
# not sure what to do here, but reassigns the reference given by target to value
Such that the following code
f = Foo()
rStandalone = Reassigner(f.standalone) # presumably this syntax might change
rIndex = Reassigner(f.lst[1])
rStandalone.reassign(7)
rIndex.reassign(9)
Would result in f.standalone equal to 7 and f.lst equal to [4, 9, 6].
Essentially, this would be an analogue to a pointer-to-pointer.
In short, it's not possible. At all. The closest equivalent is storing a reference to the object whose member/item you want to reassign, plus the attribute name/index/key, and then use setattr/setitem. However, this yields quite different syntax, and you have to differentiate between the two:
class AttributeReassigner:
def __init__(self, obj, attr):
# use your imagination
def reassign(self, val):
setattr(self.obj, self.attr, val)
class ItemReassigner:
def __init__(self, obj, key):
# use your imagination
def reassign(self, val):
self.obj[self.key] = val
f = Foo()
rStandalone = AttributeReassigner(f, 'standalone')
rIndex = ItemReassigner(f.lst, 1)
rStandalone.reassign(7)
rIndex.reassign(9)
I've actually used something very similar, but the valid use cases are few and far between.
For globals/module members, you can use either the module object or globals(), depending on whether you're inside the module or outside of it. There is no equivalent for local variables at all -- the result of locals() cannot be used to change locals reliably, it's only useful for inspecting.
I've actually used something very similar, but the valid use cases are few and far between.
Simple answer: You can't.
Complicated answer: You can use lambdas. Sort of.
class Reassigner:
def __init__(self, target):
self.reassign = target
f = Foo()
rIndex = Reassigner(lambda value: f.lst.__setitem__(1, value))
rStandalone = Reassigner(lambda value: setattr(f, 'strandalone', value))
rF = Reassigner(lambda value: locals().__setitem__('f', value)
If you need to defer assignments; you could use functools.partial (or just lambda):
from functools import partial
set_standalone = partial(setattr, f, "standalone")
set_item = partial(f.lst.__setitem__, 1)
set_standalone(7)
set_item(9)
If reassign is the only operation; you don't need a new class.
Functions are first-class citizens in Python: you can assign them to a variable, store in a list, pass as arguments, etc.
This would work for the contents of container objects. If you don't mind adding one level of indirection to your variables (which you'd need in the C pointer-to-pointer case anyway), you could:
class Container(object):
def __init__(self, val):
self.val = val
class Foo(object):
def __init__(self, target):
self.standalone = Container(3)
self.lst = [Container(4), Container(5), Container(6)]
And you wouldn't really need the reassigner object at all.
Class Reassigner(object):
def __init__(self, target):
self.target = target
def reassign(self, value):
self.target.val = value

How to allow __init__ to allow 1 or no parameters in python

Right now I have this class:
class foo():
def __init__(self):
self.l = []
Right now, I can set a variable to foo without an argument in the parameter because it doesn't take one, but how can I allow this continue to take no required parameters, but also put in a list if I wanted into foo()? Example:
>>> f = foo([1,2,3]) #would be legal and
>>> f = foo() # would be legal
def __init__(self, items=None):
if items is None: items = []
self.l = items
In response to #Eastsun's edit, I propose a different structure to __init__
def __init__(self, items=()):
''' Accepts any iterable
The appropriate TypeError will be raised if items is not iterable '''
self.l = list(items)
Note that lowercase l is a bad name, it can be confused with 1
def __init__(self, items=None):
self.l = items or []
Or
def __init__(self, items=None):
self.l = items if items else []
Edit in response to Dougal's comment.
(I have been learning Python about two weeks, so here is just my personal opinion. Correct me if I am wrong.)
In a programming language like python, it is hard to prevent someone passing an unwanted type of object to your function or method.
In my idea, the security way to assure the __init__ always work is like this:
def __init__(self, items = None):
if isinstance(items, Iterable):
self.l = list(items)
elif items is None:
self.l = []
else:
raise TypeError('items must be iterable')
Note: the above method always make a shallow copy if items is already a list.
class foo():
def __init__(self, items=[]):
self.l = items

Python Class design: attributes

I constructed a class:
class Foo (object):
def __init__(self,List):
self.List=List
#property
def numbers(self):
L=[]
for i in self.List:
if i.isdigit():
L.append(i)
return L
#property
def letters(self):
L=[]
for i in self.List:
if i.isalpha():
L.append(i)
return L
>>> inst=Foo(['12','ae','45','bb'])
>>> inst.letters
['ae', 'bb']
>>> inst.numbers
['12', '45']
How can I add attributes so I could do inst.numbers.odd that would return ['45']?
Your numbers property returns a list, so a numbers.odd won't work.
However, you could follow a workflow like:
define a small class Numbers, that would define two properties even and odd
For example, Numbers could take a list as argument of its __init__, the even property would return only the even number of this list [i for i in List if int(i)%2 == 0] (and odd the odd ones)...
create an instance of Numbers in your Foo.numbers property (using your Foo.List to initialize it) and return this instance...
Your Numbers class could directly subclass the builtin list class, as suggested. You could also define it like
class Numbers(object):
def __init__(self,L):
self.L = L
#property
def even(self):
return [i for i in self.L if not int(i)%2]
def __repr__(self):
return repr(self.L)
Here, we returning the representation of Numbers as the representation of its L attribute (a list). Fine and dandy until you want to append something to a Numbers instance, for example: you would have to define a Numb.append method... It might be easier to stick with making Numbers a subclass of list:
class Numbers(list):
#property
def even(self):
...
Edited: corrected the // by a %, because I went too fast and wasn't careful enough
Here's a silly example:
class mylst(list):
#property
def odd(self):
return [ i for i in self if int(i)%2 == 1 ]
class Foo(object):
def __init__(self,lst):
self.lst = list(lst)
#property
def numbers(self):
return mylst( i for i in self.lst if i.isdigit() )
a = Foo(["1","2","3","ab","cd"])
print(a.numbers)
print(a.numbers.odd)
Basically, we just subclass list and add a property odd which returns another list. Since our structure is a subclass of list, it is virtually indistinguishable from the real thing (Horray duck typing!). mylst.odd could even return a new instance of mylst if you wanted to be able to filter it again (e.g. a.numbers.odd.in_fibinocci )

Categories