Lớp Python không có phương thức

Trong một màn hình điện thoại gần đây, tôi đã quyết định sử dụng một thuộc tính lớp để triển khai một API Python nhất định. Người phỏng vấn của tôi đã thách thức tôi, đặt câu hỏi liệu mã của tôi có hợp lệ về mặt cú pháp hay không, khi nó được thực thi, v.v. Trên thực tế, bản thân tôi cũng không chắc chắn về câu trả lời. Vì vậy, tôi đã làm một số đào. Thuộc tính lớp Python. Không ai thực sự biết khi nào [hoặc làm thế nào] để sử dụng 'em. Trong hướng dẫn này, tôi điểm qua những cạm bẫy phổ biến và kết luận bằng một danh sách các trường hợp sử dụng hợp lệ có thể giúp bạn tiết kiệm thời gian, năng lượng và các dòng mã

Qua

Charles đầm lầy

Charlie [BCS, Princeton] đã từng là trưởng nhóm kỹ thuật tại Khan Academy, sau đó là Cedar, và hiện nay là ML tại Spring Discovery

ĐĂNG LẠI

ĐĂNG LẠI

Tôi đã có một cuộc phỏng vấn lập trình gần đây, một màn hình điện thoại trong đó chúng tôi đã sử dụng trình soạn thảo văn bản hợp tác

Tôi được yêu cầu triển khai một API nhất định và đã chọn thực hiện bằng Python. Trừu tượng hóa câu lệnh vấn đề, giả sử tôi cần một lớp có các thể hiện được lưu trữ một số

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
3 và một số
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
4

Tôi hít một hơi thật sâu và bắt đầu gõ. Sau một vài dòng, tôi đã có một cái gì đó như thế này

class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...

Người phỏng vấn của tôi đã ngăn tôi lại

  • người phỏng vấn. “Dòng đó.
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    5. Tôi không nghĩ đó là Python hợp lệ?”
  • Tôi. “Tôi khá chắc là. Nó chỉ đặt giá trị mặc định cho thuộc tính thể hiện. ”
  • người phỏng vấn. “Khi nào đoạn mã đó được thực thi?”
  • Tôi. “Tôi không thực sự chắc chắn. Tôi sẽ chỉ sửa nó để tránh nhầm lẫn. ”

Để tham khảo và cung cấp cho bạn ý tưởng về mục đích của tôi, đây là cách tôi sửa đổi mã

class Service[object]:

    def __init__[self, other_data]:
        self.data = []
        self.other_data = other_data
    ...

Hóa ra, cả hai chúng ta đều sai. Câu trả lời thực sự nằm ở việc hiểu được sự khác biệt giữa các thuộc tính lớp Python và các thuộc tính thể hiện của Python

Ghi chú. nếu bạn có kiến ​​thức chuyên môn về các thuộc tính của lớp, bạn có thể bỏ qua phần tiếp theo

Thuộc tính lớp Python

Người phỏng vấn của tôi đã sai ở chỗ đoạn mã trên hợp lệ về mặt cú pháp

Tôi cũng đã sai ở chỗ nó không đặt "giá trị mặc định" cho thuộc tính thể hiện. Thay vào đó, nó định nghĩa

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
3 như một thuộc tính lớp có giá trị
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
7

Theo kinh nghiệm của tôi, các thuộc tính lớp Python là một chủ đề mà nhiều người biết điều gì đó, nhưng ít người hiểu hoàn toàn

Biến lớp Python so với. Biến thể hiện. Có gì khác biệt?

Thuộc tính lớp Python là thuộc tính của lớp [thông tư, tôi biết], chứ không phải là thuộc tính của một thể hiện của lớp

Hãy sử dụng một ví dụ lớp Python để minh họa sự khác biệt. Ở đây,

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
8 là thuộc tính lớp và
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
9 là thuộc tính thể hiện

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var

Lưu ý rằng tất cả các phiên bản của lớp đều có quyền truy cập vào

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
8 và nó cũng có thể được truy cập như một thuộc tính của chính lớp đó

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
1

Đối với các lập trình viên Java hoặc C++, thuộc tính lớp tương tự—nhưng không giống hệt—với thành viên tĩnh. Chúng ta sẽ thấy chúng khác nhau như thế nào sau

lớp vs. Không gian tên đối tượng

Để hiểu những gì đang xảy ra ở đây, hãy nói ngắn gọn về không gian tên Python

