Passing values between class and instance - python

class MyClassA(object):
def __init__(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
c = MyClassC() #Initializied MyClassC to be ready for receive the value p
self.x = b.f #To get back the value f from MyClassB
print(self.x)
self.x1 = c.p #To get back the value f from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self, M):
self.f = M * 10 # f will contain (the value entry from MyClassA *10)
c = MyClassC(self.f) #To pass variable f to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
Above is my sample code, first of all it will ask for a value and store it into variable named entry.
Then the second class named MyClassB will recover the value inside entry, after processing the entry value, a new one will be stored into new variable named f which will be passed to third class named MyClassC then also back to first class.
Finally the third class does some processing of the f value and stores it into yet another variable p.
That's how my code should work when the user runs the program, and this is what it would look like:
Insert a value ::: 9 (assume the user typed 9 here)
so the output should be:
90
90.1
Unfortunately my problem is that passing the value from MyClassC to myClassA doesn't work.
It says I must pass it two argument from the first class but it'a going to get the value after executing the 2st class.
I think that I have problem with initializing instances, could someone correct my code to work the way I described?

The problem you're having is because there are two independent instances of MyClassC being created, one in MyClassA.__init__() and a separate one in MyClassB.__init__().
The easy way to fix it — not necessarily the best — would be to make MyClassB.__init__() store the MyClassC instance it creates in yet another instance attribute, and then refer to the attribute of that object when you want to retrieve the value of p.
Here's what I mean:
class MyClassA(object):
def __init__(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) # To pass the variable entry to class MyClassB
####### c = MyClassC() # Initializied MyClassC to be ready for receive the value p
self.x = b.f # To get back the value f from MyClassB
print(self.x)
self.x1 = b.c.p # To get back the value p from MyClassC instance created in MyClassB
print(self.x1)
class MyClassB(object):
def __init__(self, M):
self.f = M * 10 # f will contain (the value entry from MyClassA *10)
self.c = MyClassC(self.f) # Pass variable f to class MyClassC and save instance
class MyClassC(object):
def __init__(self, passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()

In line
c = MyClassC()
it should be
c = MyClassC(b.f)

Or you could set the value p to the class MyClassC
class MyClassC(object):
def __init__(self, passedVar):
MyClassC.p = passedVar + 0.1
but keep in mind that this situation can happen
class T(object):
def __init__(self, x):
T.x = x
if __name__ == '__main__':
t1 = T(3)
print t1.x, T.x
t1.x = 1
print t1.x, T.x
t2 = T(2)
print t1.x, t2.x, T.x
# output:
3 3
1 3
1 2 2

Related

Python: Create a single object for a set of arguments to the constructor [duplicate]

I defined a class named Experiment for the results of some lab experiments I am conducting. The idea was to create a sort of database: if I add an experiment, this will be pickled to a db before at exit and reloaded (and added to the class registry) at startup.
My class definition is:
class IterRegistry(type):
def __iter__(cls):
return iter(cls._registry)
class Experiment(metaclass=IterRegistry):
_registry = []
counter = 0
def __init__(self, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC):
hashdat = fn.hashfile(pathresult)
hashpro = fn.hashfile(pathprotocol)
chk = fn.checkhash(hashdat)
if chk:
raise RuntimeError("The same experiment has already been added")
self._registry.append(self)
self.name = name
[...]
While fn.checkhash is a function that checks the hashes of the files containing the results:
def checkhash(hashdat):
for exp in cl.Experiment:
if exp.hashdat == hashdat:
return exp
return False
So that if I add a previously added experiment, this won't be overwritten.
Is it possible to somehow return the existing instance if already existant instead of raising an error? (I know in __init__ block it is not possible)
You can use __new__ if you want to customize the creation instead of just initializing in newly created object:
class Experiment(metaclass=IterRegistry):
_registry = []
counter = 0
def __new__(cls, name, pathprotocol, protocol_struct, pathresult, wallA, wallB, wallC):
hashdat = fn.hashfile(pathresult)
hashpro = fn.hashfile(pathprotocol)
chk = fn.checkhash(hashdat)
if chk: # already added, just return previous instance
return chk
self = object.__new__(cls) # create a new uninitialized instance
self._registry.append(self) # register and initialize it
self.name = name
[...]
return self # return the new registered instance
Try to do it this way (very simplified example):
class A:
registry = {}
def __init__(self, x):
self.x = x
#classmethod
def create_item(cls, x):
try:
return cls.registry[x]
except KeyError:
new_item = cls(x)
cls.registry[x] = new_item
return new_item
A.create_item(1)
A.create_item(2)
A.create_item(2) # doesn't add new item, but returns already existing one
After four years of the question, I got here and Serge Ballesta's answer helped me. I created this example with an easier syntax.
If base is None, it will always return the first object created.
class MyClass:
instances = []
def __new__(cls, base=None):
if len(MyClass.instances) == 0:
self = object.__new__(cls)
MyClass.instances.append(self)
if base is None:
return MyClass.instances[0]
else:
self = object.__new__(cls)
MyClass.instances.append(self)
# self.__init__(base)
return self
def __init__(self, base=None):
print("Received base = %s " % str(base))
print("Number of instances = %d" % len(self.instances))
self.base = base
R1 = MyClass("apple")
R2 = MyClass()
R3 = MyClass("banana")
R4 = MyClass()
R5 = MyClass("apple")
print(id(R1), R1.base)
print(id(R2), R2.base)
print(id(R3), R3.base)
print(id(R4), R4.base)
print(id(R5), R5.base)
print("R2 == R4 ? %s" % (R2 == R4))
print("R1 == R5 ? %s" % (R1 == R5))
It gives us the result
Received base = apple
Number of instances = 2
Received base = None
Number of instances = 2
Received base = banana
Number of instances = 3
Received base = None
Number of instances = 3
Received base = apple
Number of instances = 4
2167043940208 apple
2167043940256 None
2167043939968 banana
2167043940256 None
2167043939872 apple
R2 == R4 ? True
R1 == R5 ? False
Is nice to know that __init__ will be always called before the return of the __new__, even if you don't call it (in commented part) or you return an object that already exists.

access list of instantiated objects form within the object

I want to access a list of instantiated objects with a method inside the objects' class in Python 3.
I assume I can't give the the whole list to the object, as it would contain itself.
Concretely: how do I access cells[] from within the class cell? Or is this the wrong way to think about it? the end goal is to easily program cell behavior like cell.moveUp() -- all cells are connected to 8 neighbors.
I am missing something, probably since I don't have much experience in python/programming.
#!/usr/bin/env python3
import random
class cell:
""" cell for celluar automata """
def __init__(self, n=0, nghbrs=[], a=0.00, b=0.00, c=0.00):
self.n = n #id
self.nghbrs = nghbrs #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
def growUp(self):
if self.a > .7: # if cell is "bright"
cells[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
def main():
iterations = 4
links = initLinks() # 150 random links [link0, link2, ... , link7]*150
val1 = initval() # 150 random values
cells = [cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])for nghbrs in enumerate(
links)] # create cell objects, store them in cells and init. neigbours , a
for i in range(iterations): # celluar automata loop
for c in cells:
c.growUp()
def initLinks(): #for stackoverflow; in real use the cells are arranged in a grid
nghbrs = []
for i in range(150):
links = []
for j in range(8):
links.append(random.randrange(0, 150))
nghbrs.append(links)
return nghbrs
def initval():
vals = []
for i in range(150):
vals.append(random.random())
return vals
if __name__ == "__main__":
main()
run as is cells cannot be accessed in the method growUp():
NameError: name 'cells' is not defined
You could make a CellsList class (subclass of list) that has a method which you call to get a new cell.
class CellsList(list):
def add_cell(self, *args, **kwargs):
"""
make a cell, append it to the list, and also return it
"""
cell = Cell(cells_list=self, *args, **kwargs)
self.append(cell)
return cell
then in the cell itself (I've renamed the class Cell and above I am using cell as in instance variable in accordance with usual capitalisation convention) you have an attribute cells_list where you store a back-reference to the cells list. (I'm also fixing the initialisation of nghbrs to avoid a mutable object in the defaults.)
class Cell:
""" cell for celluar automata """
def __init__(self, n=0, nghbrs=None, a=0.00, b=0.00, c=0.00, cells_list=None):
self.n = n #id
self.nghbrs = (nghbrs if nghbrs is not None else []) #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
self.cells_list = cells_list
def growUp(self):
if self.a > .7: # if cell is "bright"
self.cells_list[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
And then inside main, you can change your current code that instantiates Cell (or what you call cell) directly (your line with cells = ...) to instead use cells.add_cell
cells = CellsList()
for nghbrs in enumerate(links):
cells.add_cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])
Here we're not actually using the value returned by add_cell, but we return it anyway.
Note: this approach allows you to maintain multiple independent lists of cells if you wish, because it does not rely on any class variables to hold the list -- everything is held in instance variables. So for example, your main program could model multiple regions, each containing a different cells list, by instantiating CellsList more than once, and calling the add_cell method of the relevant CellsList instance to create a new cell.
You can track instances of cell() by making the cells list a static variable of your class, which can be easily accessed from within all instances of the class.
import random
class cell:
""" cell for celluar automata """
cells = []
def __init__(self, n=0, nghbrs=[], a=0.00, b=0.00, c=0.00):
self.n = n #id
self.nghbrs = nghbrs #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
def growUp(self):
if self.a > .7: # if cell is "bright"
self.cells[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
def main():
iterations = 4
links = initLinks() # 150 random links [link0, link2, ... , link7]*150
val1 = initval() # 150 random values
cell.cells = [cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])for nghbrs in enumerate(
links)] # create cell objects, store them in cells and init. neigbours , a
for i in range(iterations): # celluar automata loop
for c in cell.cells:
c.growUp()
def initLinks(): #for stackoverflow; in real use the cells are arranged in a grid
nghbrs = []
for i in range(150):
links = []
for j in range(8):
links.append(random.randrange(0, 150))
nghbrs.append(links)
return nghbrs
def initval():
vals = []
for i in range(150):
vals.append(random.random())
return vals
if __name__ == "__main__":
main()

