How to format strings in classes using attributes? - python

I want to format an attribute-string of a class with another attribute of the same class like this:
class Test:
def __init__(self):
self.name = None
self.full_name = 'name, {}'.format(self.name)
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Now it should print 'name, my_object'
But it prints 'name, None'
What to do that the string formats with the assigned value of the object?

You need to add full_name as a property so that you can add some more logic to it:
class Test:
def __init__(self):
self.name = None
#property
def full_name(self):
return f'name, {self.name}'
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Resources:
property function (built-in)

Related

Can't print an object from a class

sorry but I just started learning python not too long ago and I'm stuck in thisprogram code, I just can't get it to work like it should.
class Dog():
def __init__(self,name,breed,owner):
self.name = name
self.breed = breed
self.owner = owner
class Person():
def __init__(self,name):
self.name = name
mick = Person("Mick Jagger")
dog = Dog("Stanley","French Bulldog",mick)
print(dog.owner)
I want to get the dog's owner name but all I get is this:
= RESTART: C:/Coding Practice/Object Oriented Programming.py =
<__main__.Person object at 0x000002C5DFB02050>
Help would be appreciated.
You can use __str__ or __repr__ to get all the object's attributes in a more human-readable format.
__str__ (read as "dunder (double-underscore) string") and __repr__ (read as "dunder-repper" (for "representation")) are both special methods that return strings based on the state of the object.
class Dog():
def __init__(self,name,breed,owner):
self.name = name
self.breed = breed
self.owner = owner
def __str__(self):
return str(self.__class__) + '\n'+ '\n'.join(('{} = {}'.format(item, self.__dict__[item]) for item in self.__dict__))
class Person():
def __init__(self,name):
self.name = name
def __str__(self):
return str(self.__class__) + '\n'+ '\n'.join(('{} = {}'.format(item, self.__dict__[item]) for item in self.__dict__))
mick = Person("Mick Jagger")
dog = Dog("Stanley","French Bulldog", mick)
print(dog.owner)
str
If you print an object, or pass it to format, str.format, or str, then
if a str method is defined, that method will be called, otherwise,
repr will be used.
repr
The repr method is called by the builtin function repr and is what
is echoed on your python shell when it evaluates an expression that
returns an object.
when you assign self.owner = owner self.owner stores the reference of owner object you should access the name value by mentioning the attribute self.owner = owner.name.
class Dog():
def __init__(self,name,breed,owner):
self.name = name
self.breed = breed
self.owner_name = owner.name
class Person():
def __init__(self,name):
self.name = name
mick = Person("Mick Jagger")
dog = Dog("Stanley","French Bulldog",mick)
print(dog.owner_name)
You should add __repr__ and __str__ methods to the Person class. Or just __repr__.
class Person:
def __init__(self,name):
self.name=name
def __repr__(self)
return str(self.name)

transform class methods using parent class' decorator method

def greeting_decorator(original_function):
def return_function(*args):
name = 'John'
return f'Hi, I\'m {name}, fullname: {original_function(*args)}'
return return_function
#greeting_decorator
def greeting(name, surname):
return f'{name} {surname}'
print(greeting('John', 'Doe'))
Above, I have a simple decorator function that works as intended.
I'd like to do something similar, but with an inherited class.
How might I go about inheriting a decorator function like this:
class Guy:
def __init__(self, name):
self.name = 'John'
def greeting_decorator(self, original_function):
def return_function(*args):
return f'Hi, I\'m {self.name}, fullname: {original_function(*args)}'
return return_function
class GuyWithSurname(Guy):
def __init__(self, name, surname):
super().__init__(name)
self.surname = surname
#greeting_decorator # <----- here
def __str__(self):
return f'{self.name} {self.surname}'
JohnDoe = GuyWithSurname('John', 'Doe')
print(JohnDoe)
If you are certain that the parent class will always be Guy, you can simply annotate via #Guy.greeting_decorator:
class Guy:
def __init__(self, name):
self.name = 'John'
def greeting_decorator(original_function):
def return_function(self, *args):
return f'Hi, I\'m {self.name}, fullname: {original_function(self, *args)}'
return return_function
class GuyWithSurname(Guy):
def __init__(self, name, surname):
super().__init__(name)
self.surname = surname
#Guy.greeting_decorator # <----- here
def __str__(self):
return f'{self.name} {self.surname}'
JohnDoe = GuyWithSurname('John', 'Doe')
That way, when you call print(JohnDoe) it will output Hi, I'm John, fullname: John Doe.
Note that I had to change the greeting_decorator and the return_function parameters to properly handle self.

How to supplement __repr__() of parent class in subclass to output additional subclass features

