0% found this document useful (0 votes)
10 views27 pages

Understanding Python OOP Concepts

The document discusses object-oriented programming (OOP) in Python, explaining the concepts of classes and objects, and how they relate to each other. It provides examples of creating classes, such as a Car class, and demonstrates how to use attributes and methods. Additionally, it touches on the nature of objects in Python, including their types and the use of functions as first-class objects.

Uploaded by

horace23vt
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views27 pages

Understanding Python OOP Concepts

The document discusses object-oriented programming (OOP) in Python, explaining the concepts of classes and objects, and how they relate to each other. It provides examples of creating classes, such as a Car class, and demonstrates how to use attributes and methods. Additionally, it touches on the nature of objects in Python, including their types and the use of functions as first-class objects.

Uploaded by

horace23vt
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

2025/2/20 20:04 Objects

Objects
CS1302 Introduction to Computer Programming

In [1]: from manim import *

%reload_ext divewidgets

# Set LLM alias


%load_ext jupyter_ai
%ai update chatgpt dive:chat

Out[1]: Updated target of alias chatgpt

Definitions

{important}

Python is a [*class-based* object-oriented programming (OOP)]


([Link]
oriented_programming#Class-based_vs_prototype-based) language:
- Each object is an instance of a *class/type*, which can be a
*subclass* of one or more *base classes*.
- An object is a collection of *members/attributes*, each of
which is an object.

Why object-oriented programming?

Let's write the Hello-World program with OOP:

In [2]: %%manim -ql --progress_bar=none --disable_caching --flush_cache -v ERROR HelloWo


class HelloWorld(Scene):
def construct(self):
[Link](Write(Text("Hello, World!")))

Manim Community v0.18.1

The above code creates a video by simply defining

a Scene called HelloWorld

[Link] 1/27
2025/2/20 20:04 Objects

construct ed by play ing an animation that


Write s the Text message 'Hello, World!' .

Complicated animations can be created without too many lines of code:

In [3]: %%html
<iframe width="800" height="450" src="[Link]

An error occurred.

Try watching this video on [Link], or enable JavaScript if it is disabled in your browser.

Exercise Define

a Scene called Test


construct ed by play ing an animation that
FadeIn a Square() and then
play ing another animation that
shows a Circle that GrowFromCenter .

{hint}
See the [documentation]([Link] and
[tutorial]
([Link]
started-animating-with-manim-and-python-3-7/).

In [ ]: %%manim -ql --progress_bar=none --disable_caching --flush_cache -v ERROR Test


class Test(Scene):
def construct(self):
# YOUR CODE HERE
raise NotImplementedError()

[Link] 2/27
2025/2/20 20:04 Objects

In [4]: %%manim -ql --progress_bar=none --disable_caching --flush_cache -v ERROR Test


class Test(Scene):
def construct(self):
# SOLUTION
[Link](Write(Circle()))
[Link](FadeIn(Square()))
[Link](GrowFromCenter(Circle()))

Manim Community v0.18.1

{important}

- OOP *encapsulates* implementation details while


- making programming *expressive*.

What is an object?

In [5]: %%ai chatgpt -f text

In one paragraph, explain what is the difference between class and object in pyt

Out[5]: In Python, a class and an object are two distinct concepts. A class is a bluepr
int or a template that defines the properties and behavior of an object, wherea
s an object is an instance of a class, representing a specific entity with its
own set of attributes (data) and methods (functions). In other words, a class i
s a design pattern or a template, while an object is a real-world entity that i
s created based on that template. For example, "Car" can be a class with attrib
utes like color, model, and methods like start_engine, accelerate, whereas "my_
car" can be an object of the "Car" class, with its own specific attributes like
red color, Toyota model, and its own methods like starting its engine, accelera
ting to 60mph. This distinction is crucial in object-oriented programming, as i
t allows for the creation of multiple objects from a single class, each with it
s own unique characteristics.

Class vs Object

Classes and objects are two important aspects of object-oriented


programming.
a class is a template. It is like a blueprint (not real), and you can use class to
create many of the “same” objects with different characteristics.
an object is an instance of a class, it defines the details of a template.

[Link] 3/27
2025/2/20 20:04 Objects

Class vs Object.

Atrribute/member: what an object has.

For example, a car has wheels and color, so wheel and color are the
attribute/member of car
In program, an object has some variables and functions, they are called
member variable and member function
To use the attribute/member of an object, we use member operator .
The syntax to use a variable/function of an object is object.variable_name
or object.function_name() , e.g., [Link], [Link]()

Different objects of a class

have the same set of attributes as that of the class, but


the attribute values can be different.
For example, all cars have wheels and color, but Mercedes, BMW and Audi
have different wheels and colors

In [13]: %%ai chatgpt

Please provide a sample python code to construct a car class and create diffrent

[Link] 4/27
2025/2/20 20:04 Objects

Out[13]:
Car Class in Python
The following Python code constructs a Car class with attributes like color, model,
year, and mileage. It also includes methods to start the engine, accelerate, and
display car details.

class Car:
def __init__(self, color, model, year, mileage):
[Link] = color
[Link] = model
[Link] = year
[Link] = mileage
self.engine_status = "Stopped"
self.current_speed = 0

def start_engine(self):
self.engine_status = "Started"

def accelerate(self, speed):


self.current_speed = speed

def display_details(self):
return f"Color: {[Link]}\nModel: {[Link]}\nYear: {[Link]}\nMileage: {s
[Link]} miles\nEngine Status: {self.engine_status}\nCurrent Speed: {[Link]
t_speed} mph"

# Create different car objects


car1 = Car("Red", "Toyota", 2020, 100)
car2 = Car("Blue", "Honda", 2015, 30500)
car3 = Car("Black", "Ford", 2018, 200)

# Start the engines


car1.start_engine()
car2.start_engine()
car3.start_engine()

# Accelerate the cars


[Link](60)
[Link](70)
[Link](80)

# Display car details


print("### Car 1 Details")
print(car1.display_details())
print()

[Link] 5/27
2025/2/20 20:04 Objects

print("### Car 2 Details")


print(car2.display_details())
print()
print("### Car 3 Details")
print(car3.display_details())

Example Output

Car 1 Details
Color: Red Model: Toyota Year: 2020 Mileage: 100 miles Engine Status: Started
Current Speed: 60 mph

Car 2 Details
Color: Blue Model: Honda Year: 2015 Mileage: 30500 miles Engine Status: Started
Current Speed: 70 mph

Car 3 Details
Color: Black Model: Ford Year: 2018 Mileage: 200 miles Engine Status: Started
Current Speed: 80 mph

Almost everything in Python is an object, or more precisely, an instance of type


object .

To verify this, we can use function isinstance(obj, class)

it checks if the object (first argument) is an instance of class (second


argument).

Parameters :

obj : The object that need to be checked as a part of class or not.


class : class or type, against which object is needed to be checked.

Returns : True, if object belongs to the given class/type, else returns False.

object is a class/type like int , float , str , and bool .

In [14]: isinstance(object, type)

Out[14]: True

In [15]: (
isinstance(1, object)
and isinstance(1.0, object)
and isinstance("1", object)
and isinstance(True, object)
and isinstance(None, object)
and isinstance(__builtin__, object)

[Link] 6/27
2025/2/20 20:04 Objects

and isinstance(object, object)


)

Out[15]: True

A function is also a object.

In [16]: isinstance(print, object) and isinstance(range, object)

Out[16]: True

{note}

Python treats functions as [first-class]


([Link] objects
that can be
- passed as arguments to other functions,
- assigned to variables, and
- returned as values.

A simple illustration is as follows.

In [17]: %%optlite -h 300


def f(f):
return f

f = f(f)

Out[17]: OPTWidget(value=None, height=300, script='def f(f):\n return f\n\n\nf = f(f)


\n')

In [18]: %%ai chatgpt -f text

There exist several f in the following python code. Please explain them one by o
def f(f):
return f
f = f(f)

[Link] 7/27
2025/2/20 20:04 Objects

Out[18]: ### Explanation of the Code

The given Python code is a classic example of a self-referential function, whic


h can be confusing at first glance. Let's break it down step by step:

#### 1. Function Definition: `def f(f):`


```python
def f(f):
return f
```
This line defines a function named `f` that takes one argument, also named `f`.
The function simply returns the value of its argument `f`.

#### 2. Function Call and Assignment: `f = f(f)`


```python
f = f(f)
```
Here, the function `f` is called with itself as the argument, and the result is
assigned back to the name `f`. This is where things get tricky.

When the function `f` is called with itself as the argument, it creates a scope
where the local variable `f` (the function argument) shadows the global functio
n `f`. However, because the function `f` simply returns its argument, it return
s the local `f`, which is the function object itself.

#### 3. The Assignment


After the function call, the returned value (the function object `f`) is assign
ed back to the global name `f`. This effectively reassigns the global name `f`
to point to the function object that was returned.

### What Happens to the Original Function?


The original function definition is still present in memory, but it's no longer
accessible through the name `f` because the name `f` has been reassigned to poi
nt to the function object that was returned.

### Is This Useful?


This code is often used as a puzzle or an example of a self-referential functio
n, but it's not typically used in real-world programming. It can be confusing a
nd may lead to unexpected behavior if not understood correctly.

### Equivalent Example


To illustrate this concept further, consider an equivalent example using a diff
erent approach:
```python
def identity(x):
return x

identity_func = identity
identity = identity_func(identity_func)
```
In this example, we define an `identity` function that returns its argument. We
then assign the function object to a new name `identity_func`. Finally, we reas
sign the name `identity` to the result of calling `identity_func` with itself a
s the argument, similar to the original code.

A non-trivial illustration is decorator to be explained in a subsequent lecture.

Exercise

[Link] 8/27
2025/2/20 20:04 Objects

While an object is a type, is a type an object? Check using isinstance .

In [19]: #solution
print(isinstance(type, object))
print(isinstance(object, type))

#egg and chicken problem

True
True

Can an object has multiple types?

{important}
An object can be an instance of more than one types.

For instance, True is an instance of bool , int , and object :

In [20]: isinstance(True, bool) and isinstance(True, int) and isinstance(True, object)

Out[20]: True

As proposed in PEP 285,

$$ \begin{CD} \text{bool} @>{\text{subclass}}>> \text{int} @>{\text{subclass}}>>


\text{object} \end{CD} $$

bool is a subclass of int , and


int is a subclass of object .

In [21]: issubclass(bool, int) and issubclass(int, object)

Out[21]: True

type(True) returns the immediate type of an object.


The sequences of base classes can be returned by mro (method resolution
order).

In [22]: print('type of True:',type(True))


print('MRO of True:', type(True).mro())

type of True: <class 'bool'>


MRO of True: [<class 'bool'>, <class 'int'>, <class 'object'>]

Exercise

Check whether type is a subclass of object and vice versa. (Is the result
reasonable?)

In [23]: #Solution
print(issubclass(type, object))
print(issubclass(object, type))

[Link] 9/27
2025/2/20 20:04 Objects

True
False

In [24]: %%ai chatgpt -f text

In one paragraph, explain why object is not a subclass of type in python.

Out[24]: In Python, `object` is not a subclass of `type` because `object` is the base cl
ass of all objects, while `type` is a metaclass that creates classes. The relat
ionship between `object` and `type` is more nuanced: `type` is the metaclass th
at created the `object` class, and `object` is an instance of `type`. This mean
s that `type` is the class of `object`, not its superclass. To illustrate this,
`isinstance(object, type)` returns `True`, indicating that `object` is an insta
nce of `type`, but `issubclass(object, type)` returns `False`, indicating that
`object` is not a subclass of `type`. This distinction is fundamental to Pytho
n's object model and metaclass hierarchy.

What is an attribute?

{important}

The structure and behavior of an object is governed by its


attributes.

To check whether an object has a given attribute, we use


function hasattr(object,attribute_name)

check if an object has the given named attribute and return true if present,
else false.

Preliminary of complex number

Complex number

An complex number is represented by z = x + yj . Python converts the real


numbers x and y into complex using the function complex(x,y) . The real
part can be accessed by [Link] and imaginary part can be represented by
[Link] .

In [25]: #create a complex number


x=complex(1,2) #x=1+2j
x=complex('1+2j')
print(x)
print([Link])
print([Link])

(1+2j)
1.0
2.0

conjugate complex number

complex conjugate is when "Each of two complex numbers having their real
parts identical and their imaginary parts of equal magnitude but opposite
sign."

[Link] 10/27
2025/2/20 20:04 Objects

For example, a=1+2j,b=1-2j, then a is the conjugate complex number of b ,


or b is the conjugate complex number of a
In Python, we can get its complex conjugate by [Link](a), or
[Link]()

In [26]: X=complex(1,2)
print(X)
#method 1
print([Link](X))
#method 2
print([Link]())

(1+2j)
(1-2j)
(1-2j)

In [27]: hasattr(complex("1+j"), "imag"), hasattr("1+j", "imag")

Out[27]: (True, False)

To list all attributes of an object:

In [28]: dir(complex("1+j"))

[Link] 11/27
2025/2/20 20:04 Objects

Out[28]: ['__abs__',
'__add__',
'__bool__',
'__class__',
'__complex__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getnewargs__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__mul__',
'__ne__',
'__neg__',
'__new__',
'__pos__',
'__pow__',
'__radd__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmul__',
'__rpow__',
'__rsub__',
'__rtruediv__',
'__setattr__',
'__sizeof__',
'__str__',
'__sub__',
'__subclasshook__',
'__truediv__',
'conjugate',
'imag',
'real']

Different objects of a class have the same set of attributes as that of the class.

In [29]: dir(complex("1+j")) == dir(complex(1)) == dir(complex)

Out[29]: True

A subclass also inherits the attributes of its base classes.

In [30]: dir(bool) == dir(int) # subset relation in general

Out[30]: True

[Link] 12/27
2025/2/20 20:04 Objects

Different objects of the same class can still behave differently because their
attribute values can be different.

In [31]: complex("1+j").imag == complex(1).imag

Out[31]: False

An attribute can also be a function, which is called a method or member function.

In [32]: [Link](complex(1, 2)), type([Link])

Out[32]: ((1-2j), method_descriptor)

A method can be accessed by objects of the class:

In [33]: complex(1, 2).conjugate(), type(complex(1, 2).conjugate)

Out[33]: ((1-2j), builtin_function_or_method)

complex(1,2).conjugate is a callable object:

Its attribute __self__ is assigned to complex(1,2) .


When called, it passes __self__ as the first argument to
[Link] .

In [34]: dir(complex(1,2).conjugate) #complex(1,2).conjugate has an attribute __self__

[Link] 13/27
2025/2/20 20:04 Objects

Out[34]: ['__call__',
'__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__self__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__text_signature__']

In [35]: callable(complex(1, 2).conjugate), complex(1, 2).conjugate.__self__

Out[35]: (True, (1+2j))

Object Aliasing
What is object Aliasing?

In Python, aliasing happens whenever one variable's value is assigned to another


variable, because variables are just names that store references to values.

x=5
y=x
x and y refer to the same object (i.e., 5). We say that, y is alias (another name)
of x.

When are two objects identical?

Two objects are the same if they occupy the same memory.
The keyword is checks whether two objects are the same object.

In [36]: def f(f):


return f

[Link] 14/27
2025/2/20 20:04 Objects

f(f) is f

Out[36]: True

Is is the same as == ?

is is slightly faster because:

is simply checks whether two objects occupy the same memory, but
== calls the method ( __eq__ ) of the operands to checks the equality in
value.

To see this, we can use the function id which returns an id number for an object
based on its memory location.

In [37]: %%optlite -h 400


x = y = complex(1, 0)
z = complex(1, 0)
print(x == y == z == 1.0)
x_id = id(x)
y_id = id(y)
z_id = id(z)
print(x is y) # id(x) == id(y)
print(x is z) # id(x) != id(z)

Out[37]: OPTWidget(value=None, height=400, script='x = y = complex(1, 0)\nz = complex(1,


0)\nprint(x == y == z == 1.0)\…

As the box-pointer diagram shows:

x is y because the assignment z = x binds z to the same memory


location x points to.
y is said to be an alias (another name) of x .
x is not z because they point to objects at different memory locations,
even though the objects have the same type and value.

Can we use is instead of == to compare integers/strings?

In [38]: %%optlite -h 350


print(10**10 is 10**10)
print(10**100 is 10**100)

Out[38]: OPTWidget(value=None, height=350, script='print(10**10 is 10**10)\nprint(10**10


0 is 10**100)\n')

In [39]: %%optlite -h 350


x = y = "abc"
print(x is y)
print(y is "abc")
print(x + y is x + "abc")

Out[39]: OPTWidget(value=None, height=350, script='x = y = "abc"\nprint(x is y)\nprint(y


is "abc")\nprint(x + y is x + …

Indeed, we normally gets a SyntaxWarning when using is with a literal.

[Link] 15/27
2025/2/20 20:04 Objects

In [40]: 10 is 10, "abc" is "abc"

<>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?


<>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
<>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
<>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
/tmp/ipykernel_2424/[Link]: SyntaxWarning: "is" with a literal. Did you
mean "=="?
10 is 10, "abc" is "abc"
/tmp/ipykernel_2424/[Link]: SyntaxWarning: "is" with a literal. Did you
mean "=="?
10 is 10, "abc" is "abc"
Out[40]: (True, True)

{caution}

When using `is` with a literal, the behavior is not entirely


predictable because
- python tries to avoid storing the same value at different
locations by [*interning*]([Link]
programming/[Link]) but
- interning is not always possible/practical, especially when
the same value is obtained in different ways.

Hence, `is` should only be used for [built-in constants]


([Link]
constants) such as `None` because there can only be one instance
of each of them.

File Objects
How to read a text file?

Consider reading a csv (comma separated value) file:

In [41]: !more '[Link]' #! means runing command 'more' in shell


#more means showing the content of the file (no need to reme

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234

To read the file by a Python program:

In [42]: f = open('[Link]') # create a file object for reading


print([Link]()) # return the entire content

[Link] 16/27
2025/2/20 20:04 Objects

[Link]() # close the file

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234

1. open is a function that creates a file object and assigns it to f .


2. Associated with the file object,

read returns the entire content of the file as a string.


close flushes and closes the file.

Why close a file?

If not, depending on the operating system,

other programs may not be able to access the file, and


changes may not be written to the file.

It's very often programmers may forget to close a file, how to solve this problem?

To ensure a file is closed properly, we can use the with statement:

In [43]: with open('[Link]') as f:


print([Link]())

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234

Why we don't need to close a file in with statement?

Because it has a buit-in function __exit__ to close file automatically.

The with statement applies to any context manager that provides the methods

__enter__ for initialization, and


__exit__ for finalization.

In [44]: with open('[Link]') as f:


print(f, hasattr(f, '__enter__'), hasattr(f, '__exit__'), sep='\n')

[Link] 17/27
2025/2/20 20:04 Objects

<_io.TextIOWrapper name='[Link]' mode='r' encoding='UTF-8'>


True
True

f.__enter__ is called after the file object is successfully created and


assigned to f , and
f.__exit__ is called at the end, which closes the file.
[Link] indicates whether the file is closed.

In [45]: f=open('[Link]')
print([Link]) #to check whether a file is closed or not

[Link]()
print([Link]) #after we run [Link]() to close the file, [Link] returns True

False
True

As a file may contain many lines? how to read a file line by line?

We can iterate a file object in a for loop

In [46]: with open('[Link]') as f:


for line in f:
print(line, end='')
#print(line) #what happens without end='': one more empty line is printe

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234

Exercise Print only the first 5 lines of the file [Link] .

In [47]: with open('[Link]') as f: #use with statement to create a file object and
line_no = 1 #create a variable to represent line no
for line in f: #use a for loop to read each line
if line_no <= 5: #if line no is <5, we print it
print(line, end='')
line_no += 1

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082

How to write to a text file?

f = open('[Link]', 'r')

f2 = open('[Link]', 'w')

[Link] 18/27
2025/2/20 20:04 Objects

f3 = open('[Link]', 'a')

The open function supports the following modes:

'r' opens the file for reading


'w' opens the file for writing; original data will be lost.
'a' opens the file to append data to it; original data will not be lost.

Now, let's see how to write a file, but before that

Consider backing up [Link] to a new file:

In [48]: #first, create a string to represent the file name and directory
destination = 'private/new_contact.csv'

The directory has to be created first if it does not exist:

os module provides a portable way of using operating system dependent


functionality, such as access path and file
[Link]() is a function in os module to make a new directory
Syntax: [Link](directory_name, exist_ok)
exist_ok (optional) : If the target directory already exists, an OSError is
raised if its value is False otherwise not. It's False by default.
more information click here

In [49]: import os #import os module


dir_string=[Link](destination)
print(dir_string)
[Link](dir_string, exist_ok=True) #if exist_ok is True, it will not report
#[Link]([Link](destination), exist_ok=False) # if exist_ok is Fals
#[Link]("test", exist_ok=False)
#[Link]("test",exist_ok=False)

private

To write to the destination file:

In [50]: with open('[Link]') as source_file: #create a file object and assign it t


with open(destination, 'w') as destination_file: # create a file object and
content=source_file.read() #call read() function to read content
destination_file.write(content) #call write() function to write the co

In [51]: !more {destination} #show the content in the destination file

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234

[Link] 19/27
2025/2/20 20:04 Objects

The argument 'w' in open() sets the file object to write mode.
The method write writes the input strings to the file.
In this mode, the original data will be lost

Exercise We can also use a mode to append new content to a file.


Complete the following code to append new_data to the file destination .

In [52]: new_data = 'Effie, Douglas,galnec@[Link], (888) 311-9512'


with open(destination, 'a') as f:
[Link]('\n') # '\n' means end of a line cause we need to print t
[Link](new_data) # call write() function to append the new data to t

!more {destination}

name, email, phone


Amelia Hawkins,dugorre@[Link],(414) 524-6465
Alta Perez,bos@[Link],(385) 247-9001
Tai Ming Chan,tmchan@[Link],(634) 234-7294
Annie Zimmerman,okodag@[Link],(259) 862-1082
Eula Crawford,ve@[Link],(635) 827-9819
Clayton Atkins,vape@[Link],(762) 271-7090
Hallie Day,kozzazazi@[Link],(872) 949-5878
Lida Matthews,joobu@[Link],(213) 486-8330
Amelia Pittman,nulif@[Link],(800) 303-3234
Effie, Douglas,galnec@[Link], (888) 311-9512

How to delete a file?

Note that the file object does not provide any method to delete the file.
Instead, we should use the function remove of the os module.

Syntax: [Link](file_directory)

In [53]: if [Link](destination): #[Link]() check if destination exist or


[Link](destination) #if it exists, we call [Link]() function to

A short summary
What you need to know for file objects.

1. how to create a diretory and a file.


we use [Link]() function
2. how to read data from a file.
we use open() function, and it has three modes. Be familiar with these
modes
3. how to write data to a file.
we use write() function.
4. Remember to always close a file after you open it.
to eliminate this problem, we can use with statement cause it will close
the file automatically.
5. how to delete a file.

[Link] 20/27
2025/2/20 20:04 Objects

we use [Link]() function

String Objects
A string is an object, and actually it has many built-in functions

Next, we'll learn some common functions of string

How to search for a substring in a string?

Syntax: [Link](substring)
Returns the lowest index where the string parameter is found as a substring
of the input string; returns -1 if not found

In [54]: string="hello1, hello2"


print([Link]('hello')) #return the index of the first match
print([Link]('apple')) #return -1 if 'apple' is not found

0
-1

How to split and join strings?

Syntax [Link](separator, maxsplit)


The split() method splits a string into a list, based on the specified separator
and maxsplit (the max number of split)
separator specifies the separator to use when splitting the string. By default
any whitespace is a separator
[Link](',') will separate string into substrings by ,
[Link]('-') will separate string into substrings by -
maxsplit : specifies how many splits to do. Default value is -1, which is "all
occurrences"
[Link](delimiter, maxsplit) method splits a string into a list,
starting from the right.
if you don't specify maxsplit, it's the same as split() cause it splits "all
occurrences".

In [55]: # str1='a,b,c,d'
# str2='a-b-c-d'

#example 1, the basic usage of split()


#you can see there's no difference between split() and rsplit()
# print('Example 1:')
# print([Link](','))
# print([Link]('-'))
# print([Link](','))
# print([Link]('-'))

#example 2, specify numbers of split,


#now split() and rsplit() give different results
str1='a,b,c,d'
str2='a-b-c-d'

[Link] 21/27
2025/2/20 20:04 Objects

print('Example 2:')
print([Link](',',1))
print([Link]('-',1))
print([Link](',',1))
print([Link]('-',1))

#the expressions above are equivalent to the belows


print('Example 3:')
print([Link](',',maxsplit=1))
print([Link]('-',maxsplit=1))
print([Link](',',maxsplit=1))
print([Link]('-',maxsplit=1))

Example 2:
['a', 'b,c,d']
['a', 'b-c-d']
['a,b,c', 'd']
['a-b-c', 'd']
Example 3:
['a', 'b,c,d']
['a', 'b-c-d']
['a,b,c', 'd']
['a-b-c', 'd']

The list of substrings can be joined back together using the join methods.

Syntax: [Link](substrings)
Join all items into a single string, separated by delimiter

In [56]: substrings=['ba','na','na']
print('-'.join(substrings))
print('*'.join(substrings))
print(''.join(substrings))

ba-na-na
ba*na*na
banana

How to remove unnecessary characters at the end?

Syntax: [Link](character)
remove any leading/trailing characters, by default it's whitespace
If the chars argument is not provided, all leading and trailing whitespaces are
removed from the string.
[Link](character) , l means left: remove characters on the left side
of a string
[Link](character) , r means right: remove characters on the right
side of a string

In [57]: string=' banana '


print(string)
print([Link]()) #remove all the space
print([Link]()) #remove all the space on the left side
print([Link]()) #remove all the space on the right side
string=',,,banana,,,'
print(string)
print([Link](',')) #remove all the ,

[Link] 22/27
2025/2/20 20:04 Objects

print([Link](',')) #remove all the , on the left side


print([Link](',')) #remove all the , on the right side

banana
banana
banana
banana
,,,banana,,,
banana
banana,,,
,,,banana

How to convert all characters to be upper case or lower case?

The upper() method returns a string where all characters are in upper case.
The lower() method returns a string where all characters are in lower case.

In [58]: string="apple"
print([Link]())

string2="APPle"
print([Link]())

APPLE
apple

Operator Overloading (optional)


Recall that adding str to int raises a type error. The following code
circumvented this by OOP.

In [59]: print(1+10)
print('1'+'10')

11
110

In [60]: %%optlite -l -h 400


class MyStr(str):
def __add__(self, a):
return MyStr(str.__add__(self, str(a)))

def __radd__(self, a):


return MyStr(str.__add__(str(a), self))

print(MyStr(1) + 2, 2 + MyStr(1))

Out[60]: OPTWidget(value=None, height=400, script='class MyStr(str):\n def __add__(se


lf, a):\n return MyStr(s…

How does the above code re-implements + ?

What is overloading?
Recall that the addition operation + behaves differently for different types.

[Link] 23/27
2025/2/20 20:04 Objects

In [61]: %%optlite -h 300


for x, y in (1, 1), ("1", "1"), (1, "1"):
print(f"{x!r:^5} + {y!r:^5} = {x+y!r}")

Out[61]: OPTWidget(value=None, height=300, script='for x, y in (1, 1), ("1", "1"), (1,


"1"):\n print(f"{x!r:^5} + {y…

Having an operator perform differently based on its argument types is called


operator overloading.
+ is called a generic operator.
We can also have function overloading to create generic functions.

Dispatch on type
The strategy of checking the type for the appropriate implementation is called
dispatching on type.

A naive idea is to put all different implementations together:

def add_case_by_case(x, y):


if isinstance(x, int) and isinstance(y, int):
# integer summation
...
elif isinstance(x, str) and isinstance(y, str):
# string concatenation...
...
else:
# Return a TypeError
...

In [62]: %%optlite -h 500


def add_case_by_case(x, y):
if isinstance(x, int) and isinstance(y, int):
print("Do integer summation...")
elif isinstance(x, str) and isinstance(y, str):
print("Do string concatenation...")
else:
print("Return a TypeError...")
return x + y # replaced by internal implementations

for x, y in (1, 1), ("1", "1"), (1, "1"):


print(f"{x!r:^10} + {y!r:^10} = {add_case_by_case(x,y)!r}")

Out[62]: OPTWidget(value=None, height=500, script='def add_case_by_case(x, y):\n if i


sinstance(x, int) and isinstanc…

It can get quite messy with all possible types and combinations.

In [63]: for x, y in ((1, 1.1), (1, complex(1, 2)), ((1, 2), (1, 2))):
print(f"{x!r:^10} + {y!r:^10} = {x+y!r}")

1 + 1.1 = 2.1
1 + (1+2j) = (2+2j)
(1, 2) + (1, 2) = (1, 2, 1, 2)

[Link] 24/27
2025/2/20 20:04 Objects

What about new data types?

In [64]: from fractions import Fraction # non-built-in type for fractions

for x, y in ((Fraction(1, 2), 1), (1, Fraction(1, 2))):


print(f"{x} + {y} = {x+y}")

1/2 + 1 = 3/2
1 + 1/2 = 3/2

{caution}

Weaknesses of the naive approach:


1. New data types require rewriting the addition operation.
1. A programmer may not know all other types and combinations to
rewrite the code properly.

Data-directed programming
The idea is to treat an implementation as a datum that can be returned by the
operand types.

{important}

- `x + y` is a [*syntactic sugar*]
([Link] that
- invokes the method `type(x).__add__(x,y)` of `type(x)` to do
the addition.

In [65]: for x, y in (Fraction(1, 2), 1), (1, Fraction(1, 2)):


print(f"{x} + {y} = {type(x).__add__(x,y)}") # instead of x + y

1/2 + 1 = 3/2
1 + 1/2 = NotImplemented

The first case calls Fraction.__add__ , which provides a way to add int to
Fraction .
The second case calls int.__add__ , which cannot provide any way of adding
Fraction to int . (Why not?)

Why does python return a NotImplemented object instead of raising an


error/exception?

This allows + to continue to handle the addition by


dispatching on Fraction to call its reverse addition method __radd__ .

In [66]: %%optlite -h 500


from fractions import Fraction

def add(x, y):

[Link] 25/27
2025/2/20 20:04 Objects

"""Simulate the + operator."""


sum = x.__add__(y)
if sum is NotImplemented:
sum = y.__radd__(x)
return sum

for x, y in (Fraction(1, 2), 1), (1, Fraction(1, 2)):


print(f"{x} + {y} = {add(x,y)}")

Out[66]: OPTWidget(value=None, height=500, script='from fractions import Fraction\n\n\nd


ef add(x, y):\n """Simulate …

{important}

The object-oriented programming techniques involved are formally


called:
- [*Polymorphism*]
([Link]
Different types can have different implementations of the same
method such as `__add__`.
- [*Single dispatch*]
([Link] The
implementation is chosen based on one single type at a time. `+`
calls `__add__` of the first operand, and if not properly
implemented for the second operand type, `__radd__` of the
second operand.

{note}

- A method with *starting and trailing double underscores* in


its name is called a [*dunder method*]
([Link]
- Dunder methods are not intended to be called directly. E.g.,
we normally use `+` instead of `__add__`.
- [Other operators]
([Link]
highlight=operator) have their corresponding dunder methods that
overloads the operator.

Exercise

Explain how the addition operation for the class MyStr behaves differently as
compared to str .

In [67]: class MyStr(str):


def __add__(self, a):
return MyStr(str.__add__(self, str(a)))

def __radd__(self, a):


return MyStr(str.__add__(str(a), self))

MyStr(1) + 2, 2 + MyStr(1)

[Link] 26/27
2025/2/20 20:04 Objects

Out[67]: ('12', '21')

Solution:

Unlike str which cannot be added to instances of other types such as int ,
MyStr can be added (concatenated) or reverse added to instances of other types.
This is achieved by overloading the + operation with the new implementations
of the forward/reverse addition methods __add__ and __radd__ .

Summary
1. Understand some concepts such as class, object and object-oriented
programming.

2. Know how to create, read/write, close files

3. Know how to operate strings, such as upper() , split() , strip() ,


join()

4. Understand what is object aliasing

5. Understand what is operator overloading (optional)

In [ ]:

[Link] 27/27

You might also like