Làm cách nào để bạn giải quyết quá tải phương thức trong python?

Từ quá tải có nghĩa là nạp quá nhiều vào hoặc lên một thứ gì đó, chẳng hạn như quá tải điện làm chập mạch. Theo cách tương tự, Quá tải đề cập đến khả năng một đối tượng có thể có nhiều hành vi. Quá tải là một trong những tính năng vượt trội của OOPS

Tại sao chúng ta nên sử dụng Overloading?

Quá tải hàm là khả năng có nhiều hàm có cùng tên nhưng có chữ ký/cách triển khai khác nhau. Khi một hàm bị quá tải

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1 được gọi, bộ thực thi trước tiên sẽ đánh giá các đối số/tham số được truyền cho lệnh gọi hàm và đánh giá bằng cách này sẽ gọi triển khai tương ứng

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}

Trong ví dụ trên [được viết bằng C++], hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 bị quá tải với hai lần triển khai; . Khi chúng ta gọi hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 như
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
4, nó gọi hàm thứ hai trong khi
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
5 gọi hàm đầu tiên

Tại sao không có chức năng quá tải trong Python?

Python không hỗ trợ nạp chồng hàm. Khi chúng ta định nghĩa nhiều hàm có cùng tên, hàm sau luôn ghi đè lên hàm trước và do đó, trong không gian tên, sẽ luôn có một mục duy nhất đối với mỗi tên hàm. Chúng tôi thấy những gì tồn tại trong các không gian tên Python bằng cách gọi các hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
6 và
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
7, trả về không gian tên cục bộ và toàn cầu tương ứng

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}

Gọi hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
6 sau khi xác định hàm, chúng ta thấy rằng nó trả về một từ điển gồm tất cả các biến được xác định trong không gian tên cục bộ. Chìa khóa của từ điển là tên của biến và giá trị là tham chiếu/giá trị của biến đó. Khi bộ thực thi gặp một hàm khác có cùng tên, nó sẽ cập nhật mục nhập trong không gian tên cục bộ và do đó loại bỏ khả năng hai hàm cùng tồn tại. Do đó python không hỗ trợ Nạp chồng hàm. Đó là quyết định thiết kế được đưa ra trong khi tạo ngôn ngữ nhưng điều này không ngăn chúng tôi thực hiện nó, vì vậy hãy quá tải một số chức năng

Triển khai nạp chồng hàm trong Python

Chúng tôi biết cách Python quản lý các không gian tên và nếu chúng tôi muốn thực hiện quá tải chức năng, chúng tôi sẽ cần phải

  • quản lý các định nghĩa hàm trong một không gian tên ảo được duy trì
  • tìm cách gọi hàm thích hợp theo các đối số được truyền cho nó

Để đơn giản, chúng ta sẽ thực hiện nạp chồng hàm trong đó các hàm có cùng tên được phân biệt bằng số đối số mà nó chấp nhận

Bao hàm chức năng

Chúng tôi tạo một lớp có tên là

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 bao hàm bất kỳ chức năng nào và làm cho nó có thể gọi được thông qua một phương thức
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 bị ghi đè và cũng hiển thị một phương thức có tên là
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
11 trả về một bộ làm cho chức năng này trở thành duy nhất trong toàn bộ cơ sở mã

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
1

Trong đoạn mã trên, hàm

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
11 trả về một bộ xác định duy nhất hàm trong cơ sở mã và giữ

  • mô-đun chức năng
  • lớp mà hàm thuộc về
  • tên của chức năng
  • số đối số mà hàm chấp nhận

Phương thức

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 bị ghi đè gọi hàm được bao bọc và trả về giá trị được tính toán [hiện tại không có gì lạ mắt ở đây]. Điều này làm cho thể hiện có thể gọi được giống như chức năng và nó hoạt động chính xác như chức năng được bao bọc

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
6

Trong ví dụ trên, hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 được bọc trong
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 được khởi tạo trong
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
16.
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
17 trả về bộ dữ liệu có phần tử đầu tiên là tên mô-đun
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
18, phần tử thứ hai là lớp
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
19, phần tử thứ ba là tên hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 trong khi phần tử thứ tư là số đối số mà hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 chấp nhận là
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
62

Ví dụ này cũng cho thấy cách chúng ta có thể gọi thể hiện

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
16, giống như hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 thông thường, với các đối số
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
65 và
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
66 và nhận được phản hồi
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
67, chính xác là những gì chúng ta sẽ nhận được mà chúng ta sẽ gọi là
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
5. Hành vi này sẽ có ích trong giai đoạn sau khi chúng ta chơi với các nhà trang trí

Xây dựng Namespace ảo