Không gian tên là ánh xạ từ tên đến đối tượng, với thuộc tính không có mối quan hệ nào giữa các tên trong các không gian tên khác nhau. Chúng thường được triển khai dưới dạng từ điển Python, mặc dù điều này được trừu tượng hóa

Tùy thuộc vào ngữ cảnh, bạn có thể cần truy cập một không gian tên bằng cách sử dụng cú pháp dấu chấm [e. g. ,

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
11] hoặc dưới dạng biến cục bộ [e. g. ,
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
12]. Như một ví dụ cụ thể

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
4

Các lớp Python và các thể hiện của các lớp đều có các không gian tên riêng biệt được đại diện bởi

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
13 và
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
14, tương ứng

Khi bạn cố gắng truy cập một thuộc tính từ một thể hiện của một lớp, trước tiên nó sẽ xem không gian tên thể hiện của nó. Nếu nó tìm thấy thuộc tính, nó sẽ trả về giá trị được liên kết. Nếu không, nó sẽ tìm trong không gian tên của lớp và trả về thuộc tính [nếu có, sẽ báo lỗi nếu không]. Ví dụ

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
7

Không gian tên cá thể chiếm ưu thế hơn không gian tên lớp. nếu có một thuộc tính có cùng tên trong cả hai, không gian tên đối tượng sẽ được kiểm tra trước và giá trị của nó được trả về. Đây là phiên bản đơn giản hóa của mã [] để tra cứu thuộc tính

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
8

Và, ở dạng trực quan

Cách các thuộc tính lớp xử lý chuyển nhượng

Với suy nghĩ này, chúng ta có thể hiểu cách các thuộc tính lớp Python xử lý phép gán

  • Nếu một thuộc tính lớp được đặt bằng cách truy cập lớp, nó sẽ ghi đè giá trị cho tất cả các phiên bản. Ví dụ

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    9

    Ở cấp độ không gian tên… chúng tôi đang đặt

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    15. [Ghi chú. đây không phải là mã chính xác [có thể là
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    16] vì
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    17 trả về một , một trình bao bọc bất biến để ngăn việc gán trực tiếp, nhưng nó giúp ích cho mục đích trình diễn]. Sau đó, khi chúng tôi truy cập
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    18,
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    8 có một giá trị mới trong không gian tên lớp và do đó 2 được trả về

  • Nếu một biến lớp Python được đặt bằng cách truy cập một thể hiện, thì nó sẽ chỉ ghi đè giá trị cho thể hiện đó. Về cơ bản, điều này sẽ ghi đè biến lớp và biến nó thành một biến thể hiện có sẵn, theo trực giác, chỉ dành cho thể hiện đó. Ví dụ

    class Service[object]:
        data = []
    
        def __init__[self, other_data]:
            self.other_data = other_data
        ...
    
    5

    Ở cấp độ không gian tên… chúng tôi đang thêm thuộc tính

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    8 vào
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    41, vì vậy khi tra cứu
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    18, chúng tôi trả về 2. Trong khi đó, các phiên bản khác của
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    43 sẽ không có
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    8 trong không gian tên phiên bản của chúng, vì vậy chúng tiếp tục tìm thấy
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    8 trong
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    13 và do đó trả về 1

khả năng biến đổi

câu hỏi trắc nghiệm. Nếu thuộc tính lớp của bạn có loại có thể thay đổi thì sao?

Điều này được thể hiện rõ nhất bằng ví dụ. Hãy quay lại

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 mà tôi đã xác định trước đó và xem việc sử dụng biến lớp của tôi có thể dẫn đến các vấn đề sau này như thế nào

class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...

Mục tiêu của tôi là có danh sách trống [

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
7] làm giá trị mặc định cho
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
3 và đối với mỗi trường hợp của
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 để có dữ liệu riêng sẽ được thay đổi theo thời gian trên cơ sở từng trường hợp. Nhưng trong trường hợp này, chúng tôi nhận được hành vi sau [nhớ lại rằng
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 lấy một số đối số
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
4, trong ví dụ này là tùy ý]

class Service[object]:

    def __init__[self, other_data]:
        self.data = []
        self.other_data = other_data
    ...
0

Điều này là không tốt—việc thay đổi biến lớp thông qua một phiên bản sẽ thay đổi nó cho tất cả các phiên bản khác