How to store a variable of an instance of a class in an instance of another class

I have two self-defined classes, one is a child of the gurobipy-class and is supposed to make a lp-model. The other one I made to store variables. Now I want to store some variables of the model class in the variables class.
Here are my classes:
class Model(gb.Model):
def __init__(self):
super().__init__()
def create_model(self, var):
dim = var.dimensions()
# variables
x = self.addVars(dim[0], dim[1], vtype=gb.GRB.BINARY, name="x")
D_l = self.addVars(dim[1], lb=0, name='D_l')
D_max = self.addVar(lb=0, name='D_max')
# objective
self.setObjective(D_max, gb.GRB.MINIMIZE)
# constraints
self.addConstrs((x.sum(i, '*') == 1 for i in range(dim[0])), name="b")
self.addConstrs((D_max >= D_l[l] for l in range(dim[1])), name="c")
self.addConstrs((D_l[l] >= var.dist_mat()[i, j] * (x[i, l] + x[j, l] - 1) for i in range(dim[0])
for j in range(dim[0]) for l in range(dim[1])), name='a')
self.update()
class Variables:
def __init__(self, data, number_of_clusters, neighbourhood_size):
self.data = data
self.number_of_clusters = number_of_clusters
self.neighbourhood_size = neighbourhood_size
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
def dist_mat(self):
from scipy.spatial import distance_matrix
return distance_matrix(self.data, self.data)
def dimensions(self):
from numpy import shape
data_objects = shape(self.data)[0]
number_of_clusters = self.number_of_clusters
return data_objects, number_of_clusters
def print_dist_mat(self):
print(self.dist_mat())
It's the x-variable I want to store. First, I tried to store it in the instance of the Model-class. I added to the init-function this line self.x = None. But it raise an AttributeError: 'x' is not a model attribute. I guess, this is because the gurobipy-class doesn't have a x attribute.
Next, I wanted to store it in an instance of the variable-class. I wanted to write a function in the model class, which should do the trick. This is the function:
def store_x(self, var):
var.x = self.x
Then, I got this error: gurobipy.GurobiError: Unable to retrieve attribute 'x', I can't understand why.
I can't even access the x-variable from outside the function. I can print it from inside the function, but nothing more. The problem is, I need this x-variable in a later stage.
How can I achieve this? How can I store the x-variable to access it at a later point? It doesn't have to be in the variable-class, any other solution is appreciated as well.
Ok first off I see an issue with Your code:
def store_x(self, var):
var.x = self.x
It Needs to be changed to :
def store_x(self, var):
self.x = var.x
This is because whatever you send in the 'var' parameter will only be a copy of whatever you actually passed. And then its scope will only last to the end of that store_x method. So instead you pass that copy and tell your variable class instance to store it inside it's x value.
As for the error you got with:
self.x = None # inside your Model class
I'm not sure why, as I tried the following and it runs fine:
class Variables:
def __init__(self):
self.data = data
self.number_of_clusters = number_of_clusters
self.neighbourhood_size = neighbourhood_size
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
So I'm updating my answer with a deeper example after getting clarification on what is needed. Here are two skeleton classes named 'Variables', 'Model', respectivly:
class Variables:
def __init__(self):
self.data = None
self.number_of_clusters = None
self.neighbourhood_size = None
self.variables_before = None
self.variables_now = None
self.ofv_before = None
self.ofv_now = None
self.x = None
def get_x(self,modelx):
self.x = modelx
class Model:
def __init__(self):
self.x = ({}, {})
# create your class instances here
newVar = Variables()
newModel = Model()
# one way to assign your Variable class's x attribute the tuple dict in question.
newVar.x = newModel.x
# alternate way is to create a function inside your Variable class that updates the x variable based on the argument you send it.
newVar.get_x(newModel.x)