Không gian tên ảo, chúng tôi xây dựng ở đây, sẽ lưu trữ tất cả các chức năng chúng tôi thu thập được trong giai đoạn định nghĩa. Vì chỉ có một không gian tên/cơ quan đăng ký nên chúng tôi tạo một lớp đơn chứa các hàm trong từ điển có khóa không chỉ là tên hàm mà là bộ chúng tôi nhận được từ hàm

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
11, chứa các phần tử xác định duy nhất hàm trong toàn bộ cơ sở mã. Thông qua đó, chúng tôi sẽ có thể giữ các chức năng trong sổ đăng ký ngay cả khi chúng có cùng tên [nhưng các đối số khác nhau] và do đó tạo điều kiện cho quá tải chức năng

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
3

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
30 có một phương thức
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
31 lấy hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1 làm đối số, tạo một khóa duy nhất cho nó, lưu trữ nó trong từ điển và trả về
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1 được bao bọc trong một thể hiện của
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9. Điều này có nghĩa là giá trị trả về từ hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
31 cũng có thể gọi được và [cho đến bây giờ] hành vi của nó hoàn toàn giống với hàm bọc
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1

Sử dụng đồ trang trí như một cái móc

Bây giờ chúng ta đã xác định một không gian tên ảo với khả năng đăng ký một hàm, chúng ta cần một hook được gọi trong khi định nghĩa hàm; . Trong Python, một trình trang trí bao bọc một chức năng và cho phép chúng tôi thêm chức năng mới vào chức năng hiện có mà không sửa đổi cấu trúc của nó. Một trình trang trí chấp nhận hàm bao bọc

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1 làm đối số và trả về một hàm khác được gọi thay thế. Hàm này chấp nhận
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
38 và
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
39 được truyền trong khi gọi hàm và trả về giá trị

Một trình trang trí mẫu có thời gian thực thi một chức năng được trình bày bên dưới

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
5

Trong ví dụ trên, chúng tôi xác định một trình trang trí có tên là

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
10 bao bọc hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 và in trên
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
12 thời gian thực hiện

Hàm trang trí

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
10 được gọi mỗi lần [để nó bao bọc hàm được trang trí và lưu trữ hàm bao bọc mới này trong không gian tên cục bộ hoặc toàn cầu của Python], trình thông dịch gặp một định nghĩa hàm và đối với chúng tôi, đó là một cái móc lý tưởng để đăng ký hàm . Do đó, chúng tôi tạo trình trang trí có tên là
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
14 để đăng ký hàm trong không gian tên ảo và trả về một hàm có thể gọi được để gọi

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
1

Trình trang trí

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
14 trả về một thể hiện của
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9, như được trả về bởi
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
17 chức năng của không gian tên. Bây giờ, bất cứ khi nào hàm [được trang trí bởi
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
14] được gọi, nó sẽ gọi hàm được trả về bởi hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
17 - một thể hiện của
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 và phương thức
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 được thực thi với
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
38 và
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
39 đã chỉ định được truyền trong khi gọi. Bây giờ những gì còn lại là triển khai phương thức
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 trong lớp
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 sao cho nó gọi hàm thích hợp với các đối số được truyền trong khi gọi

Tìm đúng chức năng từ không gian tên

