5
\$\begingroup\$

I'm very new to OOP, and I'm trying to do it correctly!
I have been doing a simple friendbook where you can add, remove and show the friends you have. However, I dont know if I should be satisfied or not with my code.

class Friendbook:

    listOfFriends = {}

    def __init__(self, name, lastname):
        self.name = name
        self.lastname = lastname

    def addFriend(self):
        self.listOfFriends[self.name] = self.lastname

    def showFriends(self):
        for firstname, lastname in self.listOfFriends.items():
            print(firstname, lastname)

    def removeFriend(self):
        removeName = input("Enter name to remove\n")
        del self.listOfFriends[removeName]


while True:

    print("1. Add Friend\n2. Showfriends\n3. RemoveFriend\n9. Quit\n")
    try:
        selectedOption = int(input())
        if selectedOption == 1:
            name = input("Enter firstname\n") #Can i move this to a function?
            lastname = input("Enter lastname\n") #Can i move this to a function?
            makeFriends = Friendbook(name, lastname)
            makeFriends.addFriend()
        elif selectedOption == 2:
            makeFriends.showFriends()
        elif selectedOption == 3:
            makeFriends.removeFriend()
        elif selectedOption == 9:
            break
        else:
            print("Not a valid option")
    except:
        print("Only integers allowed")

I'm happy with it except for the code related to selectedoption 1, can I do something to put it inside the function so it looks nicer? What do you think about my code in general, appreciate feedback!

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

You are using classes wrong. With your class, you can never have two friend books, because each instance uses the classes mutable listOfFriends. (N.B.: A dictionary called listOf... is not very helpful).

Instead, have one FriendBook object, and let its methods take arguments:

class FriendBook:

    def __init__(self):
        self.friends = set()

    def add(self, firstname, lastname):
        self.friends.add((firstname, lastname))

    def remove(self, firstname, lastname):
        self.friends.remove((firstname, lastname))

    def __str__(self):
        return '\n'.join("{} {}".format(*name) for name in self.friends)

A few notes:

  1. The friends are a set now (this assumes that no two friends share the same first and last name, already a better assumption than yours, which assumed that every friend had a unique last name). You could also make it a list, you would just have to change self.friends.add to self.friends.append.
  2. The magic function __str__ allows simply calling print(fb), where fb is an instance of FriendBook, to print the full list of friends.
  3. I made the names a bit easier. Note that Python has an official style-guide, PEP8, which recommends using PascalCase for classes and snake_case everywhere else.

For your main question, yes you can put these in a function:

def ask_name():
    first_name = input("Enter firstname\n")
    last_name = input("Enter lastname\n")
    return first_name, last_name

I would also slightly rewrite your main function, like this:

if __name__ == "__main__":
    fb = FriendBook()
    while True:
        print("1. Add Friend\n2. Show Friends\n3. Remove Friend\n9. Quit\n")
        try:
            option = int(input())
        except ValueError:
            print("Only integers allowed")
            continue
        if option == 1:
            fb.add(*ask_name())
        elif option == 2:
            print(fb)
        elif option == 3:
            fb.remove(*ask_name())
        elif option == 9:
            break
        else:
            print("Not a valid option")

Notes:

  1. I wrapped it all in a if __name__ == "__main__" guard to allow importing this class from another script.
  2. I use the defined function to ask for the names and use tuple unpacking to pass it to the methods.
  3. I limited the scope of the try...except clause and made it more specific. Your current except covered everything, even, for example, the user pressing Ctrl+C. You should almost always avoid doing this.
\$\endgroup\$
0
\$\begingroup\$

For the current amount of information stored it is fine (especially @Graipher's answer). However, if you might want to add information to each friend in the future then I might be better to make a Friend class. It would work like this:

class Friend:
    def__init__(self, firstname, lastname, age = None, address = None):
        self.firstname = firstname
        self.lastname = lastname
        self.age = age
        self.address = address
    def __str__(self):
        age = ", " + str(self.age) if self.age != None else ""
        address = ", " + str(self.address) if self.address != None else ""
        return("{}, {}{}{}".format(self.firstname, self.lastname, age, address)

class Friendbook:
    def __init__(self):
        self.friends = set()
    def __str__(self):
        out = ""
        for friend in self.friends:
            out += str(friend) + "\n"
        return(out)
    def add_friend(self, friend):
        self.friends.add(friend)
    def remove_friend(self, friend):
        self.friends.remove(friend)


def ask_name():
    yes_age = input("Do you know their age (y/n): ").lower()
    yes_address = input("Do you know their address (y/n): ").lower()
    firstname = input("First name: ")
    lastname = input("Last name: ")
    age = input("Age: ") if yes_age == "y" else None
    address = input("Address: ") if yes_address == "y" else None
    return(firstname, lastname, age, address)

if name == __main__:
    fb = Friendbook()
    while True:
        print("1. Add Friend\n2. Show Friends\n3. Remove Friend\n9. Quit\n")
        try:
            option = int(input())
        except ValueError:
            print("Only integers allowed")
            continue
        if option == 1:
            fb.add_friend(Friend(*ask_name()))
        elif option == 2:
            print(fb)
        elif option == 3:
            fb.remove_friend(Friend(*ask_name())
        elif option == 9:
            break
        else:
            print("Not valid!")

This code can also have more stuff put into individual friends so there could be a way to put their email in or even a command to the friend class to send them a message. Although this is longer currently, it adds an extra layer of abstraction which would make it easier to add more functionality.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.