Using parent class to contain many instances of child class - python

I am trying to write a data processing script and I think I'm misinterpreting the structure of Object Oriented Programming in Python.
I have sets of simulations that keep some variables constant and others which change according to the sim. I'm trying to contain the set of sims in a parent object and include a list of sims as an attribute, which are defined as a child object:
class Sim_set(path) :
def __init__ :
f = open(path)
self.fixed_attributes = fixed_attributes(f)
sims = [Sim(data) for data in f]
class Sim(Sim_set) :
def __init__(data) :
Sim_set.__init__()
self.variable_attributes = variable_attributes(data)
def derived_attributes() :
self.derived_attributes = math(self.variable_attributes,self.fixed_attributes)
The problem is that it looks like for each Sim, a new instance of Sim_set is created, when in reality I want the opposite: I want a single instance of Sim_set, with attributes that Sim can fetch, and many instances of Sim, contained in Sim_set.
I apologize if this is a rather broad question, but am I doing this right?
EDIT: So based on the answers so far, what I'm doing now is:
So what I am doing now is :
class Sim :
def __init__(data,sim_set) :
self.sim_set = sim_set
self.var_attr = f(data)
def deriv_attr() :
self.deriv_attr = g(self.var_attr,self.sim_set.fixed_attr)
It seems to work, but the crux of the question is really, "is this a good habit to have"?

So, Sim_set represents a set of simulations, and Sim represents of single simulation. It seems weird to me that a simulation inherits from a set of simulations.
I would break the parent-child relationship between Sim and Sim_set. Sim_set can still contain a collection of Sims but I don't think the parent-child relationship is appropriate here. Instead, I might add a new object, let's call it "Simluation_Lab" which is responsible for creating Sims and Sim_sets, and then populating them with the correct values.
You might also want to read up on Dependency Injection, it might help in this situation: https://medium.com/#shivama205/dependency-injection-python-cb2b5f336dce

If Sim_set is parent of Sim, every Sim is also a Sim_set
Every time you create a new Sim object it will create a new Sim_set
def __init__(data)
Sim_set.__init__()
self.variable_attributes = variable_attributes(data)
Look this code you are calling the __ init __ () method of Sim_set class this method is for object initialization (Constructor) So you are saying Sim is also Sim_set
It sounds like a Sim belongs to a Sim_set rather than IS a sim_set
This can be achieved by creating an attribute that it´s class is Sim_set
I leave you the Repl.it
https://repl.it/#AndrsFernndez/DesertedDarkcyanFlashmemory#main.py

Related

Creating Object With A For Loop

