i am doing a python OOP exercise and i want to convert a list into containing variables such as name, age and job into a file, i tried 2 methods but just one worked, this was the one that worked (also the whole code)
class Person:
def __init__(self, name, job, age):
self.name = name
self.job = job
self.age = age
class PersonManagement:
def __init__(self):
self.persons = []
def add_person(self, name, job, age):
person = Person(name, job, age)
self.persons.append(person)
def persons_file(self):
with open("persons_file", "w") as file:
for line in self.persons:
file.write(f"{line.name} n")
the class method named persons_file is the one i used to make the file, i did that, but, the thing is if i put online write(line) it only writes the memory addres, i solved that by writing the name Person’s name attribute but i want the whole instance written in the file, how can i do that? i want name, age and job there
4
You can convert Person
into a dataclass, so it’s easier to work with in your context. By overwriting the __str__
method we can customize how the data will be represented when it is cast to a str
. All members of __persons
are cast to str
and written to the file.
from dataclasses import dataclass, asdict
import json
@dataclass
class Person:
name:str
age:int
job:str
def __str__(self) -> str:
return ', '.join(map(str, asdict(self).values()))
class PersonManagement:
DEFAULT_FILE = "persons_file.json"
def __init__(self, fp:str|None = None):
# private vars - no external/remote access
self.__persons = []
self.__fp = fp or PersonManagement.DEFAULT_FILE
@property
def persons(self) -> list:
# copy, maintain no modifiable access to `__persons` or it's members
# indexes reformatted to str
return [*map(str, self.__persons)]
# if `save` is a str it will be considered a filepath
def append(self, *args, save:bool|str=False, **kwargs) -> None:
self.__persons.append(Person(*args, **kwargs))
if save: self.save((self.__fp, save)[isinstance(save, str)])
# format and save `__persons` as comma-separated strings
def save(self, fp:str|None = None) -> None:
with open(fp or self.__fp, "w") as file:
file.write(',n'.join(p for p in self.persons))
Having a generic text file with arbitrary data in it is not very useful. You can switch to the json package to store the information in a way that you can easily reload. Below is a working example of one way you could structure your program to have a complete in/out system. The only real changes we have made here are:
Person
is mapped todict
instead ofstr
json
is used to format thedict
to JSON- the file is saved as json
- a
load
method is introduced
from dataclasses import dataclass, asdict
import json
@dataclass
class Person:
name:str
age:int
job:str
class PersonManagement:
DEFAULT_FILEPATH = "persons_file.json"
def __init__(self, fp:str|None = None):
# private vars - no external/remote access
self.__persons = []
self.__fp = fp or PersonManagement.DEFAULT_FILEPATH
@property
def persons(self) -> list:
# copy, maintain no modifiable access to `__persons` or it's members
# indexes reformatted to dict
return [*map(asdict, self.__persons)]
# if `save` is a str it will be considered a filepath
# `save` must be set via keyword
def append(self, *args, save:bool|str=False, **kwargs) -> None:
self.__persons.append(Person(*args, **kwargs))
if save: self.save((self.__fp, save)[isinstance(save, str)])
# format and save `__persons` as json
def save(self, fp:str|None = None) -> None:
with open(fp or self.__fp, "w") as file:
file.write(json.dumps(self.persons, indent=4, default=str))
# overwrite `__persons` from json
def load(self, fp:str|None = None) -> None:
with open(fp or self.__fp, "r") as file:
self.__persons = [Person(**data) for data in json.load(file)]
Using JSON for this might be fine, but there are a number of reasons why it isn’t that great. For instance: if you used the shelve package, you could simply store each person directly to the database. You don’t need to load the entire database to get data, and you don’t need to overwrite the entire database to add data. The syntax for working with a shelve
database is mostly the same as dict
.
1