I want to access the value of Gurobi Variable

I want to access the value of gurobi variable self.a and self.b here but its returning 0.0. How can I access the value of these variables. The code is below
from gurobipy import GRB, Model
class abc(object):
def __init__(self):
self.model = Model()
def creatingvarriables(self):
self.a = self.model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="y_")
self.b = self.model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="q_")
self.model.update()
def constraint1(self):
lhs1 = self.model.getVarByName("y_")
lhs1 = 2
rhs1 = self.model.getVarByName("q_")
rhs1 = 3
self.model.update()
self.model.addConstr(lhs1, GRB.LESS_EQUAL, rhs1)
def printvalues(self):
self.model.optimize()
#self.model.printAttr('')
print self.a.X
print self.b.X
if __name__ == "__main__":
newobject = abc()
newobject.creatingvarriables()
newobject.constraint1()
newobject.printvalues()
You can access it's value by calling the variable's *.X attribute, as explained in GUROBI's documentation. For reference, the direct link to the attribute: X Attribute
You are correctly accessing the variable values through the X attribute. The reason why you get confused by the zero solution is an error in the method constraint1:
lhs1 = self.model.getVarByName("y_")
lhs1 = 2
rhs1 = self.model.getVarByName("q_")
rhs1 = 3
self.model.update()
self.model.addConstr(lhs1, GRB.LESS_EQUAL, rhs1)
First you assign to lhs1 and rhs1 references to the created variables, but then you overwrite them with numbers. Effectively you are adding the constraint 2 <= 3, which is satisfied independently of y_ and q_. Hence, setting y_ and q_ to zero is an optimal solution.

