Here is part of my code:
some_item = target_item
first_item = my_list[0]
print first_item
print some_item
print my_list.index(first_item)
print my_list.index(some_item)
print "Finished"
exit()
And here is what I get:
<models.adb.ADB object at 0x7f1ec7654b50>
<models.seb.SEB object at 0x7f1ec7654b90>
0
0
Finished
My items in my_list are class objects.
Could someone please explain this behavior?
It depends on the comparison implemented for ADB and SEB, probably by implementing the __eq__ operator for this classes.
When python will look for the instance of first_item and some_item on the list, he will use this operator to determine if the i-th element on the list is this element, sweeping for every i.
Therefore, if the implementation is like
class Parent:
def __init__(self):
self.x = 0
def __eq__(parentObj):
return self.x == parentObj.x
class ADB (Parent):
def __init__(self): super.__init__()
class SEB (Parent):
def __init__(self): super.__init__()
it would result in ADB() == SEB(), therefore, causing the objects to both "match" the first list's element when being compared to it, but being different objects at the same time.
Note that same can go for this as well, used inheritance for simplification of the example.
class ADB (Parent):
def __init__(self):
self.x = 0
def __eq__(obj):
return self.x == obj.x
class SEB (Parent):
def __init__(self):
self.x = 0
def __eq__(obj):
return self.x == obj.x
Related
Consider the following code:
class A():
def __init__(self, thing):
self.thing = thing
def do_something(self):
if self.thing > 0:
print('thing is positive')
else:
print('thing is not positive')
def some_function(a):
if a.thing > 0:
print('this thing is positive')
else:
print('this thing is not positive')
class B(A):
#property
def thing(self):
return 0
#thing.setter
def thing(self, val):
pass
# Purposely don't want to override A.do_something
a = A(5)
print(a.thing) # 5
a.do_something() # thing is positive
some_function(a) # this thing is positive
isinstance(a, A) # True
b = B(5)
print(b.thing) # 0
b.do_something() # thing is not positive (!!! - not what we want - see below)
some_function(b) # this thing is not positive
isinstance(b, A) # True
Suppose that do_something is a complicated function which we don't want to override. This could be because it is in an external package and we want to be able to keep using the latest version of this package containing A without having to update B each time. Now suppose that an outside function accesses a.thing by referencing it directly. We want B to extend A so that this external function always sees b.thing == 0. However, we want to do this without modifying the behaviour of internal methods. In the example above, we want to modify the behaviour of some_function, but we do this at the cost of also changing the behaviour of the internal method b.do_something.
The obvious way to fix this would be to have the external functions some_function use a get_thing() method. But if these external functions have been already written in another package modifying these is not possible.
Another way would be to have B update the value of self.thing before calling the parent class' method,
class B(A):
def __init__(self, thing):
self.thing = 0
self._thing = thing
def do_something(self):
self.thing = self._thing
rval = super().do_something()
self.thing = 0
return rval
however this seems clunky and if the developer of A adds new methods, then B would change the behaviour of these methods if it is not updated.
Is there a best practice on how to go about extending a class like this which allows use to override __getattribute__ if called by an external function, but without changing any internal behaviour?
I think you can set class B like the following to achieve what you want:
class B:
def __init__(self, thing):
self.thing = 0
self._a = A(thing)
def __getattr__(self, name):
return getattr(self._a, name)
The full code is below:
class A:
def __init__(self, thing):
self.thing = thing
def do_something(self):
if self.thing > 0:
print('thing is positive')
else:
print('thing is not positive')
def some_function(a):
if a.thing > 0:
print('this thing is positive')
else:
print('this thing is not positive')
class B:
def __init__(self, thing):
self.thing = 0
self._a = A(thing)
def __getattr__(self, name):
return getattr(self._a, name)
if __name__ == '__main__':
a = A(5)
print(a.thing) # 5
a.do_something() # thing is positive
some_function(a) # this thing is positive
b = B(5)
print(b.thing) # 0
b.do_something() # thing is positive
some_function(b) # this thing is not positive
From an existing code, I need to create instance from a class within another class while lots of information that are needed for initializing the called class, are contained in the caller one.
A way to pass some attributes of a caller class to the called class can be like in the following example passing self as argument and it does what exactly is expected, bu I wondered if it is the correct or whether is there a better way to do so?
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = None
self.j = None
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
Your class does what you think it is doing, except when it might not.
(btw your code does not run: you don't define B_Obj)
See the extra code I've added at the end:
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = 0
self.j = 0
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
A_obj.x = 2 # Now update the x member
print(A_obj.x, A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
2 1 10
Here A_obj.x has changed, but the instance of B has held onto the previous values.
In my example below in Python, object x 'has-an' object y. I'd like to be able to invoke methods of x from y.
I'm able to achieve it using #staticmethod, however I'm discouraged to do that.
Is there any way(s) to reference the whole Object x from Object y?
class X(object):
def __init__(self):
self.count = 5
self.y = Y() #instance of Y created.
def add2(self):
self.count += 2
class Y(object):
def modify(self):
#from here, I wanna called add2 method of object(x)
x = X()
print x.count
>>> 5
x.y.modify()
print x.count
>>> # it will print 7 (x.count=7)
Thanks in advance.
You need to store a reference to the object which has the instance of a Y object:
class X(object):
def __init__(self):
self.count = 5
self.y = Y(self) #create a y passing in the current instance of x
def add2(self):
self.count += 2
class Y(object):
def __init__(self,parent):
self.parent = parent #set the parent attribute to a reference to the X which has it
def modify(self):
self.parent.add2()
Example usage:
>>> x = X()
>>> x.y.modify()
>>> x.count
7
Maybe it's possible for you to use class inheritance? For example:
class X(object):
def __init__(self):
self.count = 5
def add2(self):
self.count += 2
class Y(X):
def __init__(self):
super(Y, self).__init__()
def modify(self):
self.add2()
y = Y() # We now create an instance of Y which is a child class of 'super' class X
y.modify()
print(y.count) # 7
Sorry if this is a silly question, but I could not make my mind up how it could work.
I defined an iterator which has a structure like that (it is a bit more complicated, but the model will do the job):
class MyIterator ():
def __init__(self):
print ('nothing happening here')
def __iter__ (self):
self.a_list=[x for x in range (10)]
for y in a_list:
print(y)
def __next__ (self):
self.a_list = [x+1 for x in self.a_list]
for y in a_list:
print (y)
But how can I loop over it? Do I always have to call the methods manually? Or am I simply using the wrong tool?
One of the problems is that you are mixing two concepts: And
iterable defines an __iter__() method that returns an iterator,
but no __next__() method. An iterator in turn defines a
__next__() method, and a trivial __iter__() implementation that
returns self. Something like this:
class Iterable(object):
def __iter__(self):
return Iterator()
class Iterator(object):
def __init__(self):
self.i = 0
def __iter__(self):
return self
def __next__(self):
result = self.i
self.i += 1
return result
An alternative is to define the __iter__() method of the iterable as a generator function:
class Iterable(object):
def __iter__(self):
i = 0
while True:
yield i
i += 1
class TestClass(object):
def __init__(self):
self.value = 100
self.x = lambda: self.value.__add__(100)
self.run()
def run(self):
self.x()
print self.value
t = TestClass()
#Output: 100
I would like to able to define a lambda function such as the one in TestClass and have it alter an instance variable. It would seem that the way the lambda is constructed means that it does not modify the original value. I suspect that this to do with Python's reference strategy which I do more or less understand.
So accepting the flaws in what I have done, is there a similar way to get similar functionality? I ultimately need to define many methods like x and intend to keep them in a dictionary as they will form a simple instruction set. As far as I can tell I need either to use lambdas or exec to do what I want.
__add__ is not inplace, so the return value of TestClass.x is self.value + 100, but self.value is not altered. Try this:
import random
HATE_LAMBDAS = random.choice(True, False)
class TestClass(object):
def __init__(self):
self.value = 100
if HATE_LAMBDAS:
def x():
self.value += 100
self.x = x
else:
self.x = lambda: setattr(self, "value", self.value + 100)
self.run()
def run(self):
self.x()
print self.value
t = TestClass()
#Output: 200
Use the setattr to increment the value while still using a lambda. Beware however, lambda's in python are one of its worst features. However, both methods work.
Edit
Just remebered something that you might find usefull! The standard library has a module called operator which implements standard operators as functions. If you plan on using lambdas a lot, you might like to investigate it.
I'm just guessing at what you want to accomplish, but no lambdas
necessary.
class TestClass(object):
def __init__(self):
self.value = 100
self.methods = { 'add': self.w,
'subtract': self.x,
'mult': self.y,
'div': self.z,
}
self.run()
def w(self): self.value += 100
def x(self): self.value -= 100
def y(self): self.value *= 100
def z(self): self.value /= 100
def run(self):
self.x()
print self.value