Ở cấp độ không gian tên… tất cả các phiên bản của

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 đang truy cập và sửa đổi cùng một danh sách trong
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
74 mà không tạo thuộc tính
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
3 của riêng chúng trong không gian tên phiên bản của chúng

Chúng ta có thể giải quyết vấn đề này bằng cách sử dụng bài tập;

class Service[object]:

    def __init__[self, other_data]:
        self.data = []
        self.other_data = other_data
    ...
1

Trong trường hợp này, chúng tôi đang thêm

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
77, vì vậy
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
78 ban đầu không thay đổi

Thật không may, điều này đòi hỏi người dùng

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 phải có kiến ​​thức sâu sắc về các biến của nó và chắc chắn dễ mắc sai lầm. Theo một nghĩa nào đó, chúng tôi sẽ giải quyết các triệu chứng hơn là nguyên nhân. Chúng tôi muốn một cái gì đó đã được xây dựng chính xác

Giải pháp cá nhân của tôi. nếu bạn chỉ đang sử dụng một biến lớp để gán giá trị mặc định cho một biến thể hiện của Python, thì đừng sử dụng các giá trị có thể thay đổi. Trong trường hợp này, mọi phiên bản của

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
47 cuối cùng sẽ ghi đè lên
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
81 bằng thuộc tính phiên bản riêng của nó, do đó, việc sử dụng một danh sách trống làm mặc định dẫn đến một lỗi nhỏ dễ bị bỏ qua. Thay vì ở trên, chúng ta có thể có một trong hai

  1. Bị mắc kẹt hoàn toàn với các thuộc tính thể hiện, như đã trình bày trong phần giới thiệu
  2. Tránh sử dụng danh sách trống [giá trị có thể thay đổi] làm “mặc định” của chúng tôi

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    2

    Tất nhiên, chúng tôi phải xử lý vụ án

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    82 một cách thích hợp, nhưng đó là một cái giá nhỏ phải trả

Vậy khi nào bạn nên sử dụng thuộc tính lớp Python?

Các thuộc tính của lớp rất phức tạp, nhưng hãy xem xét một vài trường hợp khi chúng có ích

  1. Lưu trữ hằng số. Vì các thuộc tính của lớp có thể được truy cập dưới dạng các thuộc tính của chính lớp đó, nên thường sử dụng chúng để lưu trữ các hằng số cụ thể của Lớp, toàn Lớp. Ví dụ

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    3
  2. Xác định giá trị mặc định. Như một ví dụ tầm thường, chúng ta có thể tạo một danh sách giới hạn [i. e. , một danh sách chỉ có thể chứa một số phần tử nhất định hoặc ít hơn] và chọn giới hạn mặc định là 10 mục

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    4

    Sau đó, chúng tôi cũng có thể tạo các phiên bản có giới hạn cụ thể của riêng chúng bằng cách gán cho thuộc tính

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    83 của phiên bản

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    5

    Điều này chỉ có ý nghĩa nếu bạn muốn phiên bản điển hình của

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    43 chỉ chứa 10 phần tử hoặc ít hơn—nếu bạn đưa ra các giới hạn khác nhau cho tất cả các phiên bản của mình, thì
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    83 phải là một biến thể hiện. [Hãy nhớ rằng, mặc dù. cẩn thận khi sử dụng các giá trị có thể thay đổi làm giá trị mặc định của bạn. ]

  3. Theo dõi tất cả dữ liệu trên tất cả các phiên bản của một lớp nhất định. Đây là một loại cụ thể, nhưng tôi có thể thấy một tình huống trong đó bạn có thể muốn truy cập một phần dữ liệu liên quan đến mọi phiên bản hiện có của một lớp nhất định

    Để làm cho kịch bản cụ thể hơn, giả sử chúng ta có một lớp

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    86 và mỗi người có một lớp
    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    87. Chúng tôi muốn theo dõi tất cả các tên đã được sử dụng. Một cách tiếp cận có thể là lặp qua danh sách các đối tượng của trình thu gom rác, nhưng việc sử dụng các biến lớp sẽ đơn giản hơn

    Lưu ý rằng, trong trường hợp này,

    class MyClass[object]:
        class_var = 1
    
        def __init__[self, i_var]:
            self.i_var = i_var
    
    88 sẽ chỉ được truy cập dưới dạng biến lớp, vì vậy giá trị mặc định có thể thay đổi được chấp nhận

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    6

    Chúng tôi thậm chí có thể sử dụng mẫu thiết kế này để theo dõi tất cả các phiên bản hiện có của một lớp nhất định, thay vì chỉ một số dữ liệu liên quan

    class Service[object]:
    
        def __init__[self, other_data]:
            self.data = []
            self.other_data = other_data
        ...
    
    7
  4. Hiệu suất [đại loại là… xem bên dưới]

