I asked about this yesterday, but I botched writing up my question so much that by the time I realized what I typed, all the replies were solutions to a different miss-worded problem I didn't have. Sorry for the foolish type up last time.
I have two Classes, and I want them to able to share a common list without having to pass it as a parameter. I also want to create a method that will scramble that list, and I want the list to be the same newly scrambled list in both Class A and Class B.
I figured this was a case for inheritance, so I made a Parent Class and set the list as a class attribute and made a method to scramble, but the list variable is oddly enough being now treated as an instance variable of the children.
class A:
lst = []
target = 0
def generateNewLst(self, randomRange, listSize):
self.lst = [random.randint(*randomRange) for i in range(listSize)]
class B(A):
pass
class C(A):
pass
My inherited method works just fine:
a = B()
a.generateNewLst((0, 10), 3)
a.lst # => [2,5,7]
but when I create another B:
b = B()
b.lst # => [] not shared when I want it to be
This CANNOT be solved with a class attribute in B, because that won't solve the more important below issue...
c = C()
c.lst # => [] not shared when I want it to be
TL;DR: I want a Class attribute that shares between every instance of both classes. I want a.lst == b.lst == c.lst every time I run generateNewList on ONE of any of those instances.
How should I reorganize my setup to work the way I want it to?
You need a static variable. To do so make the method generateNewLst static and let him update the static variable lst and not a member variable lst that would belong to the instance of the class and not to the class itself.
class A:
lst = []
#staticmethod
def generateNewLst(randomRange, listSize):
A.lst = [random.randint(*randomRange) for i in range(listSize)]
class B(A):
pass
class C(A):
pass
Then once you generate the lst you will have it for all classes.
a = B()
B.generateNewLst((0, 10), 3)
# the same list is available for all classes
print(A.lst)
print(B.lst)
print(C.lst)
Related
I want to call a function from a class A inside another class B. However, it should be called for an object of A. I mean if I have something like this:
class A:
def __init__(self, ....):
self.valuechanged=False
# do something
objectfromb=B()
self.somearray.append(objectfromb)
def updateevent(self):
self.valuechanged=True
# do some things if update event triggered
class B:
def __init__(self,...):
self.somevalue=0
self.someothervalue=1
# do something
def updatesomevalue(self,somenewvalue):
self.somevalue=somenewvalue
# !!! HERE SHOULD BE A CALL TO CLASS A FUNCTION updateevent
And in my code I use the classes like this:
a=A()
Then i would have a list somearray in a (a.somearray) which contains an object of B. So if I want to update this object B with:
a.somearray[0].updatesomevalue(10)
Then there should not only be a new value for a.somearray[0].somevalue but also the function update event of class A should trigger changing a. How can I do that?
There are two ways I can think of to achieve this without invoking any special magic.
The first is to have objects of type B know what object A they belong to so that they can call updateevent on it. This isn't a way I'm generally a fan of as there's extra admin work to do when moving instances of B between instances of A and such. If that's not a concern then it may be the best way. You'd do that something like this (with a method on A to create a B and set the correct parent for convenience):
class A:
valuechanged=False
somearray=[]
def add_b(self):
b = B(self)
somearray.append(b)
return b
def updateevent(self):
self.valuechanged=True
class B:
somevalue=0
someothervalue=1
def __init__(self, parent):
self.parent = parent
def updatesomevalue(self,somenewvalue):
self.somevalue=somenewvalue
self.parent.updateevent()
The second is to provide a method on A that does both tasks. This is only suitable if 1) you know A will always contains instances of B and only B and 2) B's interface is relatively small (to avoid providing lots of methods of this type on A). You would implement this as something like:
class A:
valuechanged=False
somearray=[]
def updatesomevalue(self, index, new_value):
somearray[index].updatesomevalue(new_value)
self.updateevent()
def updateevent(self):
self.valuechanged=True
class B:
somevalue=0
someothervalue=1
def updatesomevalue(self,somenewvalue):
self.somevalue=somenewvalue
Something I haven't addressed is that somearray, somevalue, etc are all being created as class attributes in your example (i.e. they will be shared among all instances, instead of each instance having its own ones). This is likely not what you wanted.
I have a generic class definition, something like this -
class Foo(object):
property = 1
def __init__(self, ...):
...
I wish to create a large number of classes, each of which has a different value of property, and store these classes in a list. The classes in this list will be subsequently used to create several objects.
What is the best way to do this?
While I doubt that there isn't a better solution to whatever your underlying problem might be, you can create classes dynamically using type:
class Foo(object):
def __init__(self, x):
self.x = x
# class-name---vvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvv--class-attributes
klasses = [type('Foo{}'.format(n), (Foo,), {'property': n}) for n in range(5)]
# parent-classes ^^^^^^
klasses[4]
# <class '__main__.Foo4'>
klasses[4].property
# 4
inst = klasses[4]('bar')
inst.x
# 'bar'
c = []
for i in range(5):
class X(object):
property = i
def __init__(self):
print(self.property)
c.append(X)
c[0]() # will print 0
c[4]() # will print 4
But this has a bunch of drawbacks. I also think that the comment given below the question is remarkable. Very likely you strive for a solution which is not the best for your original problem.
If you really want to do it, then sure you can create classes dynamically using type
class BaseClass(object):
# the code that needs to be common among all classes
properties = [1, 2, 3]
classes = [type("class_{0}".format(i), (BaseClass,), {'property': property}) for i, property in enumerate(properties)]
However, you probably need to think about your design. I don't know about the problem you want to solve, but perhaps keeping the property variable as instance one would make more sense.
I think the best way would just be to iterate i=0 to n-1, appending a new object to the end of the list. You can then use i to index into the list and change the value of property that way.
Consider the following situation:
class A:
def __init__(self):
self.b_list = []
def add_element(b)
self.b_list.append(b)
class B:
def __init__(self,x):
self.x = x
class C:
def __init__(self,a,other_data):
self.a = a
def find_new_b(self):
....
def solve(c):
return c.find_new_b()
Each instance of class A has a list of instances of class B, that are added in an incremental way.
I need to iterate over all the instances of class A and find for each of them a new element of class B.
I'm using multiprocessing to do that
list_of_c_elements = [...]
pool = multiprocessing.Pool()
results = pool.map(solve, list_of_c_elements)
The problem
In results I have a list of results and I would like to understand of which instance of class A the new instance of class B belongs. Each instance of class B is generic, and I would like to keep the two classes decoupled.
Considered solution
Change solve() to:
def solve(c):
return (c.a, c.find_new_b())
I have to compare all the elements of class A I have with the one returned (very inefficient).
I cannot do something like:
for output in results:
output[0].add_element(output[1])
since the instance of class A returned is another instance.
Is there a more efficient way to achieve my goal?
C could additionally hold id(a) in a member and you can generate an index dictionary {id(a): a} if necessary. Be aware that all calls of id() must of course happen in the main process to produce usable results.
My Class:
class myClass:
pass
I am looking to recreate this effect:
x = myClass()
y = myClass()
z = myClass()
within a for loop because the number of times I need to loop will be varied each time.
Trying this:
x = 3
for i in range(x):
cls = myClass()
doesn't work because on each iteration I recreate the class instance.
My thinking is that on each loop I need to create a copy of the class and store that in a dict for referencing. So my questions are:
Is this the right approach?
How do I create a copy of a class?
My attempts to create a class so far have been unsuccessful as the class isn't totally individual.
x = deepcopy(cls)
CopyOfCls = type('CopyOfCls', cls.__bases__, dict(cls.__dict__))
EDIT: Answerers revealed that I was actually looking at creating multiple class instances.
You don't need to copy a class to make multiple instances of that class.
items = []
for i in range(10):
items.append(myClass())
items now contains ten separate myClass instances. You can access them individually with indexing, ex. items[3].
This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 15 days ago.
I created a class:
class A:
aList = []
now I have function that instantiate this class and add items into the aList.
note: there are 2 items
for item in items:
a = A();
a.aList.append(item);
I find that the first A and the second A object has the same number of items in their aList.
I would expect that the first A object will have the first item in its list and the second A object will have the second item in its aList.
Can anyone explain how this happens ?
PS:
I manage to solve this problem by moving the aList inside a constructor :
def __init__(self):
self.aList = [];
but I am still curious about this behavior
You have defined the list as a class attribute.
Class attributes are shared by all instances of your class.
When you define the list in __init__ as self.aList, then the list is an attribute of your instance (self) and then everything works as you expected.
You are confusing class and object variables.
If you want objects:
class A(object):
def __init__(self):
self.aList = []
in your example aList is a class variable, you can compare it with using the 'static' keyword in other languages. The class variable of course is shared over all instances.
This happened because list is a mutable object, and it is created once only when defining the class, that is why it becomes shared when you create two instances. Eg,
class A:
a = 0 #immutable
b = [0] #mutable
a = A()
a.a = 1
a.b[0] = 1
b = A()
print b.a #print 0
print b.b[0] #print 1, affected by object "a"
Therefore, to solve the problem, we can use constructor like what you have mentioned. When we put the list in constructor, whenever the object is instantiated, the new list will also be created.
In Python, variables declared inside the class definition, instead of inside a method, are class or static variables. You may be interested in taking a look at this answer to another question.