Home > Back-end >  Why am I receiving this AttributeError: 'Contact' object has no attribute 'print_entr
Why am I receiving this AttributeError: 'Contact' object has no attribute 'print_entr

Time:10-22

I was given the code that begins with the print_directory function and told not to alter anything below that. I've created the contact class above. Why am I receiving the attribute error, and how would I fix it? I'm trying to create a class that uses the variables in the main function to return the first name, last name, and phone numbers of the contacts list.

My code is below:

class Contact:
    fname = ""
    lname = ""
    p_number = ""
    
    def __init__(self,fname,lname,p_number):
        self.fname = fname
        self.lname = lname
        self.p_number = p_number
        
    def getfname(self):
        return self.fname
    
    def getlname(self):
        return self.lname
    
    def getp_number(self):
        return self.p_number


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

# -----------------------------------------------------

def main():
    champ = Contact("???", "Bobcat", "406-994-0000")
    president = Contact("Waded", "Cruzado", "406-994-CATS")
    professor = Contact("John", "Paxton", "406-994-4780")

    contacts = [champ, president, professor]

    print_directory(contacts)

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

    print_directory(contacts)

    print("The area code for cell number", champ.get_cell_number(), "is", \
           champ.get_area_code())

# -----------------------------------------------------

main()

CodePudding user response:

Hi it's seem that you trying to call a method that not exist for the "Contact" class.

person.print_entry()

the class Contact does not know to do with that call.

maybe you have to implement an print_entry() method in the class:

class Contact:
    fname = ""
    lname = ""
    p_number = ""
    
    def __init__(self,fname,lname,p_number):
        self.fname = fname
        self.lname = lname
        self.p_number = p_number
        
    def getfname(self):
        return self.fname
    
    def getlname(self):
        return self.lname
    
    def getp_number(self):
        return self.p_number
    
    def print_entry(self):
        print(f" Name: {self.lname}, {self.fname}, Number: {self.p_number}")

CodePudding user response:

Your code will throw AttributeError: 'Contact' object has no attribute 'print_entry' because in your Contact class the method print_entry isn't defined.

Additionally you will also need to define set_first_name, and set_title in your Contact class or any lines where you call these class methods will throw a similar AttributeError.

You can add a definition for print_entry like this:

class Contact:
...
    def print_entry(self):
        # add your desired print statement here
...

Then use a similar structure to add your set_first_name and set_title methods. Something like this:

class Contact:
...
    def set_first_name(self, fname):
        self.fname = fname
...

However it is unclear which instance variable you want set_title to modify. You might consider adding another instance variable called title to your class.

CodePudding user response:

TL;DR: Define a method print_entry(self) that uses print to output as expected (this solution was already answered).

A more idiomatic, object-oriented and maintainable solution would be to use __str__ and print in two different levels (see below).

Background

Attribute Error explained

This is always a signal that your class or a third-party class is missing some attributes that you referenced, like accessed fields or invoked methods.

So you need to define it or if a third-party module used via import, you should check version-mismatches, etc.

Printing an object's representation

In almost every object-oriented programming-language there is a method that converts the object instance to a string representation. In Python this is either __repr__(self) or __str__(self) (similar like toString() in Java). These are standard methods (recognize by the surrounding double underscores __) that already exist and usually can be overridden.

Solution

Instead calling and defining print_entry instance-method, override the __str__ method like:

class Contact:
    # omitted other to focus on string method
    def __str__(self):
        return "Name: "   self.last_name   ", "   self.first_name;

and use it to print a Contact object instance person like: print(person)

See also: How to print instances of a class using print()?

Benefits:

  • this is an object-oriented pattern, reusing Python's standard
  • keeping all print statements in one place (principle: abstraction-level, code-symmetry) like in your method print_directory
  • string-representation (__str__) separated from UI/output-layer (print) so that they can be changed independently (principle: separation of concerns & single-responsibility)

Bonus

Tips:

  • use an IDE like PyCharm (free community edition) or Eric, that will warn you in advance and offers quick-fix actions to add the missing attributes (methods, etc.).
  • python naming convention for fields and methods is both lower snake-case, e.g. first_name
  • setters need to be defined too, i.e. set_first_name(self), set_title(self)
  • getters used for get_cell_number and get_area_code are missing in class (whereas there is a field p_number with getter
  • meaningful names instead abbreviations usually pay-off in the long-run: phone_number can be distinguished from person_number (some IDEs offer dictionary-assisted auto-completion and will pass spellchecking this way)
  • a pythonic way for string-interpolation using templates (since Python 3) are f-strings (see applied in Ulises answer)
  • Related