Python – Hướng đối tượng

Có ba mô hình lập trình được sử dụng rộng rãi: lập trình hướng thủ tục, lập trình hướng function và lập trình hướng đối tượng. Python hỗ trợ cả ba mô hình lập trình.

Hướng đối tượng

Lập trình hướng đối tượng (OOP) là một mô hình lập trình sử dụng các đối tượng và tương tác của chúng để thiết kế các ứng dụng và chương trình máy tính.

Có một số khái niệm lập trình cơ bản trong OOP:
Tính trừu tượng
Tính đa hình
Tính đóng gói
Tính kế thừa

Tính trừu tượng là đơn giản hóa thực tế phức tạp bằng cách mô hình hóa các class phù hợp với vấn đề. Tính đa hình là quá trình sử dụng một toán tử hoặc hàm theo những cách khác nhau để nhập dữ liệu khác nhau. Việc đóng gói ẩn các chi tiết triển khai của một lớp khỏi các đối tượng khác. Kế thừa là một cách tạo class mới bằng cách sử dụng các lớp đã được định nghĩa.

Python Object

Mọi thứ trong Python đều là object. Objects là building block cơ bản trong Python.
Ví dụ 1:

import sys

def function():
    pass

print(type(1))
print(type(""))
print(type([]))
print(type({}))
print(type(()))
print(type(object))
print(type(function))
print(type(sys))

Trong ví dụ này, in ra kiểu dữ liệu của kiểu dữ liệu trong Python. Chúng đều là object

Kết quả:

C:\Users\Dell>python test.py
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'type'>
<class 'function'>
<class 'module'>

Integers, strings, lists, dictionaries, tuples, functions, và modules đều là Python object.

Keyword class

Các object trước đây là object built-in của ngôn ngữ Python. Các user defined object được tạo bởi keyword class.
Class là bản thiết kế định nghĩa bản chất của object. Từ class, chúng ta khởi tạo instance. Mỗi instance là một object cụ thể được tạo từ class cụ thể. Ví dụ: BMW là 1 instance tạo bởi class car.

Ví dụ 2: Định nghĩa class

class First:
    pass

fr = First()

print(type(fr))
print(type(First))

Đây là class first. Body của class bỏ trống. Theo coding convention, nên đặt tên class bắt đầu kí tự in hoa.

class First:
    pass

Chúng ta định nghĩa class First. Chú ý: mặc định tất cả các class đều kế thừa từ object base.

fr = First()

Tạo instance (object) của class Frist(). fr là tham chiếu đến object

Kết quả:
C:\Users\Dell>python test.py

Chúng ta thấy rằng fr là instance object của class First
Bên trong class, chúng ta có thể define các thuộc tính và method. Các thuộc tính là đặc điểm của 1 object. Ví dụ: có thể là lương của nhân viên. Method định nghĩa việc xử lí/thao tác tính toán với các object. Về mặt kĩ thuật, các thuộc tính là các biến và method là các function được định nghĩa bên trong class.

Khởi tạo object

Một method đặc biệt __init__ được sử dụng để khởi tạo object.
Ví dụ 3: Khởi tạo object bằng method __init__

class Being:

    def __init__(self):
        print("Being is initialized")

Being()

Chúng ta define class Being. Method đặc biệt __init__ được gọi tự động ngay sau khi object được tạo

Kết quả:
C:\Users\Dell>python test.py
Being is initialized

Thuộc tính của object

Các thuộc tính là đặc tính của object. Các thuộc tính được set trong method __init__
Ví dụ 4: Khởi tạo các thuộc tính của object

class Cat:

    def __init__(self, name):

        self.name = name

missy = Cat('Missy')
lucky = Cat('Lucky')

print(missy.name)
print(lucky.name)

Chúng ta define class Cat. Method __init__ được gọi ngay sau khi object được tạo.

def __init__(self, name):

Mỗi method trong định nghĩa class bắt đầu với tham chiếu tới instance object. Nó được đặt là self. Nó gần giống con trỏ this trong lập trình OOP C++. Tham số thứ 2 là name được truyền vào để khởi tạo class.

self.name = name

Gán giá tị khởi tạo cho thuộc tính của instance object.

missy = Cat('Missy')
lucky = Cat('Lucky')

Chúng ta định nghĩa 2 object missy và lucky. Số lượng đối số truyền vào phải tương ứng với method __init__ khi định nghĩa class. String “Missy” và “Lucky” trở thành tham số name trong method __init__

print(missy.name)
print(lucky.name)

Chúng ta in thuộc tính name của 2 object.

Kết quả:
C:\Users\Dell>python test.py
Missy
Lucky

Các thuộc tính có thể được gán không chỉ ở lúc khởi tạo. Ví dụ sau minh họa việc gán giá trị cho thuộc tính của object.
Ví dụ 5: Gán thuộc tính class

class Person:
    pass

