web-development-kb-asia.site

Tại sao bạn cần rõ ràng có đối số "tự" thành một phương thức Python?

Khi định nghĩa một phương thức trên một lớp trong Python, nó trông giống như thế này:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

Nhưng trong một số ngôn ngữ khác, chẳng hạn như C #, bạn có một tham chiếu đến đối tượng mà phương thức được liên kết với từ khóa "này" mà không khai báo nó là một đối số trong nguyên mẫu phương thức. 

Đây có phải là một quyết định thiết kế ngôn ngữ có chủ ý trong Python hay có một số chi tiết triển khai yêu cầu chuyển "bản thân" làm đối số không?

180
Readonly

Tôi muốn trích dẫn Zen của Python của Peters. "Rõ ràng là tốt hơn so với ngầm."

Trong Java và C++, 'this.' có thể được suy ra, ngoại trừ khi bạn có tên biến khiến không thể suy ra. Vì vậy, đôi khi bạn cần nó và đôi khi không.

Python chọn để làm cho những thứ như thế này rõ ràng hơn là dựa trên một quy tắc. 

Ngoài ra, vì không có gì được ngụ ý hay giả định, các phần của việc thực hiện được phơi bày. self.__class__, self.__dict__ và các cấu trúc "nội bộ" khác có sẵn một cách rõ ràng.

88
S.Lott

Đó là để giảm thiểu sự khác biệt giữa các phương thức và chức năng. Nó cho phép bạn dễ dàng tạo các phương thức trong siêu dữ liệu hoặc thêm các phương thức trong thời gian chạy vào các lớp có sẵn.

ví dụ.

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

Nó cũng (theo như tôi biết) làm cho việc thực hiện thời gian chạy python dễ dàng hơn.

55
Ryan

Tôi đề nghị một người nên đọc Blog của Guido van Rossum về chủ đề này - Tại sao bản thân rõ ràng phải ở lại .

Khi một định nghĩa phương thức được trang trí, chúng ta không biết nên tự động cung cấp cho nó một tham số 'tự' hay không: trình trang trí có thể biến hàm thành một phương thức tĩnh (không có 'tự') hoặc một phương thức lớp (mà có một kiểu tự hài hước đề cập đến một lớp thay vì một thể hiện) hoặc nó có thể làm một cái gì đó hoàn toàn khác (việc viết một trình trang trí thực hiện '@ classmethod' hoặc '@staticmethod' trong Python thuần túy) Không có cách nào mà không biết người trang trí làm gì có nên ban cho phương thức được xác định bằng một đối số 'tự' ngầm hay không.

Tôi từ chối các bản hack như vỏ bọc đặc biệt '@ classmethod' và '@staticmethod'.

51
bhadra

Python không ép buộc bạn sử dụng "tự". Bạn có thể đặt cho nó bất cứ tên nào bạn muốn. Bạn chỉ cần nhớ rằng đối số đầu tiên trong tiêu đề định nghĩa phương thức là tham chiếu đến đối tượng.

16
Victor Noagbodji

Đồng thời cho phép bạn làm điều này: (nói ngắn gọn, gọi Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) sẽ trả về 12, nhưng sẽ làm như vậy theo những cách điên rồ nhất.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Tất nhiên, điều này khó tưởng tượng hơn trong các ngôn ngữ như Java và C #. Bằng cách làm cho tham chiếu tự rõ ràng, bạn có thể tự do tham khảo bất kỳ đối tượng nào bằng cách tự tham chiếu đó. Ngoài ra, cách chơi với các lớp trong thời gian chạy như vậy khó thực hiện hơn trong các ngôn ngữ tĩnh hơn - không nhất thiết phải tốt hay xấu. Chỉ là bản thân rõ ràng cho phép tất cả sự điên rồ này tồn tại.

Hơn nữa, hãy tưởng tượng điều này: Chúng tôi muốn tùy chỉnh hành vi của các phương thức (để định hình hoặc một số phép thuật đen điên rồ). Điều này có thể khiến chúng ta suy nghĩ: điều gì xảy ra nếu chúng ta có một lớp Method mà hành vi chúng ta có thể ghi đè hoặc kiểm soát?

Vâng, đây là:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

Và bây giờ: InnocentClass().magic_method() sẽ hoạt động như mong đợi. Phương thức sẽ được liên kết với tham số innocent_self thành InnocentClass và với magic_self với thể hiện MagicMethod. Lạ nhỉ? Giống như có 2 từ khóa this1this2 bằng các ngôn ngữ như Java và C #. Phép thuật như thế này cho phép các khung công tác thực hiện những thứ mà nếu không thì sẽ dài dòng hơn nhiều.