Python : Passing values between class and instance and methods

A few days ago, I asked about passing values between instances of classes here is my post here
That problem was easy to fix especially the movement.
But now I can't pass objects between methods.
Example code:
class MyClassA(object):
def function1(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
d = MyClassB()
d.function2()
c = MyClassC(b.k) #Initializied MyClassC to be ready for receive the value p
self.x = d.f #To get back the value k from MyClassB function2()
print(self.x)
self.x1 = c.p #To get back the value k from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self,M):
self.f = M
self.k = 0
def function2(self):
self.k = self.f * 10 # k will contain (the value entry from MyClassA *10)
c = MyClassC(self.k) #To pass variable k to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
h.function1()
Otherwise whenever i try to work with instanace it gonna work right but between methods not that such fixed.
as last time this my code should give this way of result :
Insert a value ::: 9 (assume the user typed 9 here)
so the output should be:
90
90.1
here my code complation say
d = MyClassB()
TypeError: __init__() takes exactly 2 arguments (1 given)
Any way I can fix my code > It doesn't need to work only with instances; I need some function inside some class
You need to pass something to the constructor for MyClassb()...
Ok My problem is
d = MyClassB()
d.function2()
Statu is Fixed now, i got the way !!!
Correct code is this way :
class MyClassA(object):
def function1(self):
entry = input("Insert a value ::: ")
b = MyClassB(entry) #To pass the variable entry to class MyClassB
b.function2()
c = MyClassC(b.k) #Initializied MyClassC to be ready for receive the value p
self.x = b.f #To get back the value k from MyClassB function2()
print(self.x)
self.x1 = c.p #To get back the value k from MyClassC
print(self.x1)
class MyClassB(object):
def __init__(self,M):
self.f = M
def function2(self):
self.k = self.f * 10 # k will contain (the value entry from MyClassA *10)
c = MyClassC(self.k) #To pass variable k to class MyClassC
class MyClassC(object):
def __init__(self,passedVar):
self.p = passedVar + 0.1 # p will contain (the value entry from MyClassB + 0.1)
h = MyClassA()
h.function1()

Categories

Resources