HomeLập trìnhPythonĐịnh nghĩa lớp...

Định nghĩa lớp động trong Python


Đây là một thủ thuật Python gọn gàng mà bạn có thể thấy hữu ích vào một ngày nào đó. Hãy xem cách bạn có thể định nghĩa động các lớp và tạo các thể hiện của chúng theo yêu cầu.

Thủ thuật này sử dụng các khả năng lập trình hướng đối tượng (OOP) của Python, vì vậy chúng tôi sẽ xem xét các khả năng đó trước.

Lớp và đối tượng

Python là một ngôn ngữ hướng đối tượng, nghĩa là nó cho phép bạn viết mã theo mô hình hướng đối tượng.

Khái niệm chính trong mô hình lập trình này là các lớp. Trong Python, chúng được sử dụng để tạo các đối tượng có thể có các thuộc tính.

Các đối tượng là các thể hiện cụ thể của một lớp. Một lớp về cơ bản là một bản thiết kế về đối tượng là gì và nó sẽ hoạt động như thế nào.

Các lớp được định nghĩa với hai loại thuộc tính:

  • Thuộc tính dữ liệu – các biến có sẵn cho một thể hiện nhất định của lớp đó
  • Phương thức – các chức năng có sẵn cho một thể hiện của lớp đó

Ví dụ OOP cổ điển thường liên quan đến các loại động vật hoặc thực phẩm khác nhau. Ở đây, tôi đã thực hành nhiều hơn với một chủ đề trực quan hóa dữ liệu đơn giản.

Đầu tiên, xác định lớp BarChart.

class BarChart:
	def __init__(self, title, data):
    	self.title = title
    	self.data = data
   	def plot(self):
    	print("\n"+self.title)
        for k in self.data.keys():
        	print("-"*self.data[k]+" "+k)

Các __init__ phương pháp cho phép bạn thiết lập các thuộc tính khi khởi tạo. Đó là, khi bạn tạo một phiên bản mới của BarChartbạn có thể chuyển các đối số cung cấp tiêu đề và dữ liệu của biểu đồ.

Lớp này cũng có một plot() phương pháp. Thao tác này sẽ in một biểu đồ thanh rất cơ bản ra bàn điều khiển khi nó được gọi. Nó có thể làm được nhiều điều thú vị hơn trong một ứng dụng thực tế.

Tiếp theo, khởi tạo một thể hiện của BarChart:

data = {"a":4, "b":7, "c":8}bar = BarChart("A Simple Chart", data)

Bây giờ bạn có thể sử dụng bar đối tượng trong phần còn lại của mã của bạn:

bar.data['d'] = bar.plot()
A Simple Chart
---- a
------- b
-------- c
----- d

Điều này thật tuyệt vì nó cho phép bạn định nghĩa một lớp và tạo các thể hiện một cách linh hoạt. Bạn có thể tạo ra các phiên bản của các biểu đồ thanh khác trong một dòng mã.

new_data = {"x":1, "y":2, "z":3}
bar2 = BarChart("Another Chart", new_data)
bar2.plot()
Another Chart
- x
-- y
--- z

Giả sử bạn muốn xác định một số lớp biểu đồ. Kế thừa cho phép bạn định nghĩa các lớp “kế thừa” các thuộc tính từ các lớp cơ sở.

Đọc thêm  Nâng kỹ năng Python của bạn lên một tầm cao mới với khóa học video 6 giờ miễn phí này

Ví dụ, bạn có thể xác định một cơ sở Chart lớp. Sau đó, bạn có thể định nghĩa các lớp dẫn xuất kế thừa từ cơ sở.

class Chart:
	def __init__(self, title, data):
    	self.title = title
        self.data = data
    def plot(self):
    	pass
class BarChart(Chart):
	def plot(self):
    	print("\n"+self.title)
        for k in self.data.keys():
        	print("-"*self.data[k]+" "+k)
class Scatter(Chart):
	def plot(self):
    	points = zip(data['x'],data['y'])
        y = max(self.data['y'])+1
        x = max(self.data['x'])+1
        print("\n"+self.title)
        for i in range(y,-1,-1):
        	line = str(i)+"|"
            for j in range(x):
            	if (j,i) in points:
                	line += "X"
                else:
                	line += " "
            print(line)

