Python Forum

Full Version: saving (in text or binary) an object under a defined class
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi, I don't know if my topic makes any sense but what I'm trying to say is, I'm made a class
class Users:
    def __init__(self, fname, lname, bday, username, password, domain='gmail'):
        self.fn = fname
        self.ln = lname
        self.bd = bday
        self.un = username
        self.pw = password
        self.dom = domain

    def fullname(self):
        return(self.fn + ' ' + self.ln)

    def email(self):
        return(self.fn.lower() + '_' + self.ln.lower() + '@' + self.dom + '.com')

    def show_info(self):
        return(
            f''' The following is the info for user {self.un}:
    First Name: {self.fn}
    Last Name: {self.ln}
    Birthdate: {self.bd}
    Email: {self.fn}_{self.ln}@{self.dom}.com
            ''')
and I created an object under that class
user_1 = Users('Adam', 'Smith', '1/1/2000', 'adam1100', 1234)
As you see, my class is like a personal info sheet. My question is, how can I save this particular object to an external file (like a text or a binary file) which could be loaded as is (remain as a "User" class) the next time I ran the code. Like the external file should become a database or something.

I tried doing this
def save_info(self):
        x = f"'{self.fn}', '{self.ln}', '{self.bd}', '{self.un}', '{self.pw}', '{self.dom}'"
        with open('users', 'r+') as data:
            data.write(x)
which is a function under the class I made, yes it does save in a file however, whenever I'm reading the file using this
@staticmethod
    def load_info():
        with open('users', 'r+') as data:
             return(data.read())
and running this outside the code block of the class
z = Users.load_info()
user_1 = Users(z)
its returning an error
Error:
Traceback (most recent call last): File "c:\Users\***\Desktop\Python\Test\test.py", line 39, in <module> user_1 = Users(z) TypeError: __init__() missing 4 required positional arguments: 'lname', 'bday', 'username', and 'password'
I think what the interpreter is telling is that it can't recognize the output from the text file as a valid __init__ of the class (since it is telling me that the code does not have any positional arguments)

I tried printing the variable z and it shows what I'm expecting
Output:
'Adam', 'Smith', '1/1/2000', 'adam1100', '1234', 'gmail'
Can you please enlighten me. I'm confused with creating classed that's why I'm focusing on it. Thanks.

P.S.
If my question is kinda noob I'm so sorry since I'm really a beginner with programming in general so please bear with me. Thank you.
one way is pickle module from Python Standard Library

here is tutorial on using pickle on Python Module of the week site


Another option is store instance attributes (if possible) as json file (or some other type of text file). In which case you need to create interface to reconstruct the object from that file.
+1 to JSON. It's more work, but pickle is discouraged for security reasons so I make a habit of avoiding it.
A look how to use this with TinyDb.
Can also mention dataset my tutorial,both of this make it easier to work with small databases.

First i gone fix the class a little,to make it more usable for use with TinyDb
This mean that can take data from TinyDB and use the class.
Will also have the power of TinyDB to eg Query(search).
See that i use self.fname = fname no shortcut,this will make it easier to insert data(Users(**user_1)) from TinyDb to use class.
class Users:
    def __init__(
        self, obj_name, fname, lname, bday, username, password, domain="gmail"):
        self.obj_name = obj_name
        self.fname = fname
        self.lname = lname
        self.bday = bday
        self.username = username
        self.password = password
        self.domain = domain

    @property
    def fullname(self):
        return f"{self.fname}  {self.lname}"

    @property
    def email(self):
        return f"{self.fname.lower()}_{self.lname.lower()}@{self.domain}.com"

    def __str__(self):
        return f"""\
            The following is the info for user {self.username}:
            First Name: {self.fname}
            Last Name: {self.lname}
            Birthdate: {self.bday}
            Email: {self.fname}_{self.lname}@{self.domain}.com
        """

    def __repr__(self):
        return (f'Users({self.obj_name}, {self.fname}, {self.lname}, '+
                f'{self.bday}, {self.username}, {self.password}, {self.domain})')

# --| Test users
# user_1 = Users('user_1', 'Adam', 'Smith', '1/1/2000', 'adam1100', 1234)
# user_2 = Users('user_2', 'Kent', 'Hollow', '5/5/1970', 'kent1200', 4567)
A quick example of __str__ and __repr__ that i put in.
λ ptpython -i db_test.py
>>> user_1 = Users('user_1', 'Adam', 'Smith', '1/1/2000', 'adam1100', 1234)

>>> # Use of __repr__
>>> user_1
Users(user_1, Adam, Smith, 1/1/2000, adam1100, 1234, gmail)

>>> # Use of __str__
>>> print(user_1)
            The following is the info for user adam1100:
            First Name: Adam
            Last Name: Smith
            Birthdate: 1/1/2000
            Email: [email protected]
Use TinyDb,see that i pass in a dictionary with use of __dict__.
λ ptpython -i db_test.py
>>> from tinydb import TinyDB, Query

>>> db = TinyDB('db.json')
>>> user_1 = Users('user_1', 'Adam', 'Smith', '1/1/2000', 'adam1100', 1234)
>>> user_2 = Users('user_2', 'Kent', 'Hollow', '5/5/1970', 'kent1200', 4567)

>>> db.insert(user_1.__dict__)
1
>>> db.insert(user_2.__dict__)
2
>>> exit()
Now i want to use data from database to use the class and also have the option to use TinyDb directly.
λ ptpython -i db_test.py
>>> from tinydb import TinyDB, Query

>>> db = TinyDB('db.json')
>>> User = Query()

# Now take data from DB and instantiate user_1 
>>> user_1 = db.search(User.obj_name == 'user_1')[0]
>>> user_1 = Users(**user_1)

>>> user_1
Users(user_1, Adam, Smith, 1/1/2000, adam1100, 1234, gmail)

# Now is class workings with data from DB.
>>> user_1.email
'[email protected]'

>>> user_1.fullname
'Adam  Smith'
TinyDb directly:
>>> db.search(User.lname == 'Hollow')
[{'obj_name': 'user_2', 'fname': 'Kent', 'lname': 'Hollow', 'bday': '5/5/1970', 'username': 'kent1200', 'password': 4567, 'domain': 'gmail'}]


>>> db.all()
[{'obj_name': 'user_1', 'fname': 'Adam', 'lname': 'Smith', 'bday': '1/1/2000', 'username': 'adam1100', 'password': 1234, 'domain': 'gmail'}, {'obj_name': 'user_2', 'fname': 'Kent', 'lname': 'Hollow', 'bday': '5/5/1970', 'username': 'kent1200', 'password': 4567, 'domain': 'gmail'}]


>>> db.all()[1]
{'obj_name': 'user_2', 'fname': 'Kent', 'lname': 'Hollow', 'bday': '5/5/1970', 'username': 'kent1200', 'password': 4567, 'domain': 'gmail'}