Need Clarification on Using OOP and DRY Method in Python

169 views Asked by At

I'm trying to keep my code clean by applying OOP and DRY method; however, I found myself stuck with the following questions.

1) Since checkremote and backup method are dependent on the sshlogin method, is there another way to write it so that my object is fully initialized?

2) If there isn't a better way, where do I write the procedure for the PhoneBook Class to execute in the following manner (1 - checklocal, 2 - sshlogin, 3 - checkremote, 4 - backup)? In main?

class PhoneBook:

    def __init__ (self, name, phone_number, birthdate, location):
        self.name = name
        self.phone_number = phone_number
        self.birthdate = birthdate
        self.location = location
        self.ssh = None

    def checklocal (self):
        # Check local phonebook for existing names
        pass


    def sshlogin (self):
        # SSH into remote server


    def checkremote (self):
        # Check remote phonebook for existing names
        pass


    def backup (self):
        # Backup remote phonebook
1

There are 1 answers

3
Rick On

In this case, you probably want to use a context manager and the with keyword.

Since using a Phonebook object requires a "set up" phase beforehand, you want to make sure that is handled correctly every time you use it. So you would able to write code like this:

with Phonebook(name, phone_number, birthdate, location) as phbk: 
    #do stuff with the phonebook
    phbk.add(name, phone_number, birthdate, location)

All your setup phase steps - checking the local copy, connecting (and disconnecting) the ssh session, checking the remote copy, backup, etc. - would happen "behind the scenes" as part of the setup/tear down of the context manager (in other words, the with statement takes care of all that). This is similar to how you are supposed to use open():

with open('myfile') as file:
    lines = file.readlines()

Cleanly opening and closing the file happens "behind the scenes", automagically. This is likely what you want to happen with your phonebook.

To get the context manager working, you use the python __enter__ and __exit__ magic methods. Might look something like this:

class PhoneBook:

    def __init__ (self, name, phone_number, birthdate, location):
        self.name = name
        self.phone_number = phone_number
        self.birthdate = birthdate
        self.location = location
        self.ssh = None

    def sshlogin(self):
        # SSH into remote server

    def sshlogout(self):
        # SSH out of remote server

    def checklocal(self):
        # Check local phonebook for existing names
        pass        

    def checkremote (self):
        # Check remote phonebook for existing names
        pass            

    def backup (self):
        # Backup remote phonebook

    def __enter__(self):
        self.checklocal()
        self.sshlogin()
        self.checkremote()
        self.backup()
        return self

    def __exit__(self, cls, value, traceback):
        self.sshlogout()
        return False

As for your Add (and Delete) class, it really shouldn't be a class. It should probably either be:

  • a method of the Phonebook class, like so:

    class Phonebook:
        def __init__(self):
            self.ssh = None
        def add(self, name, phone_number, birthdate, location):
            self.name = name
            self.phone_number = phone_number
            self.birthdate = birthdate
            self.location = location
    

    or

  • a generic function, like so:

    def Add(phbk, name, phone_number, birthdate, location):
        # add to remote phonebook
    

A further point: your Phonebook class isn't named very well. Based on the __init__ method, it's more of a phonebook entry. You may want to consider implementing your phonebook (as a context manager, as explained above) separately as a container of some kind to hold your entries (including the add and delete methods), and focus the Phonebook class you have (renamed as Entry or something) on being more of a phonebook Entry object that can be added to your new Phonebook object, in which case the add method might be more like this:

    def add(self, entry):
        try:
            self.entries.append(entry)
        except AttributeError:
            self.entries = [entry] 

One other thing: I noticed you're using tab characters to define your classes, functions, and what not. This is against the recommended practice - use 4 spaces instead.

A further suggestion: for something so simple as my suggested Entry class, you might just want to use a collections.namedtuple, like so:

from collections import namedtuple as nt
Entry = nt('Entry', 'name phone_number birthdate location')

Now you can do stuff like this:

e = Entry('rick', '8675309', '1/1/2001', '125 Sesame St`)
print(e.name)