Chapter 8: Object-Oriented Programming
8.4: Polymorphism
Polymorphism is an extremely important concept in object-oriented programming because it allows us to use objects from different classes as if they were objects of the same class, thus making code more flexible and reusable. By treating objects as if they were part of the same class, we can perform the same operations on them, even if they have different internal structures or methods.
In Python, polymorphism can be achieved in a number of ways. One method is through method overloading, which involves defining multiple methods with the same name but different parameters. Another way is through method overriding, where a subclass method replaces a method of the same name in its parent class. Finally, duck typing is a concept in Python where the type of an object is determined by its behavior rather than its class, allowing for greater flexibility in code design.
By using polymorphism in our code, we can create more robust and scalable applications that are able to handle a wide range of input data and perform a variety of operations depending on the objects used. In short, polymorphism is a cornerstone of object-oriented programming and a key tool for software developers to ensure that their code is both flexible and efficient.
8.4.1: Method Overloading:
Method overloading is a programming concept that allows a class to have multiple methods with the same name but different arguments. This feature is not supported in Python in the traditional sense, but there are workarounds that can achieve similar functionality. One such workaround is to provide default values for arguments. This can be helpful when you want to provide a default behavior for a method, but still allow users to override it if they need to.
Another way to achieve similar functionality in Python is by using variable-length argument lists. You can use args
and *kwargs
to pass variable-length arguments to a method. This is useful when you are not sure how many arguments a method will need to accept, or when you want to provide a flexible interface for users to interact with your code.
8.4.2: Method Overriding:
Method overriding is a key technique in object-oriented programming that enables a subclass to inherit methods and attributes from its superclass while still allowing it to customize its behavior. This is accomplished by providing a new implementation for a method that has already been defined in the superclass. By doing so, the subclass can extend and modify the functionality of the method to meet its specific needs.
The benefits of method overriding are numerous. First and foremost, it allows for greater flexibility in the design of a program. By being able to customize the behavior of inherited methods, subclasses can tailor their functionality to better fit the specific requirements of their individual use cases. Additionally, method overriding promotes code reuse by enabling subclasses to inherit and modify existing code rather than having to recreate it from scratch.
However, it is important to note that method overriding should be used judiciously. Overriding too many methods can lead to code that is difficult to understand and maintain, and can also lead to unexpected behavior if not done properly. Therefore, it is important to carefully consider the design of a program and the requirements of its use cases before using method overriding.
class Animal:
def speak(self):
return "An animal makes a sound"
class Dog(Animal):
def speak(self):
return "A dog barks"
animal = Animal()
dog = Dog()
print(animal.speak()) # Output: An animal makes a sound
print(dog.speak()) # Output: A dog barks
8.4.3: Duck Typing:
Duck typing is a programming concept that allows you to use an object based on its behavior rather than its class. This means that you can treat any object like a duck, as long as it walks like a duck and quacks like a duck. In other words, if an object behaves like a duck (it has the required methods and properties), you can treat it as a duck, regardless of its actual class.
Python is a language that makes extensive use of duck typing to achieve polymorphism, which allows you to write code that can work with objects of different classes without having to know their exact types in advance. This flexibility is one of the key strengths of Python and has made it a popular choice for developers working on projects with complex, dynamic data structures.
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def get_area(shape):
return shape.area()
circle = Circle(5)
rectangle = Rectangle(4, 6)
print(get_area(circle)) # Output: 78.5
print(get_area(rectangle)) # Output: 24
In the example above, the get_area()
function can calculate the area of any shape object that has an area()
method, regardless of the shape's class. This demonstrates polymorphism in action through duck typing.
Exercise 8.4.1: Method Overloading
Title: Calculate the area of different shapes
Create a class Shape
that has a method area()
which accepts different numbers of arguments to calculate the area of different shapes (circle and rectangle).
Instructions:
- Create a class
Shape
. - Implement an
area()
method that accepts different numbers of arguments. - If there's one argument, treat it as the radius of a circle and calculate the area of the circle.
- If there are two arguments, treat them as the width and height of a rectangle and calculate the area of the rectangle.
- If no arguments or more than two arguments are provided, raise a
ValueError
with an appropriate error message.
class Shape:
def area(self, *args):
if len(args) == 1:
radius = args[0]
return 3.14 * (radius ** 2)
elif len(args) == 2:
width, height = args
return width * height
else:
raise ValueError("Invalid number of arguments")
shape = Shape()
print(shape.area(5)) # Output: 78.5
print(shape.area(4, 6)) # Output: 24
try:
print(shape.area())
except ValueError as e:
print(e) # Output: Invalid number of arguments
Exercise 8.4.2: Method Overriding
Title: Custom __str__
method for Person
and Employee
Create a class Person
and a subclass Employee
. Both classes should have a custom __str__
method to return a string representation of the object.
Instructions:
- Create a class
Person
with attributesfirst_name
andlast_name
. - Implement a custom
__str__
method for thePerson
class that returns the full name. - Create a subclass
Employee
that inherits fromPerson
and has an additional attributeposition
. - Implement a custom
__str__
method for theEmployee
class that returns the full name and position.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Employee(Person):
def __init__(self, first_name, last_name, position):
super().__init__(first_name, last_name)
self.position = position
def __str__(self):
return f"{super().__str__()}, Position: {self.position}"
person = Person("John", "Doe")
employee = Employee("Jane", "Doe", "Software Engineer")
print(person) # Output: John Doe
print(employee) # Output: Jane Doe, Position: Software Engineer
Exercise 8.4.3: Duck Typing
Title: Implement a SoundMaker
function
Description: Create a SoundMaker
function that accepts an object and calls its make_sound()
method, demonstrating duck typing.
Instructions:
- Create a class
Dog
with a methodmake_sound()
that returns the string "Woof!". - Create a class
Cat
with a methodmake_sound()
that returns the string "Meow!". - Implement a function
SoundMaker()
that accepts an object and calls itsmake_sound()
method. - Test the
SoundMaker()
function with instances of bothDog
andCat
.
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
def SoundMaker(animal):
return animal.make_sound()
dog = Dog()
cat = Cat()
print(SoundMaker(dog)) # Output: Woof!
print(SoundMaker(cat)) # Output: Meow!
In this exercise, we have created two classes, Dog
and Cat
, each with their own make_sound()
method. The SoundMaker()
function takes an object as an argument and calls its make_sound()
method without needing to know the exact type of the object. This demonstrates the concept of duck typing in Python.
8.4: Polymorphism
Polymorphism is an extremely important concept in object-oriented programming because it allows us to use objects from different classes as if they were objects of the same class, thus making code more flexible and reusable. By treating objects as if they were part of the same class, we can perform the same operations on them, even if they have different internal structures or methods.
In Python, polymorphism can be achieved in a number of ways. One method is through method overloading, which involves defining multiple methods with the same name but different parameters. Another way is through method overriding, where a subclass method replaces a method of the same name in its parent class. Finally, duck typing is a concept in Python where the type of an object is determined by its behavior rather than its class, allowing for greater flexibility in code design.
By using polymorphism in our code, we can create more robust and scalable applications that are able to handle a wide range of input data and perform a variety of operations depending on the objects used. In short, polymorphism is a cornerstone of object-oriented programming and a key tool for software developers to ensure that their code is both flexible and efficient.
8.4.1: Method Overloading:
Method overloading is a programming concept that allows a class to have multiple methods with the same name but different arguments. This feature is not supported in Python in the traditional sense, but there are workarounds that can achieve similar functionality. One such workaround is to provide default values for arguments. This can be helpful when you want to provide a default behavior for a method, but still allow users to override it if they need to.
Another way to achieve similar functionality in Python is by using variable-length argument lists. You can use args
and *kwargs
to pass variable-length arguments to a method. This is useful when you are not sure how many arguments a method will need to accept, or when you want to provide a flexible interface for users to interact with your code.
8.4.2: Method Overriding:
Method overriding is a key technique in object-oriented programming that enables a subclass to inherit methods and attributes from its superclass while still allowing it to customize its behavior. This is accomplished by providing a new implementation for a method that has already been defined in the superclass. By doing so, the subclass can extend and modify the functionality of the method to meet its specific needs.
The benefits of method overriding are numerous. First and foremost, it allows for greater flexibility in the design of a program. By being able to customize the behavior of inherited methods, subclasses can tailor their functionality to better fit the specific requirements of their individual use cases. Additionally, method overriding promotes code reuse by enabling subclasses to inherit and modify existing code rather than having to recreate it from scratch.
However, it is important to note that method overriding should be used judiciously. Overriding too many methods can lead to code that is difficult to understand and maintain, and can also lead to unexpected behavior if not done properly. Therefore, it is important to carefully consider the design of a program and the requirements of its use cases before using method overriding.
class Animal:
def speak(self):
return "An animal makes a sound"
class Dog(Animal):
def speak(self):
return "A dog barks"
animal = Animal()
dog = Dog()
print(animal.speak()) # Output: An animal makes a sound
print(dog.speak()) # Output: A dog barks
8.4.3: Duck Typing:
Duck typing is a programming concept that allows you to use an object based on its behavior rather than its class. This means that you can treat any object like a duck, as long as it walks like a duck and quacks like a duck. In other words, if an object behaves like a duck (it has the required methods and properties), you can treat it as a duck, regardless of its actual class.
Python is a language that makes extensive use of duck typing to achieve polymorphism, which allows you to write code that can work with objects of different classes without having to know their exact types in advance. This flexibility is one of the key strengths of Python and has made it a popular choice for developers working on projects with complex, dynamic data structures.
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def get_area(shape):
return shape.area()
circle = Circle(5)
rectangle = Rectangle(4, 6)
print(get_area(circle)) # Output: 78.5
print(get_area(rectangle)) # Output: 24
In the example above, the get_area()
function can calculate the area of any shape object that has an area()
method, regardless of the shape's class. This demonstrates polymorphism in action through duck typing.
Exercise 8.4.1: Method Overloading
Title: Calculate the area of different shapes
Create a class Shape
that has a method area()
which accepts different numbers of arguments to calculate the area of different shapes (circle and rectangle).
Instructions:
- Create a class
Shape
. - Implement an
area()
method that accepts different numbers of arguments. - If there's one argument, treat it as the radius of a circle and calculate the area of the circle.
- If there are two arguments, treat them as the width and height of a rectangle and calculate the area of the rectangle.
- If no arguments or more than two arguments are provided, raise a
ValueError
with an appropriate error message.
class Shape:
def area(self, *args):
if len(args) == 1:
radius = args[0]
return 3.14 * (radius ** 2)
elif len(args) == 2:
width, height = args
return width * height
else:
raise ValueError("Invalid number of arguments")
shape = Shape()
print(shape.area(5)) # Output: 78.5
print(shape.area(4, 6)) # Output: 24
try:
print(shape.area())
except ValueError as e:
print(e) # Output: Invalid number of arguments
Exercise 8.4.2: Method Overriding
Title: Custom __str__
method for Person
and Employee
Create a class Person
and a subclass Employee
. Both classes should have a custom __str__
method to return a string representation of the object.
Instructions:
- Create a class
Person
with attributesfirst_name
andlast_name
. - Implement a custom
__str__
method for thePerson
class that returns the full name. - Create a subclass
Employee
that inherits fromPerson
and has an additional attributeposition
. - Implement a custom
__str__
method for theEmployee
class that returns the full name and position.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Employee(Person):
def __init__(self, first_name, last_name, position):
super().__init__(first_name, last_name)
self.position = position
def __str__(self):
return f"{super().__str__()}, Position: {self.position}"
person = Person("John", "Doe")
employee = Employee("Jane", "Doe", "Software Engineer")
print(person) # Output: John Doe
print(employee) # Output: Jane Doe, Position: Software Engineer
Exercise 8.4.3: Duck Typing
Title: Implement a SoundMaker
function
Description: Create a SoundMaker
function that accepts an object and calls its make_sound()
method, demonstrating duck typing.
Instructions:
- Create a class
Dog
with a methodmake_sound()
that returns the string "Woof!". - Create a class
Cat
with a methodmake_sound()
that returns the string "Meow!". - Implement a function
SoundMaker()
that accepts an object and calls itsmake_sound()
method. - Test the
SoundMaker()
function with instances of bothDog
andCat
.
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
def SoundMaker(animal):
return animal.make_sound()
dog = Dog()
cat = Cat()
print(SoundMaker(dog)) # Output: Woof!
print(SoundMaker(cat)) # Output: Meow!
In this exercise, we have created two classes, Dog
and Cat
, each with their own make_sound()
method. The SoundMaker()
function takes an object as an argument and calls its make_sound()
method without needing to know the exact type of the object. This demonstrates the concept of duck typing in Python.
8.4: Polymorphism
Polymorphism is an extremely important concept in object-oriented programming because it allows us to use objects from different classes as if they were objects of the same class, thus making code more flexible and reusable. By treating objects as if they were part of the same class, we can perform the same operations on them, even if they have different internal structures or methods.
In Python, polymorphism can be achieved in a number of ways. One method is through method overloading, which involves defining multiple methods with the same name but different parameters. Another way is through method overriding, where a subclass method replaces a method of the same name in its parent class. Finally, duck typing is a concept in Python where the type of an object is determined by its behavior rather than its class, allowing for greater flexibility in code design.
By using polymorphism in our code, we can create more robust and scalable applications that are able to handle a wide range of input data and perform a variety of operations depending on the objects used. In short, polymorphism is a cornerstone of object-oriented programming and a key tool for software developers to ensure that their code is both flexible and efficient.
8.4.1: Method Overloading:
Method overloading is a programming concept that allows a class to have multiple methods with the same name but different arguments. This feature is not supported in Python in the traditional sense, but there are workarounds that can achieve similar functionality. One such workaround is to provide default values for arguments. This can be helpful when you want to provide a default behavior for a method, but still allow users to override it if they need to.
Another way to achieve similar functionality in Python is by using variable-length argument lists. You can use args
and *kwargs
to pass variable-length arguments to a method. This is useful when you are not sure how many arguments a method will need to accept, or when you want to provide a flexible interface for users to interact with your code.
8.4.2: Method Overriding:
Method overriding is a key technique in object-oriented programming that enables a subclass to inherit methods and attributes from its superclass while still allowing it to customize its behavior. This is accomplished by providing a new implementation for a method that has already been defined in the superclass. By doing so, the subclass can extend and modify the functionality of the method to meet its specific needs.
The benefits of method overriding are numerous. First and foremost, it allows for greater flexibility in the design of a program. By being able to customize the behavior of inherited methods, subclasses can tailor their functionality to better fit the specific requirements of their individual use cases. Additionally, method overriding promotes code reuse by enabling subclasses to inherit and modify existing code rather than having to recreate it from scratch.
However, it is important to note that method overriding should be used judiciously. Overriding too many methods can lead to code that is difficult to understand and maintain, and can also lead to unexpected behavior if not done properly. Therefore, it is important to carefully consider the design of a program and the requirements of its use cases before using method overriding.
class Animal:
def speak(self):
return "An animal makes a sound"
class Dog(Animal):
def speak(self):
return "A dog barks"
animal = Animal()
dog = Dog()
print(animal.speak()) # Output: An animal makes a sound
print(dog.speak()) # Output: A dog barks
8.4.3: Duck Typing:
Duck typing is a programming concept that allows you to use an object based on its behavior rather than its class. This means that you can treat any object like a duck, as long as it walks like a duck and quacks like a duck. In other words, if an object behaves like a duck (it has the required methods and properties), you can treat it as a duck, regardless of its actual class.
Python is a language that makes extensive use of duck typing to achieve polymorphism, which allows you to write code that can work with objects of different classes without having to know their exact types in advance. This flexibility is one of the key strengths of Python and has made it a popular choice for developers working on projects with complex, dynamic data structures.
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def get_area(shape):
return shape.area()
circle = Circle(5)
rectangle = Rectangle(4, 6)
print(get_area(circle)) # Output: 78.5
print(get_area(rectangle)) # Output: 24
In the example above, the get_area()
function can calculate the area of any shape object that has an area()
method, regardless of the shape's class. This demonstrates polymorphism in action through duck typing.
Exercise 8.4.1: Method Overloading
Title: Calculate the area of different shapes
Create a class Shape
that has a method area()
which accepts different numbers of arguments to calculate the area of different shapes (circle and rectangle).
Instructions:
- Create a class
Shape
. - Implement an
area()
method that accepts different numbers of arguments. - If there's one argument, treat it as the radius of a circle and calculate the area of the circle.
- If there are two arguments, treat them as the width and height of a rectangle and calculate the area of the rectangle.
- If no arguments or more than two arguments are provided, raise a
ValueError
with an appropriate error message.
class Shape:
def area(self, *args):
if len(args) == 1:
radius = args[0]
return 3.14 * (radius ** 2)
elif len(args) == 2:
width, height = args
return width * height
else:
raise ValueError("Invalid number of arguments")
shape = Shape()
print(shape.area(5)) # Output: 78.5
print(shape.area(4, 6)) # Output: 24
try:
print(shape.area())
except ValueError as e:
print(e) # Output: Invalid number of arguments
Exercise 8.4.2: Method Overriding
Title: Custom __str__
method for Person
and Employee
Create a class Person
and a subclass Employee
. Both classes should have a custom __str__
method to return a string representation of the object.
Instructions:
- Create a class
Person
with attributesfirst_name
andlast_name
. - Implement a custom
__str__
method for thePerson
class that returns the full name. - Create a subclass
Employee
that inherits fromPerson
and has an additional attributeposition
. - Implement a custom
__str__
method for theEmployee
class that returns the full name and position.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Employee(Person):
def __init__(self, first_name, last_name, position):
super().__init__(first_name, last_name)
self.position = position
def __str__(self):
return f"{super().__str__()}, Position: {self.position}"
person = Person("John", "Doe")
employee = Employee("Jane", "Doe", "Software Engineer")
print(person) # Output: John Doe
print(employee) # Output: Jane Doe, Position: Software Engineer
Exercise 8.4.3: Duck Typing
Title: Implement a SoundMaker
function
Description: Create a SoundMaker
function that accepts an object and calls its make_sound()
method, demonstrating duck typing.
Instructions:
- Create a class
Dog
with a methodmake_sound()
that returns the string "Woof!". - Create a class
Cat
with a methodmake_sound()
that returns the string "Meow!". - Implement a function
SoundMaker()
that accepts an object and calls itsmake_sound()
method. - Test the
SoundMaker()
function with instances of bothDog
andCat
.
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
def SoundMaker(animal):
return animal.make_sound()
dog = Dog()
cat = Cat()
print(SoundMaker(dog)) # Output: Woof!
print(SoundMaker(cat)) # Output: Meow!
In this exercise, we have created two classes, Dog
and Cat
, each with their own make_sound()
method. The SoundMaker()
function takes an object as an argument and calls its make_sound()
method without needing to know the exact type of the object. This demonstrates the concept of duck typing in Python.
8.4: Polymorphism
Polymorphism is an extremely important concept in object-oriented programming because it allows us to use objects from different classes as if they were objects of the same class, thus making code more flexible and reusable. By treating objects as if they were part of the same class, we can perform the same operations on them, even if they have different internal structures or methods.
In Python, polymorphism can be achieved in a number of ways. One method is through method overloading, which involves defining multiple methods with the same name but different parameters. Another way is through method overriding, where a subclass method replaces a method of the same name in its parent class. Finally, duck typing is a concept in Python where the type of an object is determined by its behavior rather than its class, allowing for greater flexibility in code design.
By using polymorphism in our code, we can create more robust and scalable applications that are able to handle a wide range of input data and perform a variety of operations depending on the objects used. In short, polymorphism is a cornerstone of object-oriented programming and a key tool for software developers to ensure that their code is both flexible and efficient.
8.4.1: Method Overloading:
Method overloading is a programming concept that allows a class to have multiple methods with the same name but different arguments. This feature is not supported in Python in the traditional sense, but there are workarounds that can achieve similar functionality. One such workaround is to provide default values for arguments. This can be helpful when you want to provide a default behavior for a method, but still allow users to override it if they need to.
Another way to achieve similar functionality in Python is by using variable-length argument lists. You can use args
and *kwargs
to pass variable-length arguments to a method. This is useful when you are not sure how many arguments a method will need to accept, or when you want to provide a flexible interface for users to interact with your code.
8.4.2: Method Overriding:
Method overriding is a key technique in object-oriented programming that enables a subclass to inherit methods and attributes from its superclass while still allowing it to customize its behavior. This is accomplished by providing a new implementation for a method that has already been defined in the superclass. By doing so, the subclass can extend and modify the functionality of the method to meet its specific needs.
The benefits of method overriding are numerous. First and foremost, it allows for greater flexibility in the design of a program. By being able to customize the behavior of inherited methods, subclasses can tailor their functionality to better fit the specific requirements of their individual use cases. Additionally, method overriding promotes code reuse by enabling subclasses to inherit and modify existing code rather than having to recreate it from scratch.
However, it is important to note that method overriding should be used judiciously. Overriding too many methods can lead to code that is difficult to understand and maintain, and can also lead to unexpected behavior if not done properly. Therefore, it is important to carefully consider the design of a program and the requirements of its use cases before using method overriding.
class Animal:
def speak(self):
return "An animal makes a sound"
class Dog(Animal):
def speak(self):
return "A dog barks"
animal = Animal()
dog = Dog()
print(animal.speak()) # Output: An animal makes a sound
print(dog.speak()) # Output: A dog barks
8.4.3: Duck Typing:
Duck typing is a programming concept that allows you to use an object based on its behavior rather than its class. This means that you can treat any object like a duck, as long as it walks like a duck and quacks like a duck. In other words, if an object behaves like a duck (it has the required methods and properties), you can treat it as a duck, regardless of its actual class.
Python is a language that makes extensive use of duck typing to achieve polymorphism, which allows you to write code that can work with objects of different classes without having to know their exact types in advance. This flexibility is one of the key strengths of Python and has made it a popular choice for developers working on projects with complex, dynamic data structures.
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * (self.radius ** 2)
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def get_area(shape):
return shape.area()
circle = Circle(5)
rectangle = Rectangle(4, 6)
print(get_area(circle)) # Output: 78.5
print(get_area(rectangle)) # Output: 24
In the example above, the get_area()
function can calculate the area of any shape object that has an area()
method, regardless of the shape's class. This demonstrates polymorphism in action through duck typing.
Exercise 8.4.1: Method Overloading
Title: Calculate the area of different shapes
Create a class Shape
that has a method area()
which accepts different numbers of arguments to calculate the area of different shapes (circle and rectangle).
Instructions:
- Create a class
Shape
. - Implement an
area()
method that accepts different numbers of arguments. - If there's one argument, treat it as the radius of a circle and calculate the area of the circle.
- If there are two arguments, treat them as the width and height of a rectangle and calculate the area of the rectangle.
- If no arguments or more than two arguments are provided, raise a
ValueError
with an appropriate error message.
class Shape:
def area(self, *args):
if len(args) == 1:
radius = args[0]
return 3.14 * (radius ** 2)
elif len(args) == 2:
width, height = args
return width * height
else:
raise ValueError("Invalid number of arguments")
shape = Shape()
print(shape.area(5)) # Output: 78.5
print(shape.area(4, 6)) # Output: 24
try:
print(shape.area())
except ValueError as e:
print(e) # Output: Invalid number of arguments
Exercise 8.4.2: Method Overriding
Title: Custom __str__
method for Person
and Employee
Create a class Person
and a subclass Employee
. Both classes should have a custom __str__
method to return a string representation of the object.
Instructions:
- Create a class
Person
with attributesfirst_name
andlast_name
. - Implement a custom
__str__
method for thePerson
class that returns the full name. - Create a subclass
Employee
that inherits fromPerson
and has an additional attributeposition
. - Implement a custom
__str__
method for theEmployee
class that returns the full name and position.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __str__(self):
return f"{self.first_name} {self.last_name}"
class Employee(Person):
def __init__(self, first_name, last_name, position):
super().__init__(first_name, last_name)
self.position = position
def __str__(self):
return f"{super().__str__()}, Position: {self.position}"
person = Person("John", "Doe")
employee = Employee("Jane", "Doe", "Software Engineer")
print(person) # Output: John Doe
print(employee) # Output: Jane Doe, Position: Software Engineer
Exercise 8.4.3: Duck Typing
Title: Implement a SoundMaker
function
Description: Create a SoundMaker
function that accepts an object and calls its make_sound()
method, demonstrating duck typing.
Instructions:
- Create a class
Dog
with a methodmake_sound()
that returns the string "Woof!". - Create a class
Cat
with a methodmake_sound()
that returns the string "Meow!". - Implement a function
SoundMaker()
that accepts an object and calls itsmake_sound()
method. - Test the
SoundMaker()
function with instances of bothDog
andCat
.
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
def SoundMaker(animal):
return animal.make_sound()
dog = Dog()
cat = Cat()
print(SoundMaker(dog)) # Output: Woof!
print(SoundMaker(cat)) # Output: Meow!
In this exercise, we have created two classes, Dog
and Cat
, each with their own make_sound()
method. The SoundMaker()
function takes an object as an argument and calls its make_sound()
method without needing to know the exact type of the object. This demonstrates the concept of duck typing in Python.