Python pass a class reference to another class during construction - python

I'm intending to create a data distributor class as a mutable class:
class DataDistributor(object):
def __init__(self):
self.target_trackid = -1
def next_sen(self):
self.target_trackid += 1
return self.target_trackid
So that I can globally keep a pointer on my data.
I have another class:
class Env(object):
def __init__(self, distributor):
self.distributor = distributor
self.target_trackid = 0 # init
def reset(self):
self.target_trackid = self.distributor.next_sen()
So that when I create many Env instances, each Env instance will get a different data point.
So I use this to create my instances:
ddist = DataDistributor()
env = Env(ddist)
envs = [pickle.loads(pickle.dumps(env)) for _ in range(12)]
envs[0].reset()
envs[1].reset()
envs[2].reset()
print envs[0].target_trackid
print envs[1].target_trackid
print envs[2].target_trackid
And the results are all the same: a bunch of 0s.
I'm not exactly sure how Python is handling this :( and if there is a viable solution to achieve what I want to achieve!

How about creating a class variable for keeping track of the objects created? Your simple class structure will be like:
class Env(object):
my_counter = 0 # Your class variable
def __init__(self, param1, param2):
# some initialization
Env.my_counter += 1 # increament everytime object is created
# some logic
Sample run:
>>> e1 = Env('p11', 'p12') # creation of first object
>>> Env.my_counter
1 # value of counter set as 1
>>> e1 = Env('p21', '22') # creation of second object
>>> Env.my_counter
2 # value of counter set as 2
Passing object of different class just for tracking the created object of some other class, it is definitely not the right approach.

pickle.load will create different objects which means the datadistributor variable in each env object will refere

Related

Emum not assigning values

I have an enum class and I declare it as such for a state machine and declare a class as such
#file name is statefm.py
class State(Enum):
START = auto
MID = auto
END = auto
class gate:
def __init__(self):
self.st = State.START
self.counter = 0
self.done = False
def test(self):
print(self.st)
self.st = State.MID
print(self.st)
self.state = State.END
print(self.st)
Then in another file, I do the necessary import, instantiate an object of the class and call the test class method,
import statefm
k = statefm.gate()
k.test()
Oddly, this is the output I get.
State.START
State.START
State.START
I also call list and all I get from list is just the first enum element in two places. Can I please get any help on this?
Thank you!
You are supposed to call it like auto(), not auto
from enum import Enum, auto
class State(Enum):
START = auto()
MID = auto()
END = auto()
That using the bare name auto works at all is kind of a funny accident. All values just get aliased to the same class auto itself, and your resulting enumeration type actually only has one member, State.START, with two more aliases pointing to the same member.
>>> State.__members__
mappingproxy({'START': <State.START: <class 'enum.auto'>>,
'MID': <State.START: <class 'enum.auto'>>,
'END': <State.START: <class 'enum.auto'>>})
>>> len(State)
1

Adding a new object to a class with user-input(input) in python

I am trying to add new objects to a class(emne) but the new instances of the class needs to be created using user input. So i need a way to be able to chose the name for the object and set some of the values of the objects with user input.
I have already tried to create a function that passes the value of the user input into a x = emner(x) to create it but it only returns:
AttributeError: 'str' object has no attribute 'fagKode'
so i think my issue is that the value of the input is created as a string so that it is not understood as a way to create the function
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne():
nyttEmne = input("test:")
nyttEmne=Emne(nyttEmne)
expected result is that the code creates a new instance of the class.
If by choosing a name you mean your fagKode attribute, what you need is:
fagKode = input('Enter code: ')
Emne(fagKode)
You're adding the instances of Enme to the list in the constructor, so you don't need to save them to a variable.
Alternatively, you can handle that in the function:
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
def leggTilEmne():
nyttEmne = input("test:")
enme.append(Emne(nyttEmne))
I'm not sure what exactly you are asking, since you haven't responded to the comments. So,
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne(self, value): # <--- is this what you want
self.nyttEmne= Emne(value)
This is an example of when to use a class method. __init__ should not be appending to a global variable, though. Either 1) have the class method append to a class attribute, or 2) have it return the object and let the caller maintain a global list.
emne = []
class Emne:
emne = []
def __init__(self, fag_kode):
self.fag_kode = fag_kode
self.karakter = ""
#classmethod
def legg_til_emne_1(cls):
nytt_emne = input("test:")
cls.emne.append(cls(nytt_emne))
#classmethod
def legg_til_emne_2(cls):
nyttEmne = input("test:")
return cls(nyttEmne)
Emne.legg_til_emne_1() # Add to Emne.emne
e = Emne.legg_til_emne_2()
emne.append(e)

