Representation for a method applied on a class in Python - python

Let's say I have the following class:
class Human(object):
def __init__(self, name, last_name):
self.name = name
self.last_name = last_name
def get_last_name(self):
return self.last_name
And I know I can define a __repr__ method for it:
def __repr__(self):
return "Human being, named " + str(self.name) + " " + str (self.last_name)
However, what if I want to define a separate representation for a lastname method, too? I.e., if this is a sample:
>>> me = Human("Jane", "Doe")
>>> me
Human being, named Jane Doe
>>> me.get_last_name()
'Doe'
…then I want the last output be not only the string 'Doe' itself but something like Human being's last name is Doe – how can it be done? How to define a __repr__ (or a __str__) method for a method?
Thanks.

You can not use a special attribute for a function or another attribute. In this case since you have self.last_name in your __init__ function, instead of returning it back in get_last_name() you can apply expected changes on last_name here and return the expected format.
class Human(object):
def __init__(self, name, last_name):
self.name = name
self.last_name = last_name
def get_last_name(self):
# return expected format
And you can directly access last_name if you want to see the raw data.
me = Human("Jane", "Doe")
print(me.last_name)

If you want readable representation override __str__ method. For obtain unambiguous output override __repr__

Related

How to make the Python str() function work with a custom class?

Often, when using a Python Package, I find myself using the str() function to convert a package's custom data-type to a string. If I were to try and create a Python Class for a module, how would I add compatibility to str() function for my package's class?
example:
class Person:
def __init__(self, name, age, likes, dislikes):
self.name = name
self.personality = {
"likes": likes,
"dislikes": dislikes
}
bill = Person("bill", 21, ["coding", "etc"], ["interviews", "socialising"])
strBill = str(bill) # This will store: '<__main__.Person object at 0x7fa68c2acac8>' but I want a dictionary containing all of the variables stored in this 'bill' class
print(strBill)
def __str__(self): will be used when you try to str(my_object). It would also be called in string interpolation such as f'This is my object: {my_object}'
def __repr__(self): will be used to represent your object in a console
>>> class A():
... def __str__(self):
... return 'im a string nicely formatted'
... def __repr__(self):
... return 'class A object'
...
>>> a = A()
>>> print(a)
im a string nicely formatted
>>> a
class A object

For what purpose does it make sense to give a property setter method a return value?

In what context would it make sense to give a class property setter method a return value as shown in the following code snippet?
class Person():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
#property # getter method
def full_name(self):
return ' '.join([self.first_name, self.last_name])
#full_name.setter # setter method
def full_name(self, name):
self.first_name, self.last_name = name.split()
return 'When and how should I use this return value?'
While the setter can return a value, it is meant to be invoked in a context where that return value will be ignored. In something like
p = Person()
p.full_name = "John Doe"
the assignment will be performed by Person.full_name.__set__(p, "John Doe"). If you look in the descriptor how-to, there is a section that demonstrates how the property class might be defined in pure Python. Most important for this question is how __set__ will be implemented:
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
self.fset is your setter. Note that its return value is ignored.
If you want get the value use the get method.
If you want set the value use the programming language rules for set methods.
If you do this you are breaking the rules from POO encapsulation and the principle of single responsibility.
If you want to know more you can access this wikipedia article about single responsibility principle.
Singles responsability is part of the SOLID design pattern and for POO one of the most used pattern. Here is some reference.

Trying to print list of object names, just get memory address instead