Firstly, I do apologise as I'm not quite sure how to word this query within the Python syntax. I've just started learning it today having come from a predominantly PowerShell-based background.
I'm presently trying to obtain a list of projects within our organisation within Google Cloud. I want to display this information in two columns: project name and project number - essentially an object. I then want to be able to query the object to say: where project name is "X", give me the project number.
However, I'm rather having difficulty in creating said object. My code is as follows:
import os
from pprint import pprint
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()
service = discovery.build('cloudresourcemanager', 'v1', credentials=credentials)
request = service.projects().list()
response = request.execute()
projects = response.get('projects')
The 'projects' variable then seems to be a list, rather than an object I can explore and run queries against. I've tried running things like:
pprint(projects.name)
projects.get('name')
Both of which return the error:
"AttributeError: 'list' object has no attribute 'name'"
I looked into creating a Class within a For loop as well, which nearly gave me what I wanted, but only displayed one project name and project number at a time, rather than the entire collection I can query against:
projects=[]
for project in response.get('projects', []):
class ProjectClass:
name = project['name']
projectNumber = project['projectNumber']
projects.append(ProjectClass.name)
projects.append(ProjectClass.projectNumber)
I thought if I stored each class in a list it might work, but alas, no such joy! Perhaps I need to have the For loop within the class variables?
Any help with this would be greatly appreciated!
As #Code-Apprentice mentioned in a comment, I think you are missing a critical understanding of object-oriented programming, namely the difference between a class and an object. Think of a class as a "blueprint" for creating objects. I.E. your class ProjectClass tells python that objects of type ProjectClass will have two fields, name and projectNumber. However, ProjectClass itself is just the blueprint, not an object. You then need to create an instance of ProjectClass, which you would do like so:
project_class_1 = ProjectClass()
Great, now you have an object of type ProjectClass, and it will have fields name and projectNumber, which you can reference like so:
project_class_1.name
project_class_1.projectNumber
However, you will notice that all instances of the class that you create will have the same value for name and projectNumber, this just won't do! We need to be able to specify values when we create each instance. Enter init(), a special python method colloquially referred to as the constructor. This function is called by python automatically when we create a new instance of our class as above, and is responsible for setting up all the fields of that class. Another powerful feature of classes and objects is that you can define a collection of different functions that can be called at will.
class ProjectClass:
def __init__(self, name, projectNumber):
self.name = name
self.projectNumber = projectNumber
Much better. But wait, what's that self variable? Well, just as before we were able reference the fields of our instance via the "project_class_1" variable name, we need a way to access the fields of our instance when we're running functions that are a part of that instance, right? Enter self. Self is another python builtin parameter that contains a reference to the current instance of the ProjectClass that is being accessed. That way, we can set fields on the instance of the class that will persist, but not be shared or overwritten by other instances of the ProjectClass. It's important to remember that the first argument passed to any function defined on a class will always be self (except for some edge-cases you don't need to worry about now).
So restructuring your code, you would have something like this:
class ProjectClass:
def __init__(self, name, projectNumber):
self.name = name
self.projectNumber = projectNumber
projects = []
for project in response.get('projects', []):
projects.append(ProjectClass(project["name"], project["projectNumber"])
Hopefully I've explained this well and given you a complete answer on how all these pieces fit together. The hope is for you to be able to write that code on your own and not just give you the answer!

Names of instances and loading objects from a database

I got for example the following structure of a class.
class Company(object):
Companycount = 0
_registry = {}
def __init__(self, name):
Company.Companycount +=1
self._registry[Company.Companycount] = [self]
self.name = name
k = Company("a firm")
b = Company("another firm")
Whenever I need the objects I can access them by using
Company._registry
which gives out a dictionary of all instances.
Do I need reasonable names for my objects since the name of the company is a class attribute, and I can iterate over Company._registry?
When loading the data from the database does it matter what the name of the instance (here k and b) is? Or can I just use arbitrary strings?
Both your Company._registry and the names k and b are just references to your actual instances. Neither play any role in what you'd store in the database.
Python's object model has all objects living on a big heap, and your code interacts with the objects via such references. You can make as many references as you like, and objects automatically are deleted when there are no references left. See the excellent Facts and myths about Python names and values article by Ned Batchelder.
You need to decide, for yourself, if the Company._registry structure needs to have names or not. Iteration over a list is slow if you already have a name for a company you wanted to access, but a dictionary gives you instant access.
If you are going to use an ORM, then you don't really need that structure anyway. Leave it to the ORM to help you find your objects, or give you a sequence of all objects to iterate over. I recommend using SQLAlchemy for this.
the name doesn't matter but if you are gonna initialize a lot of objects you are still gonna make it reasonable somehow

Variable from __init__ changed in one function, but not recognized as changed to other function

Sup, i'm doing a little account registration just for learning propose.
I created a class called Accounts and did many different functions to work with. With previous acknowledgment i knew that i need to start them from a function called def __init__(self)
class Account:
def __init__(self):
self.contas = {}
self.bancodecontas = open("x.txt", 'r')
def getaccounts(self):
for linha in self.bancodecontas:
linha = linha.strip()
conta = linha.split(",")
login = conta[0]
senha = conta[1]
self.contas[login] = senha
def accountsprinting(self):
for login, senha in self.contas.items():
print("Login= ", login, "Senha= ", senha)
getaccounts() is working fine, i tested a print(self.contas) in the end of it and it printed all accounts from inside my x.txt. The problem start when i need to call accountsprinting(), i tried to start it with print(self.contas) but shows me a empty dictionary, which means it is not accessing the "new" self.contas. I did the exact samething in a different type of project and it worked fine, i know i'm missing something really obvious here, so i'm asking sorry beforehand for my lack of attention.
Thanks for your time, good codding.
EDIT 1
People asked for the entire program, this is my entire program. I'm using PyCharm, i created this as a accounts.py, a root file or resources file, and i'm going to be importing this class to another main.py to use the respective functions. I know i must call Accounts().getaccounts() first, then i must call the other functions, so i can first fill my "accounts database". Even doing this:
Adding print(self.contas) to the end of getaccounts() and the start of accountsprinting()
And doing on the same .py:
Account().getaccounts()
Account().accountsprinting()
Or doing on different .py:
from AccountManager import Account
Account().getaccounts()
Account().accountsprinting()
The output is the same:
{'Bruno': '666', 'Bruno2': '444', 'Pedro': '2222a', 'Breno': '092b'}
{}
EDIT 2
Adding self.getaccounts()to def __init__(self) as #Darkonaut said, really worked, on the same .py and even doing an import from another .py, but i would like to understand why without it, it doesn't work, makes no sense to me.
Thanks a lot =)
You need to create AND use the same instance to call both methods with your expected results.
acc = Account()
accounts = acc.getaccounts()
acc.accountsprinting()
Also, you import Accounts but you call Account in your code.
You forgot self.getaccounts() in the last line of your __init__ method, hence contas remains empty because it never get's filled.
TL;DR Make sure you keep a reference to a newly created instance to keep it alive
and perform following method calls on this instance.
__init__ is a method which is being called after an instance get's created
and initializes the instance. You create an instance of a class every time
you call a class like you did with Account().
But if you don't keep a (external) reference to this newly created instance,
you can't address the instance to invoke further methods on it. What happens in your code:
Account().getaccounts() # new instance of Account created,
# i.a. __init__ called, finally getaccounts called
Account().accountsprinting() # new instance of Account created,
# i.a. __init__ called, finally accountsprinting called
Both instances are quickly garbage collected (CPython implementation of Python assumed), because you don't hold an external reference to them, like you would do if you assign a new instance to a name like: acc = Account().
You can check that you get a new object every time you call Account() by comparing identity with Account(1) is Account(1) # False or by looking at the id numbers:
id(Account(1))
# 88311904
id(Account(1))
# 88312408
As a side note:
It doesn't have to be a named reference like acc above, you could also hold an
implicit, unnamed reference by placing the new instances in a list for example and the list would keep the reference to the instances and thus, keeping them alive:
class Account:
def __init__(self, x):
self.x = x
lst = [Account(1), Account(2)]
lst[0].x
# 1
lst[1].x
# 2
self in your code is an (internal) reference connecting (binding) class and instance.
If you assign to self like you do with self.contas[login] = senha within your instance-method getaccounts, you do this only for the actual instance where you are calling getaccounts upon. So when you call Account().getaccounts() and
later Account().accountsprinting() you are doing this for two different
instances and not on the same. Hence the second instance has an empty contas dict because for this instance you didn't call getaccounts() before.