Phạm vi định hướng, ngoài tên và lớp mô-đun thông thường, là số lượng đối số mà hàm chấp nhận và do đó chúng tôi định nghĩa một phương thức có tên là

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
56 trong không gian tên ảo của chúng tôi, phương thức này chấp nhận hàm từ không gian tên của python [sẽ là định nghĩa cuối cùng cho

Vai trò của hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
56 này là quyết định việc triển khai hàm nào [nếu bị quá tải] sẽ được gọi. Quá trình lấy hàm thích hợp khá đơn giản - từ hàm và các đối số tạo khóa duy nhất bằng cách sử dụng hàm
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
11 [như đã thực hiện khi đăng ký] và xem liệu nó có tồn tại trong sổ đăng ký hàm hay không;

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
6

Hàm

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
56 tạo một thể hiện của
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 chỉ để nó có thể sử dụng hàm
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
11 để lấy một khóa duy nhất và không sao chép logic. Sau đó, khóa được sử dụng để tìm nạp chức năng thích hợp từ sổ đăng ký chức năng

Gọi hàm

Như đã nêu ở trên, phương thức

int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 trong lớp
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
9 được gọi mỗi khi một hàm được trang trí bằng một trình trang trí
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
14 được gọi. Chúng tôi sử dụng chức năng này để tìm nạp chức năng thích hợp bằng cách sử dụng chức năng
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
56 của không gian tên và gọi triển khai bắt buộc của chức năng quá tải. Phương pháp
int area[int length, int breadth] {
  return length * breadth;
}

float area[int radius] {
  return 3.14 * radius * radius;
}
10 được thực hiện như sau

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
5

Phương thức tìm nạp hàm thích hợp từ không gian tên ảo và nếu nó không tìm thấy bất kỳ hàm nào, nó sẽ đưa ra một

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
17 và nếu có, nó sẽ gọi hàm đó và trả về giá trị

Quá tải chức năng trong hành động

Khi tất cả mã được đặt vào vị trí, chúng tôi xác định hai chức năng có tên là

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2. một tính diện tích hình chữ nhật và một tính diện tích hình tròn. Cả hai chức năng được xác định bên dưới và được trang trí bằng một trình trang trí
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
14

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
0

Khi chúng ta gọi

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2 với một đối số, nó trả về diện tích hình tròn và khi chúng ta truyền hai đối số, nó gọi hàm tính diện tích hình chữ nhật, do đó làm quá tải hàm
def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
2. Bạn có thể tìm thấy toàn bộ bản demo đang hoạt động tại đây

Phần kết luận

Python không hỗ trợ nạp chồng hàm nhưng bằng cách sử dụng các cấu trúc ngôn ngữ phổ biến, chúng tôi đã hack một giải pháp cho nó. Chúng tôi đã sử dụng các trình trang trí và một không gian tên do người dùng duy trì để quá tải các hàm và sử dụng số lượng đối số làm yếu tố định hướng. Chúng ta cũng có thể sử dụng các kiểu dữ liệu [được xác định trong trình trang trí] của các đối số để định hướng - cho phép các hàm có cùng số lượng đối số nhưng khác kiểu quá tải. Độ chi tiết của tình trạng quá tải chỉ bị giới hạn bởi chức năng

def area[radius]:
  return 3.14 * radius ** 2

>>> locals[]
{
  ...
  'area': ,
  ...
}
62 và trí tưởng tượng của chúng tôi. Một cách tiếp cận gọn gàng hơn, sạch sẽ hơn và hiệu quả hơn cũng có thể thực hiện được với các cấu trúc trên, vì vậy hãy thoải mái triển khai một cách tiếp cận và tweet cho tôi @arpit_bhayani, tôi sẽ rất vui khi biết bạn đã làm gì với nó

Bài viết này ban đầu được xuất bản trên blog của tôi - Hàm quá tải trong Python

Nếu bạn thích những gì bạn đọc, hãy đăng ký nhận bản tin của tôi và nhận bài đăng được gửi trực tiếp vào hộp thư đến của bạn và gửi lời cảm ơn tới tôi @arpit_bhayani

con trăn

Bài báo cáo

Thưởng thức bài viết này?

10

Chia sẻ

Arpit Bhayani

Phần phụ trợ @Unacademy • Dữ liệu @Amazon • Nền tảng @Practo. Viết về Ngôn ngữ bên trong và Toán học trong Khoa học Máy tính

Tôi là một lập trình viên đam mê, đam mê viết mã, thiết kế, khởi nghiệp và công nghệ. Hiện tại tôi đang làm việc tại Amazon với vị trí Kỹ sư phát triển phần mềm 2. Trước Amazon, tôi đang làm việc cho một công ty khởi nghiệp về chăm sóc sức khỏe tên là Practo, nơi tôi độc thân

Theo

Khám phá và đọc thêm các bài viết từ Arpit Bhayani

bắt đầu

Thưởng thức bài viết này?

Để lại một lượt thích và bình luận cho Arpit

10

Hãy là người đầu tiên chia sẻ ý kiến ​​của bạn

Hỗ trợ đánh dấu hương vị GitHub

Gửi đi

yotamolik

một năm trước

có thể nó giống một câu hỏi triết học hơn - nhưng tại sao Python không bị quá tải ngay từ đầu?

Hồi đáp

Daniel Riggs

một năm trước

Kể từ trăn 3. 8, một trình trang trí quá tải có sẵn trong thư viện tiêu chuẩn.

Ngoài ra còn có funcools. singledispatch có thể làm điều tương tự. https. // tài liệu. con trăn. org/3/library/funcools. html

Tôi không chắc liệu chúng có bao gồm mọi thứ bạn viết ở đây hay không, nhưng sẽ rất tuyệt nếu nói về lý do tại sao các tùy chọn thư viện tiêu chuẩn này không đủ [nếu không]

Làm thế nào chúng ta có thể nạp chồng phương thức trong Python?

Quá tải phương thức trong Python .
Ví dụ. lớp nhân viên. def Hello_Emp[self,e_name=None]. nếu e_name không phải là Không có. print["Xin chào "+e_name] other. print["Xin chao "] emp1=Employee[] emp1. Hello_Emp[] emp1. Hello_Emp["Besant"].
đầu ra. Xin chào Xin chào Besant. .
Ví dụ. .
đầu ra. .
Blog liên quan

Vấn đề với quá tải phương thức trong Python là gì?

Vấn đề nạp chồng phương thức trong Python là chúng ta có thể nạp chồng phương thức nhưng chỉ có thể sử dụng phương thức được xác định mới nhất .

Làm thế nào để khắc phục tình trạng quá tải?

Nếu một lớp có nhiều phương thức có cùng tên nhưng các tham số của phương thức phải khác nhau được gọi là Nạp chồng phương thức. .
Số tham số trong hai phương thức
Các kiểu dữ liệu của các tham số của các phương thức
Thứ tự các tham số của các phương thức

Chủ Đề