Here's the code in question for the Person class:
class Person:
def __init__(self, firstName, lastName, email, yearRounder, symptomatic, tested):
self.firstName = firstName
self.lastName = lastName
self.email = email
self.yearRounder = yearRounder
self.symptomatic = symptomatic
self.tested = tested
def __repr__(self):
return str(self)
I'm assigning these objects to variable names generated on the fly through exec() commands. I'm trying to make it print so that I see a list of the assigned names and not the memory addresses. Can anyone lend a hand?
EDIT: To clarify: Trying to make the objects assign to PatientXXXX variable names instead of the names themselves. For instance, the first person in the database would be assigned as Patient0001 = Person(John, Smith, johnsmith#gmail.com, False, False, False) and then print a list that's like [Patient0001, Patient0002] etc

How to print the contents of contact list when designing a new class

I'm learning and experimenting with Python. How can I pass the contact_list in my second function print_contacts so that it can print the name from the contact_list? I'm sure I am doing something wrong, can anyone please explain why is it so?
class Contact(object):
contact_list = []
def __init__(self, name, email):
self.name = name
self.email = email
return Contact.contact_list.append(self)
# How to pass contact_list to below function?
def print_contacts(contact_list):
for contact in contact_list:
print(contact.name)
To me it doesn't make any sense to have a Contact object also own a contact_list attribute, and even less if it's class-wide instead of instanced. I would do this instead:
class Contact(object):
def __init__(self, name, email):
self.name = name
self.email = email
def __str__(self):
return f"{self.name} <{self.email}>"
# or "{} <{}>".format(self.name, self.email) in older versions of
# python that don't include formatted strings
contacts = []
def print_contacts(contacts: "list of contacts") -> None:
for c in contacts:
print(c)
adam = Contact("Adam Smith", "adam#email.com")
contacts.append(adam)
bob = Contact("Bob Jones", "bob#email.com")
contacts.append(bob)
charlie = Contact("Charlie Doe", "charlie#email.com")
contacts.append(charlie)
print_contacts(contacts)
# Adam Smith <adam#email.com>
# Bob Jones <bob#email.com>
# Charlie Doe <charlie#email.com>
Or alternatively, model an AddressBook that knows how to create Contact objects and display them all.
class AddressBook(list):
def add_contact(self, *args, **kwargs):
new_contact = Contact(*args, **kwargs)
self.append(new_contact)
def display_contacts(self):
for contact in self:
print(contact)
contacts = AddressBook()
contacts.add_contact("Adam Smith", "adam#email.com")
contacts.add_contact("Bob Jones", "bob#email.com")
contacts.add_contact("Charlie Doe", "charlie#email.com")
contacts.display_contacts()
class Contact(object):
contact_list = []
def __init__(self, name, email):
self.name = name
self.email = email
Contact.contact_list.append(self)
#classmethod
def print_contacts(cls):
for contact in cls.contact_list:
print(contact.name)
cont1 = Contact("John", "john#john.com")
cont2 = Contact("Mary", "mary#mary.com")
Contact.print_contacts()
will print
>>John
Mary
To answer your question as to why your code currently doesn't work: first, your init method doesn't need a return call, init is called upon object creation to establish object variables and typically doesn't need to return anything (especially in this case since .append() doesn't provide anything to return). Second, a classmethod seems better suited for what you are trying to do with the second method, and you can read more about that here: What are Class methods in Python for?

How to search within a class from a menu or add to a class from menu-python

I am creating a phone book with python and was stumped on how to search through the class for a specific contact or how to search for a specific entry in the class.
This is what I have so far:
class person:
def __init__(self, first_name, last_name, phone_number):
person.first = first_name
person_last = last_name
person_number = phone_number
class friend:
def __init__(self, email, birth_date):
email = johnny.seagraves8219
birth_date = 8/13/1993
super(friend, self)._init_
ans = True
while ans:
print("""
1. Add a contact
2. Look up contact by name
Press enter to quit
""")
ans = input("What would you like to do?")
if ans == "1":
elif ans == "2":
look_up = input("Who would you like to look up?")
The class will not have entries that you can search through as far as I know. The class is basically just a constructor which is used to create an instance of a, in this case, person in the phone book. You could use an array to hold the instances and then search the array.
for i in arrayName:
if(arrayName[i].first == look_up):
# do something
To create an instance simply call the constructor:
firstPerson = person("Mike", "Ryans", "1800838699")
arrayName.append(firstPerson)
My knowledge of python is fairly limited but this is what I think should work.
Good luck!
To begin with, Flexicon is correct: your person/friend class is just a single entity that holds only a single persons information. To be able to search for people, you'll either need to make an array (list) of person objects, a map (dictionary) mapping a name or nickname to the object (so {'Timmie': <my_timidger_object>}, or you can wrap one of these approaches in a AddressBook class that contains additional methods that one of those basic data structures cannot do for you.
Some other important problems: your friend class does not extend the person, the constructor for a class has two underscores, like __init__; as well, you should add default values for email and birth_date in the person class, or trying to access these later will cause an error; your attribute need self before them or they will not be treated as attribute for the object
Here is Object Orientated (using a list to hold the people) way to do it, though it might be overkill for something this simple:
class person:
def __init__(self, first_name, last_name, phone_number):
self.person.first = first_name
self.person_last = last_name
self.person_number = phone_number
self.email = None #Notice the placeholders?
self.birth_date #Not having this information should not be exceptional
class friend(person): #Here, friend extends person
def __init__(self, email, birth_date):
self.email = email
self.birth_date = birth_date
super(friend, self).__init__()
class AddressBook:
def __init__(self, people = None):
if people:
self.entries = list(people)
else:
self.entries = []
#This is merely an example method, a better way would be to use some relational method like SQL to put in a query to find specific information about the person, but that is beyond the scope of this answer
def find_num(self, first_name, last_name):
for person in self.entries:
if (person.last_name, person.first_name) == (last_name, first_name):
return person
return None

Categories

Resources