python load from shelve - can I retain the variable name?

I'm teaching myself how to write a basic game in python (text based - not using pygame). (Note: I haven't actually gotten to the "game" part per-se, because I wanted to make sure I have the basic core structure figured out first.)
I'm at the point where I'm trying to figure out how I might implement a save/load scenario so a game session could persist beyond a signle running of the program. I did a bit of searching and everything seems to point to pickling or shelving as the best solutions.
My test scenario is for saving and loading a single instance of a class. Specifically, I have a class called Characters(), and (for testing's sake) a sigle instance of that class assigned to a variable called pc. Instances of the Character class have an attribute called name which is originally set to "DEFAULT", but will be updated based on user input at the initial setup of a new game. For ex:
class Characters(object):
def __init__(self):
self.name = "DEFAULT"
pc = Characters()
pc.name = "Bob"
I also have (or will have) a large number of functions that refer to various instances using the variables they are asigned to. For example, a made up one as a simplified example might be:
def print_name(character):
print character.name
def run():
print_name(pc)
run()
I plan to have a save function that will pack up the pc instance (among other info) with their current info (ex: with the updated name). I also will have a load function that would allow a user to play a saved game instead of starting a new one. From what I read, the load could work something like this:
*assuming info was saved to a file called "save1"
*assuming the pc instance was shelved with "pc" as the key
import shelve
mysave = shelve.open("save1")
pc = mysave["pc"]
My question is, is there a way for the shelve load to "remember" the variable name assotiated with the instance, and automatically do that << pc = mysave["pc"] >> step? Or a way for me to store that variable name as a string (ex as the key) and somehow use that string to create the variable with the correct name (pc)?
I will need to "save" a LOT of instances, and can automate that process with a loop, but I don't know how to automate the unloading to specific variable names. Do I really have to re-asign each one individually and explicitly? I need to asign the instances back to the apropriate variable names bc I have a bunch of core functions that refer to specific instances using variable names (like the example I gave above).
Ideas? Is this possible, or is there an entirely different solution that I'm not seeing?
Thanks!
~ribs
Sure, it's possible to do something like that. Since a shelf itself is like a dictionary, just save all the character instances in a real dictionary instance inside it using their variable's name as the key. For example:
class Character(object):
def __init__(self, name="DEFAULT"):
self.name = name
pc = Character("Bob")
def print_name(character):
print character.name
def run():
print_name(pc)
run()
import shelve
mysave = shelve.open("save1")
# save all Character instances without the default name
mysave["all characters"] = {varname:value for varname,value in
globals().iteritems() if
isinstance(value, Character) and
value.name != "DEFAULT"}
mysave.close()
del pc
mysave = shelve.open("save1")
globals().update(mysave["all characters"])
mysave.close()
run()

Dynamically building up types in python

Suppose I am building a composite set of types:
def subordinate_type(params):
#Dink with stuff
a = type(myname, (), dict_of_fields)
return a()
def toplevel(params)
lots_of_types = dict(keys, values)
myawesomedynamictype = type(toplevelname, (), lots_of_types)
#Now I want to edit some of the values in myawesomedynamictype's
#lots_of_types.
return myawesomedynamictype()
In this particular case, I want a reference to the "typeclass" myawesomedynamictype inserted into lots_of_types.
I've tried to iterate through lots_of_types and set it, supposing that the references were pointed at the same thing, but I found that the myawesomedynamictype got corrupted and lost its fields.
The problem I'm trying to solve is that I get values related to the type subordinate_type, and I need to generate a toplevel instantiation based on subordinate_type.
This is an ancient question, and because it's not clear what the code is trying to do (being a code gist rather than working code), it's a little hard to answer.
But it sounds like you want a reference to the dynamically created class "myawesomedynamictype" on the class itself. A copy of (I believe a copy of) the dictionary lots_of_types became the __dict__ of this new class when you called type() to construct it.
So, just set a new attribute on the class to have a value of the class you just constructed; Is that what you were after?
def toplevel(params)
lots_of_types = dict(keys, values)
myawesomedynamictype = type(toplevelname, (), lots_of_types)
myawesomedynamictype.myawesomedynamictype = myawesomedynamictype
return myawesomedynamictype()

Categories