OOPS Concepts
OOPS Concepts
points
Contents
1. Objects and classes in Python
2. Type hints, type checking
3. Make your objects work
4. Module, packages, imports
5. Basic or Single Inheritance
6. Overriding and super()
7. Multiple inheritance
8. The diamond problem
9. Polymorphism
10. Ducktyping in python
11. Encapsulation
12. Method Overloading
13. Operator overloading
14. An alternative to overloading
15. Properties in python
16. Decorators
17. Deciding when to use OOP
18. Python built in functions
19. Data structures
20. Using defaultdict
21. Handling file - File I/O
22. Working with strings
23. Iterators, Generators and Yield
24. Difference between yield and return
25. Handling exceptions
26. Challenging topics
Objects and classes
DESCRIPTION
1. An object is a single instance of a class. You can create many objects from the same class
type.
2. Objects - container - which has both data and functionality
3. We create custom user-defined type class using class statement , with class methods
(callable as functions) and class data can be accessed via objects
4. The class definition line is followed by the class contents, indented. , but it does not allow to
instantiate objects of that class. We have to instantiate objects separately
5. Attributes are defined as - objects , methods or data of the class
FOCUS POINTS
Type information, what an object or method is - classes associated with it, no relation with type of
variable
This code snip shows giving a type hint to parameter n to be int and that method odd will return the
result in bool
● We don’t explicitly pass self keyword while initializing the object, python automatically do
that
● special name, __init__. The leading and trailing double underscores means this is a special
method that the Python interpreter will treat as a special case
● We need to be sure that objects respect each other's privacy and avoid complexity
Modules, packages and imports
1. import * syntax, it takes a lot longer to find where that class is located.
2. explicitly import the database class at the top of our file using from database
import Database
3. Absolute imports specify the complete path to the module, function, or class we
want to import —-import ecommerce.products
4. we could specifically import a single class definition from the module within a
package: from ecommerce.products import Product
5. Relative import - when we know exactly where our class or module inside the
package, then we use relative imports – from .database import Database
6. use the database package inside the parent package – from ..database import
Database
7. import code that appears to come directly from a package, we can import
package as a whole
8. every module has a __name__ special variable that specifies the name of the
module when it was imported.
Order and passing wrong number of arguments
FOCUS POINTS
1. If the method requires n parameters and you do not pass the same number of arguments then an error
will occur.
2. Order of the arguments matters.
Basic / Single Inheritance
FOCUS POINTS
● Define a class that takes all functionality from parent class, Child class can access data
and objects of parent class
● The simplest use of inheritance is to add new behavior to existing classes
● The superclasses, or parent classes, in the relationship are the classes that are being
inherited from, object
● If some of our contacts are suppliers too, so like the Contact class we make another
class Supplier, with all properties of Contact with an additional parameter ‘order’ , with
yet-to-be defined later Order object
● attributes of Contact class available to the Supplier class.We don't need to define them
again (code reusability).
class Supplier(Contact):
def order(self, order: "Order") -> None
Imp point with self keyword in inheritance
The self keyword can only provide access to an existing class-based variable. If you
ever attempt to set the variable using self.all_contacts, you will actually be creating a
new instance variable associated just with that object.
#depict polymorphism
class Square:
The built-in function len() calculates the length of an object depending upon its type. If
an object is a string, it returns the count of characters, and If an object is a list it
returns the count of items in a list.
Eg: does not care about whether an object is a duck, but instead it does only care about
whether it quacks.
>>> a
'AB'
● You need not create multiple functions that do the same job just because you have a different set of
parameters
● Method overloading - by which you can call the same method in different ways, i.e. with different
parameters based on the number of arguments or their different datatypes
● methods should have the same name.
● Method overloading in
● improves the code reusability
return a + b
return a + b + c
Operator overloading
● When we have to use python operators on objects , then we use operator overloading
● When we use an operator on user defined data types (class objects) then automatically
a special function or magic function associated with that operator is invoked.
● Changing the behavior of operator is as simple as changing the behavior of method or
function.
● We define methods in the class and operators work according to that behavior defined in
methods.
● When we use + operator, the magic method __add__ is automatically invoked in which
the operation for + operator is defined.
● There are several in-built methods as well to implement operator overloading
we should use the len() function instead of the __len__() method because
__len__() is a special double-underscore method, and we shouldn't call it
directly
2. reverse() - takes any sequence as input and returns a copy of that sequence in
reverse order. It is normally used in for statements when we want to iterate over
items from back to front - similar to len() function __reversed()__ will be treated
special and will be called on the class for the parameter
3. enumerate() better alternative while iterating using for statement. Iit creates a
sequence of tuples, where the first object in each tuple is the index and the
second is the original item.
Data structures
● Immutable objects, including numbers, strings, bytes, and tuples. These will often
have extended operators defined.
● Mutable collections, including sets, lists, and dictionaries, these are sized, iterable
containers
1. Empty objects - Technically, we can instantiate an object without writing a
subclass, but you cannot set any attribute later to any instaited object - class
MyObject is equivalent to class MyObject(object)
2. Lists
3. Tuples - are objects that can store a specific number of other objects in sequence
4. NamedTuples
5. Sets
Lists
FOCUS POINTS
List comprehensions - create a new list based on the values of an existing list.
Without list comprehensions you need to sue for loop to iterate over elements
● Tuples are objects that can store a specific number of other objects in sequence
● Major difference between list and tuple is that they are immutable - means we
can't add, remove, or replace objects and are dented by ()
● if you need to modify a tuple, you're using the wrong data type (usually, a list would
be more suitable)
● The primary benefit of tuples' immutability is a tuple of immutable objects (like
strings and numbers and other tuples) has a hash value, allowing us to use them as
keys in dictionaries, and members of a set.
● A tuple that contains a mutable structure, like a list, set, or dict, isn't composed of
immutable items, and doesn't have a hash value.
Tuple(‘a’,’b’,’c’)
More on tuples
● When Python displays a tuple, it uses what's called the canonical representation; this
will always include ()'s, making the ()'s
● The degenerate cases include a tuple with only one item, written like this (2.718,). The
extra comma is required here. An empty tuple is ().
● The tuple has to be exactly the same length as the number of variables, or it will raise
an exception
● Tuple unpacking - we extract those values into a single variable.
Eg of tuple unpacking
>>> s = "AAPL", 132.76, 134.80, 130.53
>>> high = s[2]
>>> high
134.8
NamedTuples
● NamedTuples via typing.NamedTuple
● Type of container like dictionaries
● Like dictionaries, they contain keys that are hashed to a particular value.
● it supports both access from key-value and iteration
Eg:
House = namedtuple("House",
["city","country","year","area","num_rooms"])
names of the values are, "city", "country", "year", "area" and "num_rooms"
in a list.
Sets
FOCUS POINTS
Allows to create sets in python using the elements from other iterables like lists, sets, or
tuples
Dataclass
● dataclasses let’s us define ordinary objects with a clean syntax for specifying
attributes. They look – superficially – very similar to named tuples
● The dataclass function is applied as a class decorator, using the @ operator
● You can specify a default value for the attributes of a dataclass.
● When the dataclass decorator receives the order=True argument, it will, by
default, compare the values based on each of the attributes in the order they
were defined.