Phương pháp ràng buộc python

Các phương thức Bound là các phương thức được định nghĩa trong một lớp. Các phương thức liên kết được liên kết với lớp mà chúng được định nghĩa. Họ lấy một thể hiện của lớp cùng với các đối số khác làm tham số của nó. Các phương thức liên kết khác với các phương thức không liên kết khác trong tham số đầu tiên của chúng. Tham số đầu tiên của các phương thức liên kết phải là thể hiện, trong khi đó, đối với các phương thức không liên kết, các tham số là tùy chọn. Nếu các tham số tồn tại, tham số đầu tiên có thể thuộc bất kỳ loại nào

class Class:
    def boundMethod[self,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", self,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]

Mặc dù hầu hết sử dụng

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
6 làm tên cho tham số đầu tiên, nhưng nó có thể được đặt tên theo bất kỳ tên nào

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]

Cả hai đoạn mã trên đều cho cùng một đầu ra

I'm a method bound to Class. Here is my Class's Reference:  Parameter: 10
class Class:
    def boundMethod[]:
        print["I'm a method bound to Class"]
instance = Class[]
instance.boundMethod[] # same as Class.boundMethod[instance]

Nếu đối số đầu tiên bị bỏ qua, Python sẽ tăng

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
7

Traceback [most recent call last]:
File "boundmethods.py", line 20, in 
instance.boundMethod[] # same as Class.boundMethod1[instance,10]
TypeError: boundMethod[] takes 0 positional arguments but 1 was given

Để sửa lỗi, các tham số và đối số phải được truyền chính xác. Nó cũng có thể được sửa bằng trình trang trí

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
8. Nếu sử dụng trình trang trí
>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
8, nó sẽ trở thành một phương thức tĩnh, trong đó thay vì một phương thức cho một thể hiện của một lớp, một phương thức cho toàn bộ lớp sẽ được tạo

Thực hiện đánh giá mã là một cách tuyệt vời để khám phá những điều mà mọi người có thể khó hiểu. Trong khi đọc bản sửa lỗi OpenStack gần đây, tôi phát hiện ra rằng mọi người không sử dụng đúng cách các trình trang trí khác nhau mà Python cung cấp cho các phương thức. Vì vậy, đây là nỗ lực của tôi trong việc cung cấp cho tôi một liên kết để gửi chúng đến trong các bài đánh giá mã tiếp theo của tôi. . -]

Cách các phương thức hoạt động trong Python

Một phương thức là một hàm được lưu trữ như một thuộc tính của lớp. Bạn có thể khai báo và truy cập một chức năng như vậy theo cách này

>>> class Pizza[object]:
..     def __init__[self, size]:
..         self.size = size
..     def get_size[self]:
..         return self.size
...
>>> Pizza.get_size

Điều Python nói với bạn ở đây là thuộc tính get_size của lớp Pizza là một phương thức không liên kết. Điều đó có nghĩa là gì?

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]

Chúng tôi không thể gọi nó vì nó không bị ràng buộc với bất kỳ phiên bản Pizza nào. Và một phương thức muốn một thể hiện làm đối số đầu tiên của nó [trong Python 2, nó phải là một thể hiện của lớp đó; trong Python 3, nó có thể là bất kỳ thứ gì]. Hãy cố gắng làm điều đó sau đó

>>> Pizza.get_size[Pizza[42]]
42

Nó đã làm việc. Chúng tôi đã gọi phương thức với một thể hiện là đối số đầu tiên của nó, vì vậy mọi thứ đều ổn. Nhưng bạn sẽ đồng ý với tôi nếu tôi nói rằng đây không phải là một cách thuận tiện để gọi các phương thức; . Và nếu chúng ta không biết lớp nào là đối tượng của mình, điều này sẽ không hoạt động lâu dài

Vì vậy, những gì Python làm cho chúng ta là nó liên kết tất cả các phương thức từ lớp

>>> Pizza.get_size[Pizza[42]]
42
0 với bất kỳ thể hiện nào của lớp này. Điều này có nghĩa là thuộc tính
>>> Pizza.get_size[Pizza[42]]
42
1 của một thể hiện của
>>> Pizza.get_size[Pizza[42]]
42
0 là một phương thức ràng buộc. một phương thức mà đối số đầu tiên sẽ là chính thể hiện

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
1

Như mong đợi, chúng tôi không phải cung cấp bất kỳ đối số nào cho

>>> Pizza.get_size[Pizza[42]]
42
1, vì nó bị ràng buộc, đối số
>>> Pizza.get_size[Pizza[42]]
42
4 của nó sẽ tự động được đặt thành phiên bản
>>> Pizza.get_size[Pizza[42]]
42
0 của chúng tôi. Đây là một bằng chứng tốt hơn về điều đó

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
5