p = Person()
p.age = 24
p.name = "Peter"

print("{0} is {1} years old".format(p.name, p.age))

Chúng ta định nghĩa class rỗng Person

p.age = 24
p.name = "Peter"

Chúng ta tạo 2 thuộc tính age và name, đồng thời gán giá trị cho các thuộc tính.

Kết quả:
C:\Users\Dell>python test.py
Peter is 24 years old

Thuộc tính của class

Trong ví dụ này, chúng ta bàn về thuộc tính class
Ví dụ 6: Thuộc tính class

class Cat:
    species = 'mammal'

    def __init__(self, name, age):
        self.name = name
        self.age = age


missy = Cat('Missy', 3)
lucky = Cat('Lucky', 5)

print(missy.name, missy.age)
print(lucky.name, lucky.age)

print(Cat.species)
print(missy.__class__.species)
print(lucky.__class__.species)

Trong ví dụ này, chúng ta có 2 object với thuộc tính riêng ‘name’ và ‘age’. Missy và Lucky đều là động vật. Điều này được phản ánh trong thuộc tính chung ‘species’. Thuộc tính của class ‘species’ được định nghĩa bên ngoài tất cả các phương thức của class.

print(Cat.species)
print(missy.__class__.species)

Có 2 cách truy xuất vào thuộc tính class: hoặc thông qua tên class Cat, hoặc sử dụng thuộc tính __class__

Kết quả:
C:\Users\Dell>python test.py
Missy 3
Lucky 5
mammal
mammal
mammal

Phương thức

Phương thức là hàm được định nghĩa bên trong body class. Chúng được sử dụng để thực hiện thao tác với các thuộc tính của object. Các phương thức là quan trọng thể hiện tính đóng gói của OOP.

Ví dụ 7: Phương thức trong class

class Circle:

    pi = 3.141592

    def __init__(self, radius=1):
        self.radius = radius

    def area(self):
        return self.radius * self.radius * Circle.pi

    def setRadius(self, radius):
        self.radius = radius

    def getRadius(self):
        return self.radius


c = Circle()

c.setRadius(5)
print(c.getRadius())
print(c.area())

Trong ví dụ này, chúng ta định class Circle có 3 phương thức.

def area(self):
    return self.radius * self.radius * Circle.pi

Phương thức area() tính diện tích hình tròn.

def setRadius(self, radius):
    self.radius = radius

Phương thức setRadius set giá trị bán kính vào thuộc tính ‘radius’.

def getRadius(self):
    return self.radius

Phương thức getRadius() get giá trị bán kính thuộc tính ‘radius’

c.setRadius(5)

Gọi phương thức setRadius() từ object ‘c’. Object ‘c’ được truyền vào tham số ‘self’ và 5 được truyền vào tham số ‘radius’

Kết quả:
C:\Users\Dell>python test.py
5
78.5398

Trong Python, chúng ta có thể gọi phương thức theo 2 cách. Gọi bound và unbound.

Ví dụ 8: gọi phương thức theo 2 cách bound và unbound

class Methods:

    def __init__(self):
        self.name = 'Methods'

    def getName(self):
        return self.name


m = Methods()

print(m.getName())
print(Methods.getName(m))

Ví dụ này minh họa 2 cách gọi phương thức.

print(m.getName())

Đây là cách gọi bound. Trình thông dịch Python tự động truyền object ‘m’ vào thuộc tính ‘self’

print(Methods.getName(m))

Đây là cách gọi unbound. Object ‘m’ được truyền trực tiếp vào phương thức getName().

Kết quả:

C:\Users\Dell>python test.py
Methods
Methods

Tính kế thừa

Kết thừa là cách tạo class mới sử dụng các class đã được định nghĩa. Các class mới được gọi là class dẫn xuất (hay class con). Các class mà class dẫn xuất kế thừa được gọi là class cơ sở (class cha). Lợi ích của kế thừa là tái sử dụng code và giảm tính phức tạp của chương trình. Class dẫn xuất override hoặc extend chức năng của class cơ sở.

Ví dụ 9: Tính kế thừa trong class Python

class Animal:

    def __init__(self):
        print("Animal created")

    def whoAmI(self):
        print("Animal")

    def eat(self):
        print("Eating")


class Dog(Animal):

    def __init__(self):
        super().__init__()
        
        print("Dog created")

    def whoAmI(self):
        print("Dog")

    def bark(self):
        print("Woof!")

d = Dog()
d.whoAmI()
d.eat()
d.bark()

Trong ví du này, chúng ta có 2 class: ‘Animal’ và ‘Dog’. ‘Animal’ là class cơ sở, ‘Dog’ là class dẫn xuất. Class dẫn xuất kế thừa chức năng của class cơ sở. Đó là phương thức ‘eat()’. Class dẫn xuất thay đổi behavior của class cơ sở, đó là phương thức ‘WhoAmI()’. Cuối cùng, class dẫn xuất extend chức năng của class cơ sở, đó là định nghĩa phương thức mới ‘bark()’

