can anyone please explain me this piece of code - python-3.x

I know this is a noob question but I am learning OOPs and can't able to figure the outputs got
This is the code I found and may i know how this runs?
class InstanceCounter(object):
count = 0
def __init__(self, val):
self.val = val
InstanceCounter.count += 1
def set_val(self, newval):
self.val = newval
def get_val(self):
print(self.val)
def get_count(self):
print(InstanceCounter.count)
a = InstanceCounter(5)
b = InstanceCounter(10)
c = InstanceCounter(15)
for obj in (a, b, c):
print("value of obj: %s" % obj.get_val())
print("Count : %s" % obj.get_count())

You have a class called InstanceCounter which inherits from object. The inherince from object can be removed if you use Python3. This class has an attribute count and value and some methods (functions - for example set_val).
Now you create three objects of your class and set the value of value to 5, 10 and 15 by passing these values into the constructor. You also increase the static attribute (see here) count by one with each constructor call. A static attribute is used with the notation Class.Attribute.
In the last step you loop over a list of your three objects ((a, b, c)) and store each of this object in the object obj, so obj will represent a then b and then c. So you can call the methods of this object, because your object obj has the type InstanceCounter and so obj contain the same methods and attributes.
By the way I have reworked your code so make it more understandable and use Python3 syntax.
class InstanceCounter:
count = 0
def __init__(self, val):
self.val = val
InstanceCounter.count += 1
def set_val(self, newval):
self.val = newval
def get_val(self):
return self.val
def get_count(self):
return InstanceCounter.count
a = InstanceCounter(5)
print("Count : {}".format(a.get_count()))
b = InstanceCounter(10)
print("Count : {}".format(b.get_count()))
c = InstanceCounter(15)
print("Count : {}".format(c.get_count()))
for obj in (a, b, c):
print("value of obj: {}".format(obj.get_val()))
print("Count : {}".format(obj.get_count()))
This result in the following output:
Count : 1
Count : 2
Count : 3
value of obj: 5
Count : 3
value of obj: 10
Count : 3
value of obj: 15
Count : 3
For a better understanding of static attributes:
So if you have three objects with type InstanceCounter you have three different attributes with name val because each object with type InstanceCounter contains one attribute val - an instance attribute and one identical attribute with name count - a class attribute.
count is a class attribute for the class InstanceCounter. This
attribute has the same value for all objects with type
InstanceCounter. Used with Classname.Attributename - for example InstanceCounter.count.
val is a instance attribute because each instance of a class InstanceCounter has his own value. Used with Instancename.Attributename - for example a.val.
See here for more information.

Related

change objects 'dynamically' in python

I have a number of objects with a similar name format, e.g. max_A, max_B, max_C etc. Given the value of a certain object ID, I'd like to change the value of the object named max_ID (let's say increment by 1, assuming the object already stores an int).
E.g. if ID = 'A' then I'd like to execute max_A += 1, but if ID = 'Q' then I'd like max_Q += 1.
I know I can use eval('max_'+ID) to get the value of max_ID, but how can I change the value?
You can represent the objects like bellow and use endswith function to find the appropriate object to be incremented:
class Data:
def __init__(self, name, value):
self.name = name
self.value = value
max_A = Data("max_A", 1)
max_B = Data("max_B", 2)
max_C = Data("max_C", 3)
obj_list = [max_A, max_B, max_C]
def increment_object_value(ending: str, objects: list):
for obj in objects:
if obj.name.endswith(ending):
obj.value += 1
increment_object_value("A", obj_list)
increment_object_value("B", obj_list)
increment_object_value("C", obj_list)

Creating new object keeps data even with default value

I am struggling to understand why instance C keeps data of instance B, even though I initialized the instance variable var with the default empty list. Why is the default argument "var = []" ignored?.
class A():
def __init__(self, var=[]):
self.var = var
B = A()
B.var.append(3)
C = A()
print(C.var)
The print retuns
[3]
Even stranger is this:
class A():
def __init__(self, var=[2]):
self.var = var
B = A()
B.var.append(3)
C = A()
print(C.var)
prints
[2, 3]
How can the statement self.var = var append to the list from the front?
According to what's given here
A Python variable is a symbolic name that is a reference or pointer to an object. Once an object is assigned to a variable, you can refer to the object by that name. But the data itself is still contained within the object.
B = A()
B.var.append(3)
Here, A's reference is passed to B. So they point to the same data, but are just called by different names. So whatever operation you perform on B, you also perform on A.
Hence, later when you assign A to C, the same data is referenced by C.
If you don't want that to happen, use deepcopy:
class A():
def __init__(self, var=[]):
self.var = var
import copy
B = copy.deepcopy(A())
B.var.append(3)
C = A()
print(C.var)

