Adding class to list as instance - python

I have the below code:
classes = [Class1(), Class2(), Class3()]
usedClasses = {}
number = random.randint(0, len(classes)-1)
usedClasses[len(usedClasses)] = classes[number]
This code randomly selects a class from classes and then adds this to usedClasses however, when I apply a method to a class in usedClasses, any duplicate additions are classed as the same instance. How would I add a class from classes to usedClasses as an instance each time.

You need to have a list of the classes themselves, not instances, and instatiate them when required:
classes = [Class1, Class2, Class3] # Just the names of the classes
usedClasses = {}
number = random.randint(0, len(classes)-1)
usedClasses[len(usedClasses)] = classes[number]() # create a new instance here.

Related

How to dynamically initialize an object within an inner class in Python 3?

I am leveraging the SeriesHelper object of InfluxDB library(please have a look at https://influxdb-python.readthedocs.io/en/latest/examples.html#tutorials-serieshelper) to push set of data points to InfluxDB. The SeriesHelper class has to be inherited and the child class needs to initialize various objects as its meta attributes, so as to override the default values of the objects in the Parent class.
Actual code
class MySeriesHelper(SeriesHelper):
"""Instantiate SeriesHelper to write points to the backend."""
class Meta:
"""Meta class stores time series helper configuration."""
client = myclient
series_name = 'rf_results'
fields = ['some_stat', 'other_stat']
tags = ['server_name']
bulk_size = 5
autocommit = True
Here the 'series_name' object is initialized(hard-coded) right before it is ran as a script. My use case is to initialize 'series_name' based on the runtime arguments that are passed to this script.
I tried by defining a global variable whose value is providing at runtime and assigning that global variable to the 'series_name' like the below one, but in vain.
Problematic code
series_configured = None
class MySeriesHelper(SeriesHelper):
"""Instantiate SeriesHelper to write points to the backend."""
class Meta:
"""Meta class stores time series helper configuration."""
client = myclient
series_name = series_configured
fields = ['some_stat', 'other_stat']
tags = ['server_name']
bulk_size = 5
autocommit = True
def main():
global series_configured
series_configured = args.series_name
MySeriesHelper(server_name='server_A', some_stat='Master server', other_stat='Controller')
MySeriesHelper.commit()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--series_name", dest='series_name',
help="The measurement to be used for storing the data points",required=True)
args = parser.parse_args()
main()
Error seen while running is
'NoneType' object has no attribute 'format'
It infers that the object 'series_name' is not initialized with a value. Is there any way of properly initializing it ?
When the python interpreter go over the code (line by line) it define all the classes static variable.
It's set static variable before you create an instance from a class.
That mean when you reach the point of:
autocommit = True
The value of series_name is already set to None (because that is the value of series_configured at the point).
The following example show that the static variable are already set before I created an instance:
>>> series_configured = None
>>> class MySeriesHelper:
"""Instantiate SeriesHelper to write points to the backend."""
class Meta:
"""Meta class stores time series helper configuration."""
series_name = series_configured
fields = ['some_stat', 'other_stat']
tags = ['server_name']
bulk_size = 5
autocommit = True
>>> print(MySeriesHelper.Meta.series_name)
None
If you want to change the Meta.series_configured static variable you will have to set it after the series_configured change its content.
Try the following main.
def main():
global series_configured
series_configured = args.series_name
# The following line will set the variable at the inner Meta class.
MySeriesHelper.Meta.series_name = series_configured
MySeriesHelper(server_name='server_A', some_stat='Master server', other_stat='Controller')
MySeriesHelper.commit()

Python pass a class reference to another class during construction

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

list of objects python

I am trying to print a list of python objects that contain a list as a property and i am having some unexpected results:
here is my code:
class video(object):
name = ''
url = ''
class topic(object):
topicName = ''
listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
topic1 = topic()
topic1.topicName = 'topic1'
video1 = video()
video1.name = 'VideoName1'
video1.url = 'VideoURL1'
video2 = video()
video2.name = 'VideoName2'
video2.url = 'VideoURL2'
topic1.addVideo(video1)
topic1.addVideo(video2)
topic2 = topic()
topic2.topicName = 'topic2'
video3 = video()
video3.name = 'VideoName3'
video3.url = 'VideoURL3'
video4 = video()
video4.name = 'VideoName4'
video4.url = 'VideoURL4'
topic2.addVideo(video3)
topic2.addVideo(video4)
topicsList = []
topicsList.append(topic1)
topicsList.append(topic2)
for topicCurrent in topicsList:
print(topicCurrent.topicName)
for video in topicCurrent.getListOfVideo():
print(video.name)
print(video.url)
What I expect to get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
topic2
VideoName3
VideoURL3
VideoName4
VideoURL4
but what I actually get is this:
topic1
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
topic2
VideoName1
VideoURL1
VideoName2
VideoURL2
VideoName3
VideoURL3
VideoName4
VideoURL4
Why? I want to iterate over my list of topics and print out each video in each topic, but for each topic it prints out all videos???
What is going on here?
You have created class variables instead of instance variables, which are different for each instance object. Define your class as follows:
class topic(object):
def __init__(self):
self.topicName = ''
self.listOfVideo = []
def addVideo(self,videoToAdd):
self.listOfVideo.append(videoToAdd)
def getTopic(self):
return self.topicName
def getListOfVideo(self):
return self.listOfVideo
From Python Tutorial:
Instance variables are for data unique to each instance and class
variables are for attributes and methods shared by all instances of
the class.
EDIT:
One more important thing to consider is that why only listOfVideo was common for all instances but not topicName. It is because list's are mutable objects while string's are immutable.
So any changes made to listOfVideo are common for all instances, i.e., they still refer to listOfVideo defined in the topic namespace.
However when you do topic1.topicName = 'topic1', you create a new variable topicName within topic1 namespace, which overrides the topicName found in topic(class) namespace. You can confirm it by printing the value topic.topicName, which you will find to be an empty string, i.e., ''.