class Dog(Animal):

    def __init__(self):
        super().__init__()
        print("Dog created")

Chúng ta đăt class cơ sở vào class dẫn xuất Dog. Nếu class dẫn xuất định nghĩa phương thức __init__ và chúng ta muốn gọi hàm tạo class cơ sở với hàm ‘super()’.

Kết quả:
C:\Users\Dell>python test.py
Animal created
Dog created
Dog
Eating
Woof!

Tính đa hình

Đa hình là process sử dụng toán tử hoặc function theo cách khác nhau giành cho các data input khác nhau. Trên thực tế, đa hình nghĩa là nếu class B kế thừa từ class A, nó sẽ không kế thừa mọi thứ trong class A; nó có thể implement thêm chức năng khác.

Ví dụ 10: Tính đa hình trong built-in data

a = "alfa"
b = (1, 2, 3, 4)
c = ['o', 'm', 'e', 'g', 'a']

print(a[2])
print(b[1])
print(c[3])

Python sử dụng đa hình một cách rộng rãi trong các kiểu dữ liệu built-in. Ở đây chúng ta sử dụng cùng một toán tử [] cho ba kiểu dữ liệu khác nhau.

Kết quả:
C:\Users\Dell>python test.py
f
2
g

Đa hình hầu hết được sử dụng khi xử lý kế thừa.
Ví dụ 11: Đa hình khi xử lí kế thừa

class Animal:
    
   def __init__(self, name=''):
       
      self.name = name

   def talk(self):
       
      pass

class Cat(Animal):
    
   def talk(self):
       
      print("Meow!")

class Dog(Animal):
    
   def talk(self):
       
      print("Woof!")

a = Animal()
a.talk()

c = Cat("Missy")
c.talk()

d = Dog("Rocky")
d.talk()

Ở đây chúng ta có hai loài: một con chó và một con mèo. Cả hai đều là động vật. Class Dog và class Cat kế thừa lớp ‘Animal’. Chúng đều có phương thức talk(), nhưng output của các phương thức này khác nhau.

Kết quả:
C:\Users\Dell>python test.py
Meow!
Woof!

Phương thức đặc biệt

Class trong Python có thể implement operation nhất định với tên phương thức đặc biêt. Các phương thức này không được gọi trực tiếp mà bằng một cú pháp ngôn ngữ cụ thể. Điều này tương tự như những gì được gọi là nạp chồng toán tử trong C ++ hoặc Ruby.

Ví dụ 12: Tên phương thức đặc biệt

class Book:

    def __init__(self, title, author, pages):

        print("A book is created")

        self.title = title
        self.author = author
        self.pages = pages

    def __str__(self):

        return "Title:{0} , author:{1}, pages:{2} ".format(
            self.title, self.author, self.pages)

    def __len__(self):

        return self.pages

    def __del__(self):

        print("A book is destroyed")

book = Book("Inside Steve's Brain", "Leander Kahney", 304)

print(book)
print(len(book))
del book

Trong ví dụ, chúng ta có class ‘Book’, và 4 phương thức đặc biệt: __init__, __str__, __len__ and __del__.

book = Book("Inside Steve's Brain", "Leander Kahney", 304)

Tạo object và phương thức __init__() được gọi để khởi tạo object

print(book)

Keyword print gọi phương thức __str__. Phương thức này trả về string mô tả object.

print(len(book))

Phương thức len() gọi phương thức __len__. Trong ví dụ này, chúng ta in ra số lượng trang của sách

del book

Keyword del xóa object ‘book’. Phương thức __del__ được gọi

Kết quả:
C:\Users\Dell>python test.py
A book is created
Title:Inside Steve’s Brain , author:Leander Kahney, pages:304
304
A book is destroyed

Ví dụ 13: Vector class

class Vector:

    def __init__(self, data):

        self.data = data

    def __str__(self):

        return repr(self.data)

    def __add__(self, other):

        data = []

        for j in range(len(self.data)):

            data.append(self.data[j] + other.data[j])

        return Vector(data)

    def __sub__(self, other):

        data = []

        for j in range(len(self.data)):

            data.append(self.data[j] - other.data[j])

        return Vector(data)


x = Vector([1, 2, 3])
y = Vector([3, 0, 2])

print(x + y)
print(y - x)

Ví dụ này mô tả 2 phương thức __add__ và __sub__

def __add__(self, other):

    data = []

    for j in range(len(self.data)):

        data.append(self.data[j] + other.data[j])

    return Vector(data)

Đoạn code này implement phương thức cộng 2 vector. Phương thức __add__ được gọi khi gọi toán tử + 2 vector.

Kết quả:
C:\Users\Dell>python test.py
[4, 2, 5] [2, -2, -1]

Be the first to comment

Leave a Reply