Một lần nữa, tôi không muốn bình luận về Đạo đức của công cụ này. Tôi chỉ muốn thể hiện những điều khó thực hiện hơn nếu không có tài liệu tham khảo rõ ràng.

6
vlad-ardelean

Tôi nghĩ lý do thực sự ngoài "The Zen of Python" là Hàm là công dân hạng nhất trong Python. 

Mà về cơ bản làm cho họ trở thành một đối tượng. Bây giờ Vấn đề cơ bản là nếu các chức năng của bạn cũng là đối tượng thì trong mô hình hướng đối tượng, bạn sẽ gửi tin nhắn đến các đối tượng như thế nào khi chính các tin nhắn là đối tượng? 

Trông giống như một vấn đề Trứng gà, để giảm nghịch lý này, cách duy nhất có thể là chuyển một bối cảnh thực thi sang các phương thức hoặc phát hiện ra nó. Nhưng vì python có thể có các hàm lồng nhau nên sẽ không thể làm như vậy vì bối cảnh thực thi sẽ thay đổi cho các hàm bên trong. 

Điều này có nghĩa là giải pháp khả thi duy nhất là vượt qua 'bản thân' một cách rõ ràng (Bối cảnh thực hiện).

Vì vậy, tôi tin rằng đây là một vấn đề triển khai mà Zen đã đến nhiều sau đó.

2
pankajdoharey

Tôi nghĩ rằng nó phải làm với PEP 227:

Tên trong phạm vi lớp học không thể truy cập. Tên được giải quyết trong phạm vi chức năng kèm theo trong cùng. Nếu một định nghĩa lớp xảy ra trong một chuỗi phạm vi lồng nhau, quá trình phân giải bỏ qua lớp định nghĩa. Quy tắc này ngăn chặn các tương tác kỳ lạ giữa các lớp thuộc tính và truy cập biến cục bộ. Nếu một tên ràng buộc hoạt động xảy ra trong một định nghĩa lớp, nó tạo ra một thuộc tính trên kết quả đối tượng lớp. Để truy cập biến này trong một phương thức hoặc trong một hàm lồng trong một phương thức, một tham chiếu thuộc tính phải được sử dụng, hoặc thông qua bản thân hoặc thông qua tên lớp.

2
daole

Như đã giải thích trong self trong Python, Demystified

bất cứ điều gì như obj.meth (args) trở thành Class.meth (obj, args). Quá trình gọi là tự động trong khi quá trình nhận không (rõ ràng). Đây là lý do tham số đầu tiên của hàm trong lớp phải là chính đối tượng. 

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from Origin"""
        return (self.x**2 + self.y**2) ** 0.5

Lời mời:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () định nghĩa ba tham số nhưng chúng ta chỉ truyền hai (6 và 8). Tương tự khoảng cách () yêu cầu một nhưng không có đối số nào được thông qua. 

Tại sao Python không phàn nàn về số đối số này không khớp?

Nói chung, khi chúng ta gọi một phương thức với một số đối số, hàm lớp tương ứng được gọi bằng cách đặt đối tượng của phương thức trước đối số đầu tiên. Vì vậy, bất cứ điều gì như obj.meth (args) sẽ trở thành Class.meth (obj, args). Quá trình gọi là tự động trong khi quá trình nhận không (rõ ràng).

Đây là lý do tham số đầu tiên của hàm trong lớp phải là chính đối tượng. Viết tham số này là tự nó chỉ là một quy ước. Nó không phải là một từ khóa và không có ý nghĩa đặc biệt trong Python. Chúng tôi có thể sử dụng tên khác (như thế này) nhưng tôi thực sự khuyên bạn không nên. Việc sử dụng các tên khác ngoài bản thân được hầu hết các nhà phát triển cau mày và làm giảm khả năng đọc của mã ("Số lượng dễ đọc") . 
...
Trong, ví dụ đầu tiên self.x là một thuộc tính thể hiện trong khi x là biến cục bộ. Chúng không giống nhau và nằm trong các không gian tên khác nhau.

Tự ở đây để ở lại

Nhiều người đã đề xuất biến mình thành một từ khóa trong Python, như thế này trong C++ và Java. Điều này sẽ loại bỏ việc sử dụng bản thân rõ ràng khỏi danh sách tham số chính thức trong các phương thức. Mặc dù ý tưởng này có vẻ hứa hẹn, nhưng nó sẽ không xảy ra. Ít nhất là không trong tương lai gần. Lý do chính là khả năng tương thích ngược. Dưới đây là một blog từ chính người tạo ra Python giải thích lý do tại sao bản thân rõ ràng phải ở lại.

0
mon