Thật vậy, bạn thậm chí không cần phải giữ một tham chiếu đến đối tượng

>>> Pizza.get_size[Pizza[42]]
42
0 của mình. Phương thức của nó được liên kết với đối tượng, vì vậy phương thức là đủ cho chính nó

Nhưng nếu bạn muốn biết phương thức ràng buộc này được liên kết với đối tượng nào thì sao?

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
7

Rõ ràng, chúng ta vẫn có một tham chiếu đến đối tượng của mình và chúng ta có thể tìm lại nó nếu muốn

Trong Python 3, các hàm được gắn với một lớp không được coi là phương thức không liên kết nữa mà là các hàm đơn giản, được liên kết với một đối tượng nếu được yêu cầu. Vì vậy, nguyên tắc vẫn giữ nguyên, mô hình chỉ được đơn giản hóa

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
8Phương pháp tĩnh

Các phương thức tĩnh là một trường hợp đặc biệt của các phương thức. Đôi khi, bạn sẽ viết mã thuộc về một lớp, nhưng điều đó hoàn toàn không sử dụng đối tượng đó. Ví dụ

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
9

Trong trường hợp như vậy, viết

>>> Pizza.get_size[Pizza[42]]
42
7 như một phương thức không tĩnh cũng sẽ hoạt động, nhưng nó sẽ cung cấp cho nó một đối số
>>> Pizza.get_size[Pizza[42]]
42
4 sẽ không được sử dụng. Đây, người trang trí
>>> Pizza.get_size[Pizza[42]]
42
9 mua cho chúng tôi vài thứ

  • Python không phải khởi tạo phương thức ràng buộc cho từng đối tượng
    >>> Pizza.get_size[Pizza[42]]
    42
    
    0 mà chúng tôi khởi tạo. Các phương thức ràng buộc cũng là các đối tượng và việc tạo chúng có chi phí. Có một phương pháp tĩnh tránh điều đó
I'm a method bound to Class. Here is my Class's Reference:  Parameter: 10
4
  • Nó làm giảm khả năng đọc của mã. nhìn thấy

    >>> Pizza.get_size[Pizza[42]]
    42
    
    9, chúng ta biết rằng phương thức không phụ thuộc vào trạng thái của chính đối tượng;

  • Nó cho phép chúng ta ghi đè phương thức

    >>> Pizza.get_size[Pizza[42]]
    42
    
    7 trong một lớp con. Nếu chúng ta sử dụng một hàm
    >>> Pizza.get_size[Pizza[42]]
    42
    
    7 được xác định ở cấp cao nhất của mô-đun, thì một lớp kế thừa từ
    >>> Pizza.get_size[Pizza[42]]
    42
    
    0 sẽ không thể thay đổi cách chúng ta trộn nguyên liệu cho bánh pizza mà không ghi đè chính
    class Class:
        def boundMethod[instance,param1]:
            print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
    instance = Class[]
    instance.boundMethod[10] # same as Class.boundMethod[instance,10]
    
    15

phương pháp lớp

Như đã nói, phương thức của lớp là gì? .
not bound to an object, but to… a class!

class Class:
    def boundMethod[]:
        print["I'm a method bound to Class"]
instance = Class[]
instance.boundMethod[] # same as Class.boundMethod[instance]
0

Dù bạn sử dụng cách nào để truy cập phương thức này, thì nó sẽ luôn được liên kết với lớp mà nó được gắn vào và đối số đầu tiên của nó sẽ là chính lớp đó [hãy nhớ rằng các lớp cũng là đối tượng]

Khi nào sử dụng loại phương pháp này?

  • Các phương thức xuất xưởng, được sử dụng để tạo một thể hiện cho một lớp bằng cách sử dụng một số loại tiền xử lý chẳng hạn. Thay vào đó, nếu chúng tôi sử dụng
    >>> Pizza.get_size[Pizza[42]]
    42
    
    9, chúng tôi sẽ phải mã hóa cứng tên lớp
    >>> Pizza.get_size[Pizza[42]]
    42
    
    0 trong hàm của mình, khiến bất kỳ lớp nào kế thừa từ
    >>> Pizza.get_size[Pizza[42]]
    42
    
    0 không thể sử dụng nhà máy của chúng tôi cho mục đích sử dụng riêng
>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
0
  • Các phương thức tĩnh gọi các phương thức tĩnh. nếu bạn chia một phương thức tĩnh thành nhiều phương thức tĩnh, bạn không nên mã hóa tên lớp mà hãy sử dụng các phương thức lớp. Sử dụng cách này để khai báo phương thức của chúng ta, tên
    >>> Pizza.get_size[Pizza[42]]
    42
    
    0 không bao giờ được tham chiếu trực tiếp và việc kế thừa và ghi đè phương thức sẽ hoạt động hoàn hảo
