How to index through dynamic generated nested objects in Python? - python

import tkinter as tk
import tksheet
import json
import pickle
class Treino(object):
class config(object):
_list = []
def __init__(self, name, value):
self.name = name
self.value = value
self._list.append(self)
class CategoriaTreino(object):
_list = []
def __init__(self, name):
self.name = name
self._list.append(self)
self.config = {'RNG': 0}
class SubCategoriaTreino(object):
_list = []
def __init__(self, name, repet):
self.name = name
self.repetição = repet
self._list.append(self)
pass
def returnCat():
for cat in TreinoMain.CategoriaTreino._list:
yield cat
def returnSubCat():
for subcat in TreinoMain.CategoriaTreino.SubCategoriaTreino._list:
yield subcat
def savefile():
with open('treinos.pkl', 'wb') as file:
for cat in returnCat():
pickle.dump(cat, file, pickle.HIGHEST_PROTOCOL)
def loadfile():
data = []
with open('treinos.pkl', 'wb') as file:
while True:
try:
data.append(pickle.load(file))
except EOFError:
break
for d in data:
#iterate through objs
pass
if __name__ == "__main__":
TreinoMain = Treino()
ca1 = TreinoMain.CategoriaTreino("Braço")
subca1 = ca1.SubCategoriaTreino('Biceps', '2x10')
So, code is obviously far from done, my issue though is, i was hoping that creating an instance of the parent object, and then an instance of the child object would allow me to easily return attributes from the child object through it's parent object (and save/load from pickle). but apparently that's not the case (can't reefer to the childobj as parentobj.childobj), any ideas on how to do it in a simple way, or a better way to dynamically generate an object inside another object?
Also i'm almost pretty sure the _list will be useless after i load the objs with pickle and iterate through them...
The idea: Make a GUI so that the user can add/remove categories and subcategories of a data structure on the fly
Why i didn't go with nested data types? I figured it would be easier to implement with objects when i'm actually going to use them for what my goal is (randomize exercise schedules) and to write the add/remove functions.
So far what i've tried was to return attributes with:
ca1.subca1.name
That doesn't work.

Related

Python: Inner Class

I am trying to create a json string from a class and I defined my class as follows:
import json
import ast
from datetime import datetime
import pytz
import time
class OuterClass:
def __init__(self):
self.Header = None
self.Body = None
class Header:
def __init__(self, ID = None, Name = None):
self.ID = ID
self.Name = Name
class Body:
def __init__(self, DateTime=None, Display=None):
self.DateTime = DateTime
self.Display = Display
def current_time_by_timezone(timezone_input):
return datetime.now(pytz.timezone(timezone_input))
if __name__ == '__main__':
response = OuterClass()
header = response.Header('123', 'Some Name')
body = response.Body(current_time_by_timezone('US/Central'), 'NOT VALID')
print(json.dumps(response.__dict__))
I'm getting an error 'TypeError: 'NoneType' object is not callable'. Is it because I'm setting the Header and Body in the OuterClass definition myself to None?
The problem with your code is these lines:
self.Header = None
self.Body = None
These create instance variables named Header and Body on every instance of OuterClass, so you can never access the class variables (the nested classes) via an instance, only via OuterClass itself.
It's not very clear what your intention is with this data structure. Defining a class inside another class doesn't do anything special in Python (by default, you could probably make there be special behavior with special effort, like using a metaclass that makes the inner classes into descriptors). Generally though, there's no implied relationship between the classes.
If you want your OuterClass to create instances of the other two classes, you can do that without nesting their definitions. Just put the class definitions at top level and write a method that creates an instance at an appropriate time and does something useful with it (like binding it to an instance variable).
You might want something like:
def Header:
...
def Response:
def __init__(self):
self.header = None
def make_header(self, *args):
self.header = Header(*args)
return self.header
You could keep the classes nested as long as you don't expect that to mean anything special, just be sure that you don't use the class name as an instance variable, or you'll shadow the name of the nested class (a capitalization difference, like self.header vs self.Header could be enough).

Would giving a list of objects to another class , not make this relation aggregation?

class A:
def __init__(self, id, name ,age):
self.id = id
self.name = name
self.age = age
def get_id(self):
return self.id
def get_name(self):
return self.name
def get_age(self):
return self.age
class B:
def __init__(self, lst, file):
self.lst = lst
self.file = file
def writefile(self):
fileObj = open(self.file, 'w')
write_string = ''
for person in self.lst:
for func in [person.get_id, person.get_name, person.get_age]:
write_string += func() + '\t'
write_string = write_string[:-1] + '\n'
fileObj.write(write_string[:-1])
fileObj.close()
def main():
file = 'sample.txt'
def loadfile():
try:
filez = open(file, 'r')
except FileNotFoundError:
filez = open(file, 'w')
filez.close()
filez = open(file, 'r')
lst = []
for line in filez:
id, name, age = line.split('\t')
age = date.rstrip('\n')
lst.append(A(id, name, age))
return lst
population = loadfile()
call = B(population, file)
def add():
obj_A1 = A('1','bilal','29')
obj_A3 = A('3','asda','54')
population.append(obj_A1)
population.append(obj_A3)
add()
def display():
for i in population:
if i.get_id() == '3':
print('found')
display()
call.writefile()
main()
Im new to OOP. im trying to understand if giving a list of objects to class B would make any difference to its relation. The relation i hope here is aggregation between Class A and class B if im not wrong since im adding population list to class B ? ps. sorry for the long code.
According to Martin Fowler's UML Distilled:
Aggregation is strictly meaningless; as a result, I recommend that you ignore it in your own diagrams.
That leaves us with the question of whether the objects contained within lst have an association or composition relationship with B?
Composition implies that the objects being composed do not outlive their container classes. It also implies that they are not shared by other container classes.
Association defines a looser coupling relationship than composition, namely that one object merely refers to another object. In python this basically translates to the idea that the class has a certain instance attribute.
In your code you first instantiate population then pass it to B's constructor. Suppose you had another object C which could take in a list object just like B:
class C:
def __init__(self, lst, file):
self.lst = lst
self.file = file
One could imagine that later in your main block, the population variable could be reused to instantiate C. This would result in a shared instance attribute between B and C. Also if you called del B somewhere later in your code, it wouldn't destroy population. You therefore have a mere association relationship here.
If you wanted to implement true composition (which I assume is what you mean by aggregation), you could either instantiate the list within your constructor:
class B:
def __init__(self, file):
self.lst = loadfile(file)
self.file = file
Or you could instantiate the list upon B instantiation as follows:
call = B(loadfile(file), file)

How to bind data of instance of object A to corresponding instance of object B?

I'm writing another "bicycle" for reading .ini files to get some experience in advanced Python and OOP. Also I find default Python's configparser access style a little unpleasant for eyes, i.e.: something = config['section']['parameter'] instead of more eye-candish something = config.section.parameter.
I've ended up with this design:
ConfigStorage object to keep pairs of parameter/value as dictionary;
Config object to manage data in storage object.
__getattribute__ in Config object is overridden so I can access values in ConfigStorage dictionary by attribute name of Config object (the goal!).
The system works OK when there is only one instance of Config object. When I tried to work with multiple configs (and, therefore, instantiate new Config objects to manage them), I realized that ConfigStorage is one for all.
I've tried to create new instance of ConfigStorage for every Config object but Python reaches maximum recursion depth in this code (why?):
class _ConfigStorage(object):
def __init__(self):
self.config = dict()
class Config(object):
def __getattribute__(self, name):
if name in self.c.config:
return self.c.config[name]
else:
raise AttributeError("No parameter named [%s]" % name)
def __init__(self, file):
self.c = _ConfigStorage()
with open(file, 'r') as f:
for config_line in f:
key = # getting key from line
value = # getting value
self.c.config[key] = value
Finally, I got my code working, but I find this solution very crude and tainted with black magic. I separate data in storage object by adding to dictionary key a string representation of Config object ID. The ConfigStorage object is still single.
Also __del__ method is needed, as GC don't know about unnecessary data in storage and I have to remove them manually. It sucks.
class _ConfigStorage(object):
config = dict()
class Config(object):
def __getattribute__(self, name):
key = str(id(self)) + name
if key in _ConfigStorage.config:
return _ConfigStorage.config[key]
else:
raise AttributeError("No parameter named [%s]" % name)
def __init__(self, file):
with open(file, 'r') as f:
for config_line in f:
key = str(id(self) + # getting key from line
value = # getting value
_ConfigStorage.config[key] = value
def __del__(self):
instance_id = str(id(self))
keys_to_delete = []
for key in _ConfigStorage.config:
if instance_id in key:
keys_to_delete.append(key)
for key_to_delete in keys_to_delete:
del _ConfigStorage.config[key_to_delete]
How can I improve the design, being able to access dictionary data by object attribute?
I think this implementation suits your needs:
class Config(object):
def __getattr__(self, name):
if name in self.config:
return self.config[name]
else:
raise AttributeError("No parameter named [%s]" % name)
def __init__(self, file=None):
# changed to make it work without real file
self.config = {'key': 'value'}
config = Config()
print(config.key) # value
print(config.not_a_key) # AttributeError: ...
No need to write _ConfigStorage and __del__, no infinite recursion, access by dot notation.
Silly, but I found more elegant way to solve my problem.
class Config(object):
config = dict()
def __getattribute__(self, name):
if name in Config.config:
return Config.config[name]
else:
raise AttributeError("No parameter named [%s]" % name)
def __init__(self, file):
try:
with open(file, 'r') as f:
for config_line in f:
config_line = config_line.strip()
eq_position = config_line.find('=')
key = config_line[:eq_position].strip()
value = config_line[eq_position + 1:].strip()
Config.config[key] = value
except FileNotFoundError:
print('File not found')

Extracting specific fields from python object

This is a sample python object that I am working with.
class DataObj(object):
def __init__(self, cvid, cvname, address, get_info):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
class PROF(object):
def __init__(self, organization, manager_name):
self.organization = organization
self.manager_name = manager_name
self.project_list = [Proj("asd", "asd"), Proj("asdsd", "asdsd")]
class Proj(object):
def __init__(self, projectname, projecttype):
self.projectname = projectname
self.projecttype = projecttype
I need to write a function that takes a list of fields and extract all the fields as key value pair from the DataObj. The trick is it should also look for attributes of object composed inside DataObj class. for example if list of fields is ["cvid", "organization", "projectname"], it should return something like this in the following format
{'cvid' : 'value', 'organization' : 'Honda', Proj :[{'projectname' : 'asd'}, {'projectname' : 'asdsd'}]
Where should I write this function, so my code is more modular? I was thinking about writing it inside DataObj but I wouldn't know what are the attributes of object composed inside DataObj. How to achieve what I am trying to do in more object oriented way?
All I did was simply add __iter__ which basically says hey, you can iterate over me, if you cast the object to an iterabale container type.
class Proj(object):
def __init__(self, projectname, projecttype):
self.projectname = projectname
self.projecttype = projecttype
def __iter__(self):
yield ("projectname", self.projectname)
class PROF(object):
def __init__(self, organization, manager_name):
self.organization = organization
self.manager_name = manager_name
self.project_list = [Proj("asd", "asd"), Proj("asdsd", "asdsd")]
def __iter__(self):
for proj in self.project_list:
yield (dict(proj))
class DataObj(object):
def __init__(self, cvid, cvname, address):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
def __iter__(self):
yield ('cvid', self.cvid)
yield ('organization', self.prof.organization)
yield ("Proj", list(self.prof))
do = DataObj("1", "heinst", "A Street, Somewhere, USA")
print dict(do)
Between __getattr__ and operator.attrgetter, you could make this work fairly easily:
class DataObj(object):
def __init__(self, cvid, cvname, address, get_info):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
def __getattr__(self, name):
# Called when an attribute is accessed which is not found on DataObj
# You can limit the loop to avoid checking some attributes, or
# remove the loop if only self.prof should be checked
for member in (self.cvid, self.cvname, self.address, self.prof):
try:
return getattr(member, name)
except AttributeError:
pass
raise AttributeError(name)
# If only self.prof should be checked, the function could simplify to:
# return getattr(self.prof, name)
Then you can make a simple utility function that runs against a DataObj to get an arbitrary set of key value pairs from it:
from operator import attrgetter
def extractdata(dataobj, *names):
return dict(zip(names, attrgetter(*names)(dataobj)))
Or as a member of DataObj, just name the first param self to match convention:
def extractdata(self, *names):
return dict(zip(names, attrgetter(*names)(self)))
__getattr__ allows delegation of attribute lookup to contained objects, and attrgetter allows you to retrieve a set of arbitrary attributes in a simple way.

python (built-in)json de/serilazation with nested custom types

I don't have much experience with json module in python2 (2.7). Now I am facing a problem: How to serialize a custom object to json and later de-serialize it back.
I have this object hierarchy as example:
class Company(object):
def __init__(self, company_id):
self.company_id = company_id
self.name = ''
# other 10 attributes with simple type
...
self.departments = [] #list of Dept objects
class Dept(object):
def __init__(self, dept_id):
self.dept_id = dept_id
self.name = ''
# other 10 attributes with simple type
...
self.persons = [] #list of Person objs
class Person(object):
def __init__(self, per_id):
self.per_id = per_id
self.name = ''
# other 10 attributes with simple type
...
self.skills = [] #list of Skill objs
class Skill(object):
def __init__(self, skill_id):
self.skill_id = skill_id
self.name = ''
# other 10 attributes with simple type
...
self.foos = [] #list of Foo objs
class Foo(object):
.....
Now say I have got an object from Company, with all attributes and lists from nested object filled. I want to save the object into a json file. And later load it back, so that those nested objects (departments, persons, skills) are loaded as well.
I have read pydoc, knew that the json de/encoding is dict based. I can now do the serialization with this:
json.dump(company_obj, jsonfile, default = lambda o: o.__dict__, sort_keys=True, indent=4)
but it is hard to get it back to Company later.
I thought this problem would be common thing. I do searched here at SO and google, didn't find helpful information.
What is the proper way in this case to do json serialization and de-serialization.
What you need are custom encoders and decoders. These are documented here : http://docs.python.org/2/library/json.html#encoders-and-decoders
A working solution is to add the qualified class name to the dict while encoding and use it to create an instance of the right class when decoding.

Categories