Accessing member variable in Python?

I have recently started learning python (coming from C++ background), but I could not understand how should I access the member variable (nonce) and use it in the second function called def mine_block().Aren't all members of the class Block publicly available from everywhere?
class Block:
'''
Дефинираме ф-я , която създава
променливите като членове на класа Block
'''
def _init_(self,prevHash,index,nonce,data,hash,time):
self.prevHash = prevHash
self.index = index
self.nonce = nonce
self.data = data
self.hash = hash
self.time = time
def get_hash(self):
print(self.hash)
def mine_block(self,difficulty):
arr = []
for i in range(difficulty):
arr[i] = '0'
arr[difficulty] = '\0'
str = arr
while True:
'''
here I receive an error
unresolved referene nonce
'''
nonce++
To refer to class attributes within the class methods you need pass the object itself into the methods with the keyword self. Then you can access other class methods and the class attributes with self.foo.
Also, the while True loop should not be indented at root level within the class. Last, the foo++ C-style is not correct in Pyhton, it should be foo += 1
In Python all instance members are publicly available through the class instance which is passed to class methods as self. Hence you should use self.nonce.
Besides, in Python be careful with indentation. Your mine_block method should look like:
def mine_block(self,difficulty):
...
str = arr
while True:
self.nonce += 1

Python class attributes within a list of instances are not recognized properly

I'm trying to use class objects in a list for the first time. But for some reason, the attributes of all class objects in the list are getting assigned the same value as the last object in the list. Here's my code:
# First I define the class
class Batsman:
def __init__(self, innings, avg, sr):
Batsman.innings = innings
Batsman.avg = avg
Batsman.sr = sr
# Then I create the list of class objects:
batsman = [
Batsman(100,45,65),
Batsman(50,40,60)
]
# Then I print the below:
print(batsman[0].innings)
Output should be 100, but it is 50 instead. Why is this?
If I use 5 instances, the attributes of all 5 get reset to whatever the last object contains. Why is this?
When using the name of the class Batsman you are refering to the class not the instance, you need to use self:
class Batsman:
def __init__(self, innings, avg, sr):
self.innings = innings
self.avg = avg
self.sr = sr
# Then I create the list of class objects:
batsman = [
Batsman(100,45,65),
Batsman(50,40,60)
]
# Then I print the below:
print(batsman[0].innings)
You can check some extra explanations and inforamtion about self in this other question

Python: Adding to dict of one object in a list changes all dicts of every other object in the list

So Python isn't my strong suit and I've encountered what I view to be a strange issue. I've narrowed the problem down to a few lines of code, simplifying it to make asking this question easier. I have a list of objects, this object:
class FinalRecord():
ruid = 0
drugs = {}
I create them in the shell like this:
finalRecords = []
fr = FinalRecord()
fr.ruid = 7
finalRecords.append(fr)
fr2 = FinalRecord()
fr2.ruid = 10
finalRecords.append(fr2)
As soon as I want to change the drugs dict on one object, it changes it for the other one too
finalRecords[0].drugs["Avonex"] = "Found"
I print out this:
finalRecords[1].drugs
and it shows:
{'Avonex':'Found'}
When I'm expecting it to actually be empty. I know I'm not completely understand how Python is working with the objects, can anyone help me out here?
The reason for this is because drugs is a class attribute. So if you change it for one object it will in fact change in others.
If you are looking to not have this behaviour, then you are looking for instance attributes. Set drugs in your __init__ like this:
class FinalRecord():
def __init__(self):
self.ruid = 0
self.drugs = {}
Take note of the use of self, which is a reference to your object.
Here is some info on class vs instance attributes
So, full demo illustrating this behaviour:
>>> class FinalRecord():
... def __init__(self):
... self.ruid = 0
... self.drugs = {}
...
>>> obj1 = FinalRecord()
>>> obj2 = FinalRecord()
>>> obj1.drugs['stuff'] = 2
>>> print(obj1.drugs)
{'stuff': 2}
>>> print(obj2.drugs)
{}
You define drugs as a class attribute, not an instance attribute. Because of that, you are always modifying the same object. You should instead define drugs in the __init__ method. I would also suggest using ruid as an argument:
class FinalRecord():
def __init__(self, ruid):
self.ruid = ruid
self.drugs = {}
It could then be used as this:
fr = FinalRecord(7)
finalRecords.append(fr)
fr2 = FinalRecord(10)
finalRecords.append(fr2)
Or more simply:
finalRecords.append(FinalRecord(7))
finalRecords.append(FinalRecord(10))

Categories

Resources