Dynamically setting attribute as function in Python class

I am creating a simple game that contains classes called 'Player' and 'Strategy'. I want to assign a Strategy instance to the Player instance when the Player is created.
class Player(object):
def __init__(self):
self.Strategy = None
def Decision(self, InputA, InputB):
Result = self.Strategy(InputA, InputB)
return Result
def SetStrategy(self):
# Sets a strategy instance to the Player instance
class Strategy(object):
def Strategy1(self, InputA, InputB):
return InputA * InputB
def Strategy2(self, InputA, InputB):
return (InputA - InputB) / 2
def Strategy3(self, InputA, InputB):
return 0
What I'm trying to achieve:
in[0] Player1 = Player()
in[1] Player2 = Player()
in[2]: Player1.SetStrategy('Strategy1')
in[3]: Player2.SetStrategy('Strategy3')
in[4]: Player1.Decision(2,5)
out[0]: 10
in[5]: Player2.Decision(3,6)
out[1]: 0
Searching here and via google shows me ways of doing it with monkey patching but the approach looks a little inelegant (and although I'm a beginner I think there's a better way to do it) - is there a way to do this with inheritance that I'm not seeing?
def strategy1(inputA, inputB): # 2
return inputA * inputB
def strategy2(inputA, inputB):
return (inputA - inputB) / 2
def strategy3(inputA, inputB):
return 0
strategy = {
'mul': strategy1,
'diff': strategy2,
'zero': strategy3
}
class Player(object):
def __init__(self, strategy_name='mul'): # 1
self.strategy_name = strategy_name # 5
def decision(self, inputA, inputB): # 4
result = strategy[self.strategy_name](inputA, inputB)
return result
player1 = Player()
player2 = Player()
player1.strategy_name = 'mul' # 3
player2.strategy_name = 'zero'
print(player1.decision(2, 5))
# 10
print(player2.decision(3, 6))
# 0
Every player has a strategy, so don't allow instantiation of Player
without assigning some strategy. You could use a default strategy
(as shown below), or make strategy a mandatory argument.
The strategies could be plain functions; I don't see a reason to
bundle them as methods of a Strategy class. Always keep code as
simple as possible; don't use a class when a function would suffice;
use a class when it provides some feature (such as inheritance) which
makes the class-based solution simpler.
In Python there is no need for getters/setters like setStrategy.
You can use plain attributes for simple values, and properties to
implement more complicated behavior. Attributes and properties use
the same syntax, so you can switch from one to the other without
having to change have the class is used.
There is a convention (recommended in PEP8) that classes be named in
CamelCase, and instances, functions and variables in lowercase. The
convention is used ubiquitously, and following it will help other
understand your code more easily.
To make it easy to store the strategy in a database, you could store
the strategy_name in the database, and use a lookup dict (such as
strategy) to associate the name with the actual function.

instantiating and defining classes in python

There is a python file named BasePlat.py which contain something like this:
class BasePlatform(SimObj):
type = 'BasePlatform'
size = Param.Int(100, "Number of entries")
class Type1(BasePlatform):
type = 'Type1'
cxx_class = 'Type1'
Now this file is used in another file named BaseModel.py
from BasePlat import BasePlatform
class BaseModel(ModelObj):
type = 'BaseModel'
delay = Param.Int(50, "delay")
platform = Param.BasePlatform(NULL, "platform")
These file define the parameters. In another file inst.py, some models are instantiated and I can modify the parameters. For example I can define two models with different delays.
class ModelNumber1(BaseModel):
delay = 10
class ModelNumber2(BaseModel):
delay = 15
However I don't know how can I reach size parameter in BasePlatform. I want something like this (this is not a true code):
class ModelNumber1(BaseModel):
delay = 10
platform = Type1
**platform.size = 5**
class ModelNumber2(BaseModel):
delay = 15
platform = Type1
**platform.size = 8**
How can I do that?
The attributes you are defining are at class level, which means that every instance of that class will share the same objects (which are instantiated at definition time).
If you want ModelNumber1 and ModelNumber2 to have different platform instances, you have to override their definition. Something like this:
class ModelNumber1(BaseModel):
delay = 10
platform = Param.Type1(NULL, "platform", size=5)
class ModelNumber2(BaseModel):
delay = 15
platform = Param.Type1(NULL, "platform", size=8)
Edit the BasePlatform class definition with something like this:
class BasePlatform(SimObj):
type = 'BasePlatform'
size = Param.Int(100, "Number of entries")
def __init__(self, size=None):
if size:
self.size = size
# or, if size is an integer:
# self.size = Param.Int(size, "Number of entries")
If you don't have access to the BasePlatform definition, you can still subclass it as MyOwnBasePlatform and customize the __init__ method.

Categories

Resources