Có liên quan. Mẹo và phương pháp hay nhất về Python của Toptal Developers

Dưới mui xe

Ghi chú. Nếu bạn lo lắng về hiệu suất ở cấp độ này, thì bạn có thể không muốn sử dụng Python ngay từ đầu, vì sự khác biệt sẽ ở mức phần mười mili giây—nhưng vẫn rất thú vị khi tìm hiểu một chút và sẽ giúp ích cho bạn

Nhớ lại rằng không gian tên của một lớp được tạo và điền vào thời điểm định nghĩa lớp. Điều đó có nghĩa là chúng ta chỉ thực hiện một phép gán—không bao giờ—cho một biến lớp nhất định, trong khi các biến thể hiện phải được gán mỗi khi một thể hiện mới được tạo. Hãy lấy một ví dụ

class Service[object]:

    def __init__[self, other_data]:
        self.data = []
        self.other_data = other_data
    ...
8

Chúng tôi chỉ gán cho

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
89 một lần, nhưng
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
90 cho mọi cuộc gọi tới
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
91

Để có thêm bằng chứng, hãy sử dụng trình dịch ngược Python

class Service[object]:

    def __init__[self, other_data]:
        self.data = []
        self.other_data = other_data
    ...
9

Khi chúng ta nhìn vào mã byte, một lần nữa rõ ràng là

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
92 phải thực hiện hai nhiệm vụ, trong khi
class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
93 chỉ thực hiện một nhiệm vụ

Trong thực tế, mức tăng này thực sự trông như thế nào?

Tuy nhiên, tôi nghĩ rằng những đoạn mã nhỏ này [chạy với mô-đun timeit của Python] giúp minh họa sự khác biệt giữa các biến lớp và biến thể hiện, vì vậy tôi vẫn đưa chúng vào

Ghi chú. Tôi đang dùng MacBook Pro với OS X 10. 8. 5 và Trăn 2. 7. 2

Khởi tạo

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
0

Quá trình khởi tạo của

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
94 nhanh hơn hơn một giây, do đó, sự khác biệt ở đây dường như có ý nghĩa thống kê

Vậy tại sao lại như vậy? . chúng tôi làm hai bài tập trong ________ 192, nhưng chỉ một bài trong ________ 193

Phân công

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
1

Ghi chú. Không có cách nào để chạy lại mã thiết lập của bạn trong mỗi lần dùng thử theo thời gian, vì vậy chúng tôi phải khởi tạo lại biến của mình trong lần dùng thử. Dòng thời gian thứ hai biểu thị thời gian trên với thời gian khởi tạo được tính toán trước đó đã trừ

Từ những điều trên, có vẻ như _______ 197 chỉ mất khoảng 60% miễn là ________ 194 xử lý các bài tập

Tại sao điều này là trường hợp? . khi chúng tôi gán cho

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
99, trước tiên chúng tôi tìm trong vùng tên đối tượng [
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
50], không tìm thấy
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
51, sau đó tìm trong vùng tên lớp [
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
52], sau đó thực hiện phép gán thích hợp. Khi chúng tôi gán cho
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
53, chúng tôi thực hiện số lần tra cứu chỉ bằng một nửa so với khi chúng tôi gán ngay cho không gian tên đối tượng [
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
54]

Tóm lại, mặc dù những mức tăng hiệu suất này không quan trọng trong thực tế, nhưng những thử nghiệm này rất thú vị ở cấp độ khái niệm. Nếu có bất cứ điều gì, tôi hy vọng những khác biệt này sẽ giúp minh họa sự khác biệt cơ học giữa các biến lớp và biến thể hiện

Tóm lại là

Các thuộc tính lớp dường như không được sử dụng đúng mức trong Python;

của tôi. Các biến lớp Python có vị trí của chúng trong trường mã tốt. Khi được sử dụng cẩn thận, chúng có thể đơn giản hóa mọi thứ và cải thiện khả năng đọc. Nhưng khi bất cẩn ném vào một lớp nhất định, họ chắc chắn sẽ làm bạn vấp ngã

ruột thừa. Biến thể hiện cá nhân

