1

I'm starting to use classes to create a simple contacts output, and then an updated version like this:

My Contacts
-----------
??? Murphy              555-555-8980
George Smith            555-555-2323
Mike Johnson            555-555-4780
-----------

My Contacts
-----------
Cade Murphy             555-555-8980
President George Smith  555-555-2323
Professor Mike Johnson  555-555-4780
----------

I have the functions set up correctly, but I don't know what to put into class Contact so that it prints what I want.

class Contact:
    # I don't know what to put here     

def print_directory(contacts):
    print("My Contacts")
    print("-----------")
    for person in contacts:
        print(person)
    print("-----------\n")


def main():
    champ = Contact("???", "Murphy", "555-555-8980")
    president = Contact("George", "Smith", "555-555-2323")
    professor = Contact("Mike", "Johnson", "555-555-4780")

    contacts = [champ, president, professor]

    print_directory(contacts)

    champ.set_first_name("Cade")
    president.set_title("President")
    professor.set_title("Professor")

    print_directory(contacts)


main()

I tried looking at tutorials and documentation on classes, but I'm not getting anywhere. Any help would be appreciated, Thank you.

Bryan Zeng
  • 101
  • 2
  • 16
  • 1
    Given your print statements, I'm assuming you are using python3+. You can remove the '():' from the line of code that reads 'class Contact():'; the argument of Contact would be another class for which you could extend properties or attributes. To print a line, you will need to put __str__ method in your class. Typing on mobile but can update later. –  Oct 20 '17 at 01:21
  • @mikey I think you are getting too far away for beginners... – Bryan Zeng Oct 27 '17 at 23:52

3 Answers3

3

if you want to only set the property:

professor.first_name = "Mike"

this will add a property first_name, which value is Mike, dynamically

if you need a setter, make it OO more:

class Contact(object):

    def set_first_name(self, fn):
        self._first_name = fn

and

professor.set_first_name(Mike)

you may want to use __init__, the class constructor, which make it even more OO:

class Contact(object):

    def __init__(self, first_name, last_name, tel):
        # convention: private members' name usually start with '_'
        self._first_name = first_name
        self._last_name = last_name
        self._tel = tel

then you can use:

professor = Contact("Mike", "Johnson", "555-555-4780")

If you want more pythonic OO, you may use a setter/getter decorator:

class Contact(object):

@property
def first_name():
    # this is a getter
    print "getter!"
    return self._first_name

@first_name.setter
def first_name(self, first_name):
    # this is a setter
    print "setter!"
    self._first_name = first_name

You can:

professor = Contact()
professor.first_name = "Mike"  # this calls the setter, set value of `_first_name`
print(professor.first_name) # this calls the getter, return value of `_first_name`

Note: It's a convention in Python that name a private member starts with a _, like _first_name. This hints that outer should not operate this member directly.

Hope this helps.

small update: I think in Python, a list of Contact to represent a PhoneBook is enough in most cases, including cases when you need to use some ORM/ODM lib to write it to database. No need for a PhoneBook class. Just my thinking.

small update 2: Some says about __str__ in answers and comments, it's a good point. See @Bryan Zeng 's answer. And also there is a thing called __repr__ provides similar function with __str__.

This question may helps: Difference between __str__ and __repr__ in Python

I recommend a Book "Fluent Python", it introduced a lot of "magic functions" (functions that start and end with double under line) in the OO chapter, which will provide great help in Python OO programming.

small update 3: fix errors on setter/getter decorator. I did not use it for a while and I wrote it wrong... @setter should be @first_name.setter. Sorry about this.

raaay0608
  • 105
  • 9
3

First, it need's to initialize so put a __init__ function.

class Contact:
    def __init__(self, first_name, last_name, phone_number): # Arguments. self is always needed.
        self.first_name = first_name
        self.last_name = last_name
        self.phone_number = phone_number

So then the class has three variables. Second, it needs to turn into a string.