>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
1Phương pháp trừu tượng

Phương thức trừu tượng là phương thức được định nghĩa trong lớp cơ sở nhưng có thể không cung cấp bất kỳ triển khai nào. Trong Java, nó sẽ mô tả các phương thức của một giao diện

Vì vậy, cách đơn giản nhất để viết một phương thức trừu tượng trong Python là

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
2

Bất kỳ lớp nào kế thừa từ

>>> Pizza.get_size[Pizza[42]]
42
0 nên triển khai và ghi đè phương thức
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
51, nếu không sẽ xảy ra ngoại lệ

Cách cụ thể này để thực hiện phương pháp trừu tượng có một nhược điểm. Nếu bạn viết một lớp kế thừa từ

>>> Pizza.get_size[Pizza[42]]
42
0 và quên triển khai
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
51, lỗi sẽ chỉ xuất hiện khi bạn thử sử dụng phương thức đó

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
3

Có một cách để kích hoạt theo cách này sớm hơn, khi đối tượng đang được khởi tạo, sử dụng mô-đun abc được cung cấp cùng với Python

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
4

Sử dụng

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
54 và lớp đặc biệt của nó, ngay khi bạn cố gắng khởi tạo
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
55 hoặc bất kỳ lớp nào kế thừa từ nó, bạn sẽ nhận được một
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
56

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
5Kết hợp các phương thức tĩnh, lớp và trừu tượng

Khi xây dựng các lớp và thừa kế, sẽ đến lúc bạn phải kết hợp tất cả các phương thức trang trí này. Vì vậy, đây là một số lời khuyên về nó

Hãy nhớ rằng việc khai báo một phương thức là trừu tượng, không đóng băng nguyên mẫu của phương thức đó. Điều đó có nghĩa là nó phải được triển khai, nhưng nó có thể được triển khai với bất kỳ danh sách đối số nào

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
6

Điều này hợp lệ, vì

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
57 đáp ứng yêu cầu giao diện mà chúng tôi đã xác định cho các đối tượng
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
55. Điều đó có nghĩa là chúng ta cũng có thể triển khai nó như một lớp hoặc một phương thức tĩnh chẳng hạn

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
7

Điều này cũng đúng và đáp ứng hợp đồng mà chúng tôi có với lớp trừu tượng

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
55 của chúng tôi. Thực tế là phương thức
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
70 không cần biết về đối tượng để trả về kết quả là một chi tiết triển khai, không phải là tiêu chí để hoàn thành hợp đồng của chúng tôi

Do đó, bạn không thể buộc việc triển khai phương thức trừu tượng của mình thành phương thức thông thường, lớp hoặc tĩnh và có thể nói là bạn không nên. Bắt đầu với Python 3 [điều này sẽ không hoạt động như bạn mong đợi trong Python 2, xem vấn đề5867], giờ đây bạn có thể sử dụng các trình trang trí

>>> Pizza.get_size[Pizza[42]]
42
9 và
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
72 trên đầu trang của
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
73

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
8

Đừng hiểu lầm điều này. nếu bạn nghĩ rằng điều này sẽ buộc các lớp con của bạn triển khai

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
70 như một phương thức của lớp thì bạn đã nhầm. Điều này chỉ ngụ ý rằng việc bạn triển khai
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
70 trong lớp
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
55 là một phương thức lớp

Một triển khai trong một phương pháp trừu tượng? . Trong Python, trái ngược với các phương thức trong giao diện Java, bạn có thể có mã trong các phương thức trừu tượng của mình và gọi nó qua

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
77

>>> Pizza.get_size[]
Traceback [most recent call last]:
  File "", line 1, in 
TypeError: unbound method get_size[] must be called with Pizza instance as first argument [got nothing instead]
9

Trong trường hợp như vậy, mọi chiếc bánh pizza bạn sẽ tạo bằng cách kế thừa từ

class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
55 sẽ phải ghi đè phương thức
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
70, nhưng sẽ có thể sử dụng cơ chế mặc định để lấy danh sách thành phần bằng cách sử dụng
class Class:
    def boundMethod[instance,param1]:
        print["I'm a method bound to Class. Here is my Class's Reference:", instance,'Parameter:',param1]
instance = Class[]
instance.boundMethod[10] # same as Class.boundMethod[instance,10]
77

Nếu bạn muốn biết thêm, tôi đã đề cập nhiều đến chủ đề này trong Hướng dẫn về Python của Hacker. Kiểm tra nó ra

Chủ Đề