Ở đây, Chart lớp là một lớp cơ sở. Các BarChartScatter các lớp kế thừa __init__() phương pháp từ Chart. Nhưng họ có cái riêng của họ plot() các phương thức ghi đè lên phương thức được xác định trong Chart.

Bây giờ bạn cũng có thể tạo các đối tượng biểu đồ tán xạ.

data = {'x':[1,2,4,5], 'y':[1,2,3,4]}
scatter = Scatter('Scatter Chart', data)
scatter.plot()
Scatter Chart
4|     X
3|	  X 
2|  X
1| X
0|

Cách tiếp cận này cho phép bạn viết mã trừu tượng hơn, giúp ứng dụng của bạn linh hoạt hơn. Có các bản thiết kế để tạo ra vô số biến thể của cùng một đối tượng chung sẽ giúp bạn tránh lặp lại các dòng mã không cần thiết. Nó cũng có thể làm cho mã ứng dụng của bạn dễ hiểu hơn.

Bạn cũng có thể nhập các lớp vào các dự án trong tương lai, nếu bạn muốn sử dụng lại chúng sau này.

phương pháp xuất xưởng

Đôi khi, bạn sẽ không biết lớp cụ thể mà bạn muốn triển khai trước thời gian chạy. Ví dụ: có thể các đối tượng bạn tạo sẽ phụ thuộc vào đầu vào của người dùng hoặc kết quả của một quy trình khác có kết quả thay đổi.

Phương pháp nhà máy cung cấp một giải pháp. Đây là những phương thức lấy một danh sách động các đối số và trả về một đối tượng. Các đối số được cung cấp xác định lớp của đối tượng được trả về.

Một ví dụ đơn giản được minh họa dưới đây. Nhà máy này có thể trả về biểu đồ thanh hoặc đối tượng biểu đồ phân tán, tùy thuộc vào style đối số mà nó nhận được. Một phương thức xuất xưởng thông minh hơn thậm chí có thể đoán được lớp tốt nhất để sử dụng, bằng cách nhìn vào cấu trúc của data tranh luận.

def chart_factory(title, data, style):
	if style == "bar":
    	return BarChart(title, data)
    if style == "scatter":
    	return Scatter(title, data)
    else:
    	raise Exception("Unrecognized chart style.")
        
    
chart = chart_factory("New Chart", data, "bar")
chart.plot()

Các phương thức xuất xưởng rất tuyệt khi bạn biết trước lớp nào bạn muốn trả về và các điều kiện theo đó chúng được trả về.

Đọc thêm  Quét web bằng Python – Cách cạo phim khoa học viễn tưởng từ IMDB

Nhưng nếu bạn thậm chí không biết điều này trước thì sao?

định nghĩa động

Python cho phép bạn định nghĩa các lớp một cách linh hoạt và khởi tạo các đối tượng với chúng theo yêu cầu.

Tại sao bạn có thể muốn làm điều này? Câu trả lời ngắn gọn nhưng trừu tượng hơn.

Phải thừa nhận rằng việc cần viết mã ở mức độ trừu tượng này thường hiếm khi xảy ra. Khi lập trình, bạn nên cân nhắc xem có giải pháp nào dễ dàng hơn không.

Tuy nhiên, có thể đôi khi việc định nghĩa các lớp động thực sự hữu ích. Chúng tôi sẽ đề cập đến một trường hợp sử dụng có thể có bên dưới.

Bạn có thể quen thuộc với Python type() chức năng. Với một đối số, nó chỉ đơn giản trả về “loại” đối tượng của đối số.

type(1) # <type 'int'>
type('hello') # <type 'str'>
type(True) # <type 'bool'>

Nhưng, với ba lập luận, type() trả về một đối tượng kiểu hoàn toàn mới. Điều này tương đương với việc định nghĩa một lớp mới.

NewClass = type('NewClass', (object,), {})
  • Đối số đầu tiên là một chuỗi đặt tên cho lớp mới
  • Tiếp theo là một bộ, chứa bất kỳ lớp cơ sở nào mà lớp mới sẽ kế thừa từ đó
  • Đối số cuối cùng là một từ điển các thuộc tính dành riêng cho lớp này