class Contact:
    def __init__(self, first_name, last_name, phone_number): # Arguments. self is always needed.
        self.first_name = first_name
        self.last_name = last_name
        self.phone_number = phone_number

    def __str__(self):
        return "%s %s \t %s" % (self.first_name, self.last_name, self.phone_number)

You have a set_first_name function in the code, so make one

class Contact:
    def __init__(self, first_name, last_name, phone_number): # Arguments. self is always needed.
        self.first_name = first_name
        self.last_name = last_name
        self.phone_number = phone_number

    def __str__(self):
        return "%s %s \t %s" % (self.first_name, self.last_name, self.phone_number)

    def set_first_name(self, first_name):
        self.first_name = first_name

And last, you have a set_title function in your code

class Contact:
    def __init__(self, first_name, last_name, phone_number): # Arguments. self is always needed.
        self.first_name = first_name
        self.last_name = last_name
        self.phone_number = phone_number
        self.title = None

    def __str__(self):
        if self.title is None:
            return "%s %s \t %s" % (self.first_name, self.last_name, self.phone_number)
        else:
            return "%s %s %s \t %s" % (self.title, self.first_name, self.last_name, self.phone_number)

    def set_first_name(self, first_name):
        self.first_name = first_name

    def set_title(self, title):
        self.title = title
Bryan Zeng
  • 101
  • 2
  • 16
2

In object-oriented programming (OOP), classes define objects which hold related properties.

The simplest way to represent your contacts in a class would be (you guessed it) using a Contact class, but for cleanness we'll also have a Phonebook class:

class Contact:
    def __init__(self, first_name, last_name, phone_number):
        # The init method is the one called when you instantiate the class
        # Ideally it takes all mandatory parameters, that is
        # Information without which the object would not fulfill its job

        # We could do other stuff, but here we only save the parameters given
        # as object properties so you can refer to them later
        self.first_name = first_name
        self.last_name = last_name
        self.phone_number = phone_number

    def print_info(self):
        # Ideally a data operation class wouldn't be printing anything
        # We should return this information as a string and handle it elsewhere
        # We'll print it right out of the bat though to keep it straightforward
        print(self.first_name, self.last_name, self.phone_number)

class Phonebook:
    def __init__(self):
        # The phonebooks don't need any special stuff to exist, 
        # so the only parameter taken is the implicit self
        self.contact_list = []

    def add(self, contact):
        # Here is a method that adds an instance of Contact to the list
        self.contact_list.append(contact)
        return self

    def get_all(self):
        # Again, IDEALLY this would be what we would call
        # And this list would be handled elsewhere to be printed...
        return self.contact_list

    def print_all(self):
        # ...however this is a small program, and this class can print itself
        print("My contacts")
        print("-----------")
        for contact in self.contact_list:
            contact.print_info()
        print("-----------\n")

def main():

    phonebook = Phonebook() # Phonebook had no __init__, so no params are used

    # Then we create the contacts (remember the params we defined at __init__)
    champ = Contact("???", "Murphy", "555-555-8980")
    president = Contact("George", "Smith", "555-555-2323")
    professor = Contact("Mike", "Johnson", "555-555-4780")

    # And we add them to the phonebook (remember method add)
    # We can chain all .add calls because of the "return self" line
    phonebook.add(champ).add(president).add(professor)

    # We can then print everything!
    phonebook.print_all()

main()

Edit

As has been pointed out, Python has a built-in __str__ method and we wouldn't need to define print_info(). I didn't change my block of code since I guess explicitly explaining methods would be better for starters. Still, the more appropriate way would be to define __str__ and then print(contact) instead of calling contact.print_info().

gchiconi
  • 624
  • 1
  • 7
  • 17
  • 2
    how about instead of the `print_info`, going with `__str__` – 0TTT0 Oct 20 '17 at 01:38
  • 1
    Good point, though since OP doesn't seem to be used to OOP I guess going the more language-agnostic way (what I did) is also valid. I'll edit this in. – gchiconi Oct 20 '17 at 01:45