Một điều tôi muốn đưa vào nhưng không có điểm vào tự nhiên…

Có thể nói Python không có các biến riêng tư, nhưng một mối quan hệ thú vị khác giữa cách đặt tên lớp và cá thể đi kèm với việc xáo trộn tên

Trong hướng dẫn về phong cách Python, người ta nói rằng các biến giả riêng phải được thêm tiền tố bằng dấu gạch dưới kép. '__'. Đây không chỉ là một dấu hiệu cho những người khác biết rằng biến của bạn được xử lý riêng tư mà còn là một cách để ngăn chặn quyền truy cập vào nó. Đây là những gì tôi muốn nói

class MyClass[object]:
    class_var = 1

    def __init__[self, i_var]:
        self.i_var = i_var
2

Nhìn kìa. thuộc tính thể hiện

class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
55 được tự động thêm tiền tố vào tên lớp để tạo ra
class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
56

Mặc dù vẫn có thể giải quyết và có thể lấy được bằng cách sử dụng

class Service[object]:
    data = []

    def __init__[self, other_data]:
        self.other_data = other_data
    ...
57, việc xáo trộn tên này là một phương tiện để tạo một biến 'riêng tư' vì nó ngăn bạn và những người khác truy cập vào nó một cách tình cờ hoặc do thiếu hiểu biết

Chỉnh sửa. như Pedro Werneck đã vui lòng chỉ ra, hành vi này phần lớn nhằm mục đích trợ giúp việc phân lớp. Trong , họ thấy nó phục vụ hai mục đích. [1] ngăn các lớp con truy cập các thuộc tính nhất định và [2] ngăn xung đột không gian tên trong các lớp con này. Mặc dù hữu ích, nhưng việc xáo trộn biến không nên được coi là lời mời viết mã với sự phân biệt công khai-riêng tư giả định, chẳng hạn như có trong Java

Có liên quan. Trở nên cao cấp hơn. Tránh 10 lỗi phổ biến nhất mà các lập trình viên Python mắc phải

Hiểu những điều cơ bản

Không gian tên Python là gì?

Như tên gợi ý, không gian tên Python là ánh xạ từ tên sang đối tượng, với thuộc tính không có mối quan hệ nào giữa các tên trong các không gian tên khác nhau. Không gian tên thường được triển khai dưới dạng từ điển Python, mặc dù điều này được trừu tượng hóa

Phương thức lớp Python so với. phương pháp ví dụ. Có gì khác biệt?

Trong Python, một phương thức lớp là một phương thức được gọi với lớp làm ngữ cảnh. Điều này thường được gọi là phương thức tĩnh trong các ngôn ngữ lập trình khác. Mặt khác, một phương thức thể hiện được gọi với một thể hiện là bối cảnh

Điều gì xảy ra nếu cả thuộc tính thể hiện và thuộc tính lớp được xác định?

Trong trường hợp đó, không gian tên cá thể chiếm ưu thế hơn không gian tên lớp. Nếu có một thuộc tính có cùng tên trong cả hai, không gian tên đối tượng sẽ được kiểm tra trước và giá trị của nó được trả về

Chúng ta có thể có một lớp không có phương thức không?

Không có lớp nào không có phương thức . Tất cả các Lớp là lớp con của lớp Đối tượng. Vì vậy, tất cả các phương thức từ lớp Object được kế thừa.

Chúng ta có thể tạo một lớp không có phương thức Init trong Python không?

Mặc dù không bắt buộc , các lớp Python có thể có thứ gì đó tương tự như hàm tạo. phương thức __init__[]. Tuy nhiên, rất hiếm khi thực sự cần triển khai __new[]__ vì Python xây dựng các đối tượng cho chúng ta. Vì vậy, trong hầu hết các trường hợp, chúng ta thường chỉ triển khai phương thức đặc biệt, __init[]__.

Một lớp có thể tồn tại mà không có hàm tạo trong Python không?

Trong Python, để tạo và khởi tạo một đối tượng của một lớp, bạn cần một phương thức đặc biệt và phương thức [hàm] đặc biệt đó được gọi là hàm tạo. Mỗi lớp đều có một hàm tạo, nhưng không bắt buộc phải định nghĩa nó một cách rõ ràng .

Chúng ta có thể định nghĩa một phương thức không có lớp trong Python không?

Có, bạn chắc chắn có thể có các hàm bên ngoài lớp học .

Chủ Đề