Lets say I have parent class A and child class B like this:
class A:
def __init__(self,name):
self.name = name
def __repr__(self):
return f"My name is: {self.name}"
class B(A):
def __init__(self,name,surname):
super(B,self).__init__(name)
self.name = name
self.surname = surname
def __repr__(self):
return f"My name is: {self.name} {self.surname}"
a = A("Jhon")
b = B("Bon","Boby")
print(a)
print(b)
Is there any way to modify the B.__repr__() without repeating code from parent class and use A.__repr__() to just append the surname to its value?
Solution that seems to work is to call super(B,self).__repr__() within B's __repr__() like this:
class A:
def __init__(self,name):
self.name = name
def __repr__(self):
return f"My name is: {self.name}"
class B(A):
def __init__(self,name,surname):
super(B,self).__init__(name)
self.name = name
self.surname = surname
def __repr__(self):
s = super(B,self).__repr__()
s += f" {self.surname}"
return s
a = A("Jhon")
b = B("Bon","Boby")
print(a)
print(b)

How to use class methods in python?

I have this code
class Person(object):
def __init__(self, name):
self.name = name
#classmethod
def from_classmethod(cls, name):
return cls(name)
p = Person.from_classmethod("Moctar")
p.name
But it shows the following error:
AttributeError: 'Person' object has no attribute 'name'
What could be going wrong here, or am i using wrongly the python #classmethod feature ?
As #furas says, what I think you want is:
class Person(object):
def __init__(self, name):
self.name = name
#classmethod
def from_classmethod(cls, name):
return cls(name)
p = Person.from_classmethod("Moctar")
print(p.name)
Result:
Moctar
It is the assignment to self.name that creates that attribute on the instance of Person that you are creating.

How to create a list out of a class?

Let's say I have a class named Books that has the variables: author, title, and book_id. And then I have another class name Patrons that has the variables: name, patron_id, and borroweds.Borroweds is supposed to be a list of Books currently "checked out" so I would have to encorporate the class Books into the class Patron. But how would I go about doing that?
This is what I have so far:
class Book:
author= ""
title = ""
book_id= ""
# the class constructor
def __init__(self, author, title, book_id):
self.title = title
self.author = author
self.book_id = book_id
def __str__(self):
s = str("Books("+str(self.author)+", "+str(self.title)+", "+str(self.book_id+")"))
return s
def __repr__(self):
return str(self)
class Patron:
name= ""
patron_id= ""
borroweds= list()
# the class constructor
def __init__(self, name, patron_id, borroweds):
self.name= name
self.patron_id= patron_id
self.borroweds= borroweds
def __str__(self):
s= str("Patron("+str(self.name)+","+str(self.patron_id)+","+list(self.borroweds)+")")
return s
def __repr__(self):
return str(self)
borroweds = [Book('Author Authorsson', 'The book of books', 'ISBN76576575757')]
patron = Patron('thename', 'theid', borroweds)
>>> patron
Patron(thename,theid,[Books(Author Authorsson, The book of books, ISBN76576575757)])
>>> patron.borroweds[0]
Books(Author Authorsson, The book of books, ISBN76576575757)
Also, skip the class attributes, you don't need them.
class Book:
# the class constructor
def __init__(self, author, title, book_id):
self.title = title
self.author = author
self.book_id = book_id
def __str__(self):
s = str("Books("+str(self.author)+", "+str(self.title)+", "+str(self.book_id+")"))
return s
def __repr__(self):
return str(self)
class Patron:
# the class constructor
def __init__(self, name, patron_id, borroweds):
self.name= name
self.patron_id= patron_id
self.borroweds= borroweds
def __str__(self):
s= str("Patron("+str(self.name)+","+str(self.patron_id)+","+str(self.borroweds)+")")
return s
def __repr__(self):
return str(self)
Did you notice the typo in the __str__ method of Books? Your parenthesis at the end needs moved left, after self.book_id.
You don't need the class attributes because they are for "global" purposes for every 'Patron'. So if you wanted to keep track of how many patrons you make, you could update that "global" variable each time you make one, like this:
class Patron:
patron_id= 0
# the class constructor
def __init__(self, name, borroweds):
self.name= name
self.patron_id=self.patron_id
self.borroweds= borroweds
Every time you create a Patron object you could add one to the class attribute:
p1 = Patron('Dave',[Book('Me','Something', '8675309')])
print p1.patron_id
Patron.patron_id+=1
p2 = Patron('Dave',[Book('You','Others', 'Number9')])
print p2.patron_id
You'll notice the class attribute was changed and set the objects attribute. You could even create a class attribute in Patron that was a list of every Patron object and add each one during the __init__ method if you wanted. Its going to keep track of it for the class.
Also, I think you need ","+list(self.borroweds)+")" to be ","+str(self.borroweds)+")"

Categories