Khi nào bạn có thể cần sử dụng thứ gì đó trừu tượng như thế này? Hãy xem xét ví dụ sau.

Flask Table là một thư viện Python tạo cú pháp cho các bảng HTML. Nó có thể được cài đặt thông qua trình quản lý gói pip.

Bạn có thể sử dụng Flask Table để định nghĩa các lớp cho mỗi bảng mà bạn muốn tạo. Bạn định nghĩa một lớp kế thừa từ một cơ sở Table lớp. Các thuộc tính của nó là các đối tượng cột, là các thể hiện của Col lớp.

from flask_table import Table, Col
class MonthlyDownloads(Table):
	month = Col('Month')
    downloads = Col('Downloads')
    
data = [{'month':'Jun', 'downloads':700},
		{'month':'Jul', 'downloads':900},
        {'month':'Aug', 'downloads':1600},
        {'month':'Sep', 'downloads':1900},
        {'month':'Oct', 'downloads':2200}]
        
table = MonthlyDownloads(data)print(table.__html__())

Sau đó, bạn tạo một thể hiện của lớp, chuyển dữ liệu bạn muốn hiển thị. Các __html__() phương pháp tạo HTML cần thiết.

Đọc thêm  Dòng mới của Python và cách in Python mà không cần dòng mới

Bây giờ, giả sử bạn đang phát triển một công cụ sử dụng Bảng Flask để tạo các bảng HTML dựa trên tệp cấu hình do người dùng cung cấp. Bạn không biết trước có bao nhiêu cột mà người dùng muốn xác định — có thể là một, có thể là một trăm! Làm cách nào mã của bạn có thể xác định đúng lớp cho công việc?

Định nghĩa lớp động rất hữu ích ở đây. Đối với mỗi lớp bạn muốn xác định, bạn có thể tự động xây dựng attributes từ điển.

Giả sử cấu hình người dùng của bạn là tệp CSV, với cấu trúc sau:

Table1, column1, column2, column3
Table2, column1
Table3, column1, column2

Bạn có thể đọc từng dòng tệp CSV, sử dụng phần tử đầu tiên của mỗi hàng làm tên của từng lớp bảng. Các phần tử còn lại trong hàng đó sẽ được sử dụng để xác định Col các đối tượng cho lớp bảng đó. Chúng được thêm vào một attributes từ điển, được xây dựng lặp đi lặp lại.

for row in csv_file:
	attributes = {}
    for column in row[1:]:
    	attributes[column] = Col(column)
        globals()[row[0]] = type(row[0], (Table,), attributes)

Đoạn mã trên xác định các lớp cho từng bảng trong tệp cấu hình CSV. Mỗi lớp được thêm vào globals từ điển.

Tất nhiên, đây là một ví dụ tương đối tầm thường. FlaskTable có khả năng tạo các bảng phức tạp hơn nhiều. Một trường hợp sử dụng thực tế sẽ sử dụng tốt hơn điều này! Tuy nhiên, hy vọng rằng bạn đã thấy định nghĩa lớp động có thể hữu ích như thế nào trong một số ngữ cảnh.

Bây giờ bạn đã biết…

Nếu bạn chưa quen với Python, thì bạn nên bắt đầu học nhanh với các lớp và đối tượng ngay từ đầu. Hãy thử thực hiện chúng trong dự án học tập tiếp theo của bạn. Hoặc duyệt qua các dự án mã nguồn mở trên Github để xem các nhà phát triển khác sử dụng chúng như thế nào.

Đối với những người có nhiều kinh nghiệm hơn một chút, có thể rất bổ ích khi tìm hiểu cách mọi thứ hoạt động “đằng sau hậu trường”. Duyệt các tài liệu chính thức có thể được chiếu sáng!

Bạn đã bao giờ tìm thấy trường hợp sử dụng cho định nghĩa lớp động trong Python chưa? Nếu vậy, thật tuyệt khi chia sẻ nó trong các câu trả lời bên dưới.



Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status