How to define external overloading for PriorityQueue to manage heterogeneous type elements?

I want to store pairs (prio,val) of heterogeneous types in a python PriorityQueue. Here val can be either a string or a custom class object.
When prio are equals, the PriorityQueue (actually heapq) implementation comes to compare the second member, thus comparing a string and a custom objects.
Depending on the order the elements were stored, it comes to compare either:
custom_object < string
string < custom_object
Case 1. translates to custom_object.__lt__(string) and this is fine, as i can overload the def __lt__:method in my custom class.
Case 2. : i am stuck because i do not know how to redefine __lt__ for strings.
Below is a MWE that inserts 3 elements with equal priorities (the value 1).
Running it results in the error message:
TypeError: '<' not supported between instances of 'str' and 'C'
import queue
class C:
def __init__(self,value):
__value__ = value
def __lt__(selfself,other):
return 0
q = queue.PriorityQueue()
tuple1=(1,"t1")
tuple2=(1,C("t2"))
tuple3=(1,"t3")
q.put(tuple1)
q.put(tuple2)
q.put(tuple3)
print( q.get())
If a does not supply an implementation for a < b, then Python will look for an implementation of b > a next.
class C:
def __lt__(self, other):
return 0
def __gt__(self, other):
return 1
c = C()
print(c < 'a') # 0
print('a' < c) # 1

How to override the setters and getters of the property function in python?

I'm creating members using the property function, but when I'm trying to override the setters and getters of those properties, it always reference the setters and getters of the parent class:
class A():
def evaluate(self):
return 'A'
value = property(evaluate)
class B(A):
def evaluate(self):
return 'B'
b = B()
print(b.value) # I get 'A'
I tried to put the definition of the value member inside the constructor of the parent such as:
self.value = property(self.evaluate)
but when accessing the value of an object it returns a property object not the actual value such as : 'A' or 'B.
<property object at 0x7fecd01a88b8>
I know how to workaround this issue, but I want to know if it is possible to solve it using the property function/decorator and without code repetition.
The problem is that the expression property(evaluate) binds the property to the evaluate function that is in scope when the class body for A is executing. To do what you want you would have to delay accessing evaluate until the property is being used.
This would work, but if we knew why you are trying to do this there is probably a much better way:
class A():
def evaluate(self):
return 'A'
value = property(lambda self: self.evaluate())
class B(A):
def evaluate(self):
return 'B'
b = B()
print(b.value) # prints 'B'
If all you want to do is return a different constant string for A or B then you don't need a property at all:
class A():
value = 'A'
class B(A):
value = 'B'
b = B()
print(b.value)
and if you really need a property then just redefine the property in the subclass:
class A():
#property
def value(self):
return 'A'
class B(A):
#property
def value(self):
return 'B'
b = B()
print(b.value)

I have two classes(A and B), and I'm trying to use a method from A in B. The method in A, simply finds the index of an item in a list:

I have three classes(A, I and B), where A is inheriting from I. I'm trying to use a method ,from A, in B. The method in A, simply finds the index of an item in a list. I have:
File 1:
class I:
def__init__(self,s):
self.s = s
class A(I):
def __init__(self,n):
self.n = n
self.lst = []
for i in range(n):
self.lst.append([])
.....
def get_item_location(self, item):
for index in range(len(self.lst)):
if item in self.lst[index]:
return index
File 2:
from A import classA
class B:
def __init__(self,n):
self._model = A(n)
def something(self, dest_point):
print (self._model.get_item_location(self._item))
Where the type of self._item is Class I, now this prints None for me, where I expect it to return the index number of the list which the item is inside it, and the item is inside the list. When I used get_item_location function, it gives me an integer, but when Class B is using it, it returns None. I beleive it's something to do with that self._item, but I have not come up with any solution yet. I'd really appreciate it if someone could help.

Resources