Python tên mangling


109

Trong các ngôn ngữ khác, một nguyên tắc chung giúp tạo ra mã tốt hơn là luôn ẩn mọi thứ càng tốt. Nếu nghi ngờ về việc liệu một biến có nên là riêng tư hay được bảo vệ hay không, tốt hơn là nên chọn chế độ riêng tư.

Điều tương tự có đúng với Python không? Lúc đầu, tôi có nên sử dụng hai dấu gạch dưới hàng đầu trên mọi thứ và chỉ làm cho chúng ít bị ẩn hơn (chỉ một dấu gạch dưới) khi tôi cần chúng không?

Nếu quy ước là chỉ sử dụng một dấu gạch dưới, tôi cũng muốn biết cơ sở lý luận.

Đây là nhận xét tôi để lại về câu trả lời của JBernardo . Nó giải thích tại sao tôi hỏi câu hỏi này và cũng là lý do tại sao tôi muốn biết tại sao Python lại khác với các ngôn ngữ khác:

Tôi đến từ những ngôn ngữ giúp bạn nghĩ rằng mọi thứ chỉ nên công khai khi cần thiết và không hơn thế nữa. Lý do là điều này sẽ làm giảm sự phụ thuộc và làm cho mã an toàn hơn để thay đổi. Cách thức hoạt động của Python ngược lại - bắt đầu từ công khai và chuyển sang ẩn - đối với tôi là kỳ lạ.

Câu trả lời:


182

Khi nghi ngờ, hãy để nó ở chế độ "công khai" - ý tôi là đừng thêm bất cứ thứ gì để che khuất tên thuộc tính của bạn. Nếu bạn có một lớp với một số giá trị nội bộ, đừng bận tâm về nó. Thay vì viết:

class Stack(object):

    def __init__(self):
        self.__storage = [] # Too uptight

    def push(self, value):
        self.__storage.append(value)

viết cái này theo mặc định:

class Stack(object):

    def __init__(self):
        self.storage = [] # No mangling

    def push(self, value):
        self.storage.append(value)

Đây chắc chắn là một cách làm gây tranh cãi. Những người mới dùng Python chỉ ghét nó và thậm chí một số anh chàng Python cũ cũng coi thường mặc định này - nhưng dù sao thì nó cũng là mặc định, vì vậy tôi thực sự khuyên bạn nên làm theo nó, ngay cả khi bạn cảm thấy không thoải mái.

Nếu bạn thực sự muốn gửi thông báo "Không thể chạm vào cái này!" đối với người dùng của bạn, cách thông thường là đặt trước biến bằng một dấu gạch dưới. Đây chỉ là một quy ước, nhưng mọi người hiểu nó và cẩn thận khi xử lý những thứ như vậy:

class Stack(object):

    def __init__(self):
        self._storage = [] # This is ok but pythonistas use it to be relaxed about it

    def push(self, value):
        self._storage.append(value)

Điều này cũng có thể hữu ích để tránh xung đột giữa tên thuộc tính và tên thuộc tính:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

Còn dấu gạch dưới kép thì sao? Chà, phép thuật gạch dưới kép được sử dụng chủ yếu để tránh tình trạng quá tải các phương thức và xung đột tên với các thuộc tính của lớp cha . Nó có thể khá hữu ích nếu bạn viết một lớp dự kiến ​​sẽ được kéo dài nhiều lần.

Nếu bạn muốn sử dụng nó cho các mục đích khác, bạn có thể, nhưng nó không bình thường và cũng không được khuyến khích.

EDIT : Tại sao điều này là như vậy? Chà, kiểu Python thông thường không nhấn mạnh đến việc đặt mọi thứ ở chế độ riêng tư - ngược lại! Có rất nhiều lý do cho điều đó - hầu hết đều gây tranh cãi ... Chúng ta hãy xem một số trong số đó.

Python có các thuộc tính

Hầu hết các ngôn ngữ OO ngày nay sử dụng cách tiếp cận ngược lại: những gì không nên sử dụng sẽ không được hiển thị, do đó các thuộc tính phải là riêng tư. Về mặt lý thuyết, điều này sẽ mang lại nhiều lớp dễ quản lý hơn, ít ghép nối hơn, bởi vì không ai có thể thay đổi các giá trị bên trong các đối tượng một cách liều lĩnh.

Tuy nhiên, nó không đơn giản như vậy. Ví dụ, các lớp Java có rất nhiều thuộc tính và bộ nhận chỉ lấy giá trị và bộ định tuyến chỉ đặt giá trị. Giả sử bạn cần bảy dòng mã để khai báo một thuộc tính duy nhất - điều mà một lập trình viên Python sẽ nói là phức tạp không cần thiết. Ngoài ra, trên thực tế, bạn chỉ cần viết toàn bộ đoạn mã này để lấy một trường công khai, vì bạn có thể thay đổi giá trị của nó bằng cách sử dụng getters và setters.

Vậy tại sao phải tuân theo chính sách private-by-default này? Chỉ cần đặt thuộc tính của bạn ở chế độ công khai theo mặc định. Tất nhiên, đây là vấn đề trong Java, vì nếu bạn quyết định thêm một số xác thực vào thuộc tính của mình, nó sẽ yêu cầu bạn thay đổi tất cả

person.age = age;

trong mã của bạn, hãy để chúng tôi nói,

person.setAge(age);

setAge() là:

public void setAge(int age) {
    if (age >= 0) {
        this.age = age;
    } else {
        this.age = 0;
    }
}

Vì vậy, trong Java (và các ngôn ngữ khác), mặc định là sử dụng getters và setters, vì chúng có thể gây khó chịu khi viết nhưng có thể giúp bạn tiết kiệm rất nhiều thời gian nếu bạn rơi vào tình huống mà tôi đã mô tả.

Tuy nhiên, bạn không cần phải làm điều đó trong Python, vì Python có các thuộc tính. Nếu bạn có lớp học này:

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self.age = age

và sau đó bạn quyết định xác thực độ tuổi, bạn không cần phải thay đổi các person.age = agephần mã của mình. Chỉ cần thêm một thuộc tính (như hình bên dưới)

 class Person(object):
     def __init__(self, name, age):
         self.name = name
         self._age = age if age >= 0 else 0

     @property
     def age(self):
         return self._age

     @age.setter
     def age(self, age):
         if age >= 0:
             self._age = age
         else:
             self._age  = 0

Nếu bạn có thể làm điều đó và vẫn sử dụng person.age = age, tại sao bạn lại thêm các trường riêng tư và getters và setters?

(Ngoài ra, hãy xem Python không phải là Javabài viết này về tác hại của việc sử dụng getters và setters .).

Mọi thứ đều hiển thị - và cố gắng che giấu chỉ làm phức tạp công việc của bạn

Ngay cả trong những ngôn ngữ có các thuộc tính riêng tư, bạn có thể truy cập chúng thông qua một số loại thư viện phản ánh / nội quan. Và mọi người làm điều đó rất nhiều, trong khuôn khổ và để giải quyết các nhu cầu cấp thiết. Vấn đề là các thư viện nội quan chỉ là một cách khó để thực hiện những gì bạn có thể làm với các thuộc tính chung.

Vì Python là một ngôn ngữ rất năng động, nên việc thêm gánh nặng này vào các lớp của bạn sẽ phản tác dụng.

Vấn đề là không thể nhìn thấy - nó được yêu cầu để xem

Đối với Pythonista, việc bao bọc không phải là không có khả năng nhìn thấy bên trong của các lớp, mà là khả năng tránh nhìn vào nó. Ý tôi là, tính đóng gói là thuộc tính của một thành phần cho phép nó được sử dụng mà người dùng không quan tâm đến các chi tiết bên trong. Nếu bạn có thể sử dụng một thành phần mà không cần bận tâm về việc triển khai nó, thì nó được đóng gói (theo ý kiến ​​của một lập trình viên Python).

Bây giờ, nếu bạn đã viết lớp của mình theo cách như vậy, bạn có thể sử dụng nó mà không cần phải suy nghĩ về các chi tiết triển khai, không có vấn đề gì nếu bạn muốn xem bên trong lớp vì một lý do nào đó. Vấn đề là: API của bạn phải tốt và phần còn lại là chi tiết.

Guido đã nói như vậy

Chà, điều này không có gì phải bàn cãi: thực ra anh ấy đã nói như vậy . (Tìm "kimono hở.")

Đây là văn hóa

Có, có một số lý do, nhưng không có lý do quan trọng nào. Đây chủ yếu là một khía cạnh văn hóa của lập trình bằng Python. Thành thật mà nói, nó cũng có thể là theo cách khác - nhưng không phải vậy. Ngoài ra, bạn có thể dễ dàng hỏi ngược lại: tại sao một số ngôn ngữ sử dụng thuộc tính riêng theo mặc định? Vì lý do chính tương tự như đối với thực hành Python: bởi vì nó là văn hóa của các ngôn ngữ này, và mỗi lựa chọn đều có ưu điểm và nhược điểm.

Vì đã có văn hóa này, bạn nên tuân theo nó. Nếu không, bạn sẽ thấy khó chịu khi các lập trình viên Python yêu cầu bạn xóa __mã khỏi mã của bạn khi bạn đặt câu hỏi trong Stack Overflow :)


1. Đóng gói là để bảo vệ các bất biến của lớp. Không che giấu những chi tiết không cần thiết với thế giới bên ngoài vì đó sẽ là một điều khó chịu. 2. "Vấn đề là: API của bạn phải tốt và phần còn lại là chi tiết." Đây là sự thật. Và các thuộc tính công khai là một phần của API của bạn. Ngoài ra, đôi khi các bộ cài đặt công khai thích hợp (liên quan đến các bất biến trong lớp của bạn) và đôi khi chúng không phù hợp. Một API có các bộ thiết lập công khai không được công khai (nguy cơ vi phạm các thay đổi) là một API xấu. Điều này có nghĩa là bạn phải nghĩ về khả năng hiển thị của từng setter và việc có 'default' có nghĩa là ít hơn.
Sao Mộc

21

Đầu tiên - Tên mangling là gì?

Tên mangling được gọi khi bạn đang ở trong định nghĩa và sử dụng lớp __any_namehoặc __any_name_, nghĩa là hai (hoặc nhiều) dấu gạch dưới ở đầu và nhiều nhất là một dấu gạch dưới ở cuối.

class Demo:
    __any_name = "__any_name"
    __any_other_name_ = "__any_other_name_"

Và bây giờ:

>>> [n for n in dir(Demo) if 'any' in n]
['_Demo__any_name', '_Demo__any_other_name_']
>>> Demo._Demo__any_name
'__any_name'
>>> Demo._Demo__any_other_name_
'__any_other_name_'

Khi nghi ngờ, hãy làm gì?

Công dụng thể hiện là ngăn các lớp con sử dụng thuộc tính mà lớp đó sử dụng.

Một giá trị tiềm năng là tránh xung đột tên với các lớp con muốn ghi đè hành vi, để chức năng của lớp cha tiếp tục hoạt động như mong đợi. Tuy nhiên, ví dụ trong tài liệu Python không thể thay thế Liskov và không có ví dụ nào xuất hiện trong tâm trí tôi thấy điều này hữu ích.

Nhược điểm là nó làm tăng tải nhận thức để đọc và hiểu cơ sở mã, và đặc biệt là khi gỡ lỗi, nơi bạn thấy tên gạch dưới kép trong nguồn và tên bị xáo trộn trong trình gỡ lỗi.

Cách tiếp cận cá nhân của tôi là cố tình tránh nó. Tôi làm việc trên một cơ sở mã rất lớn. Những công dụng hiếm hoi của nó nhô ra như ngón tay cái đau và dường như không hợp lý.

Bạn cần phải biết về nó để bạn biết nó khi bạn nhìn thấy nó.

PEP 8

PEP 8 , hướng dẫn kiểu thư viện chuẩn Python, hiện cho biết (được rút gọn):

Có một số tranh cãi về việc sử dụng __names.

Nếu lớp của bạn dự định được xếp vào lớp con và bạn có các thuộc tính mà bạn không muốn các lớp con sử dụng, hãy cân nhắc đặt tên chúng bằng dấu gạch dưới đứng đầu kép và không có dấu gạch dưới ở cuối.

  1. Lưu ý rằng chỉ tên lớp đơn giản được sử dụng trong tên bị xáo trộn, vì vậy nếu một lớp con chọn cả tên lớp và tên thuộc tính giống nhau, bạn vẫn có thể nhận được xung đột tên.

  2. Mangling tên có thể tạo ra một số công dụng nhất định, chẳng hạn như gỡ lỗi và __getattr__()kém tiện lợi hơn. Tuy nhiên, thuật toán mangling tên được ghi chép đầy đủ và dễ dàng thực hiện bằng tay.

  3. Không phải ai cũng thích mangling tên. Cố gắng cân bằng nhu cầu tránh đụng độ tên ngẫu nhiên với khả năng sử dụng của những người gọi nâng cao.

Làm thế nào nó hoạt động?

Nếu bạn thêm hai dấu gạch dưới (không có dấu gạch dưới kép kết thúc) trong định nghĩa lớp, tên sẽ bị xáo trộn và dấu gạch dưới theo sau tên lớp sẽ được thêm vào đối tượng:

>>> class Foo(object):
...     __foobar = None
...     _foobaz = None
...     __fooquux__ = None
... 
>>> [name for name in dir(Foo) if 'foo' in name]
['_Foo__foobar', '__fooquux__', '_foobaz']

Lưu ý rằng tên sẽ chỉ bị xáo trộn khi định nghĩa lớp được phân tích cú pháp:

>>> Foo.__test = None
>>> Foo.__test
>>> Foo._Foo__test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute '_Foo__test'

Ngoài ra, những người mới sử dụng Python đôi khi gặp khó khăn khi hiểu chuyện gì đang xảy ra khi họ không thể truy cập thủ công một tên mà họ thấy được xác định trong định nghĩa lớp. Đây không phải là lý do mạnh mẽ chống lại nó, nhưng đó là điều cần xem xét nếu bạn có đối tượng học hỏi.

Một gạch dưới?

Nếu quy ước là chỉ sử dụng một dấu gạch dưới, tôi cũng muốn biết cơ sở lý luận.

Khi ý định của tôi là để người dùng tránh xa một thuộc tính, tôi có xu hướng chỉ sử dụng một dấu gạch dưới, nhưng đó là bởi vì trong mô hình tinh thần của tôi, các lớp con sẽ có quyền truy cập vào tên (mà họ luôn có, vì họ có thể dễ dàng phát hiện ra dù sao cũng có tên mangled).

Nếu tôi đang xem lại mã sử dụng __tiền tố, tôi sẽ hỏi tại sao họ đang gọi tên mangling và nếu họ không thể làm tốt chỉ với một dấu gạch dưới, hãy lưu ý rằng nếu các lớp con chọn cùng tên cho lớp và thuộc tính lớp sẽ có xung đột tên bất chấp điều này.


15

Tôi sẽ không nói rằng thực hành tạo ra mã tốt hơn. Công cụ sửa đổi chế độ hiển thị chỉ khiến bạn mất tập trung khỏi nhiệm vụ đang thực hiện và như một tác dụng phụ buộc giao diện của bạn phải được sử dụng theo ý muốn. Nói chung, việc thực thi khả năng hiển thị ngăn các lập trình viên làm rối tung mọi thứ nếu họ không đọc đúng tài liệu.

Một giải pháp tốt hơn nhiều là lộ trình mà Python khuyến khích: Các lớp và biến của bạn phải được ghi lại đầy đủ và hành vi của chúng rõ ràng. Nguồn nên có sẵn. Đây là cách viết mã có thể mở rộng và đáng tin cậy hơn nhiều.

Chiến lược của tôi trong Python là:

  1. Chỉ cần viết điều chết tiệt, không có giả định nào về cách dữ liệu của bạn nên được bảo vệ. Điều này giả định rằng bạn viết để tạo ra các giao diện lý tưởng cho các vấn đề của bạn.
  2. Sử dụng dấu gạch dưới ở đầu cho những thứ có thể sẽ không được sử dụng bên ngoài và không phải là một phần của giao diện "mã khách hàng" bình thường.
  3. Chỉ sử dụng dấu gạch dưới kép cho những thứ hoàn toàn tiện lợi bên trong lớp học, hoặc sẽ gây ra thiệt hại đáng kể nếu vô tình để lộ.

Trên tất cả, cần phải rõ ràng mọi thứ làm gì. Ghi lại nó nếu ai đó sẽ sử dụng nó. Ghi lại nó nếu bạn muốn nó hữu ích trong thời gian một năm.

Lưu ý thêm, bạn thực sự nên sử dụng bảo vệ bằng các ngôn ngữ khác đó: Bạn không bao giờ biết lớp của mình có thể được kế thừa sau này và nó có thể được sử dụng để làm gì. Tốt nhất chỉ nên bảo vệ những biến mà bạn chắc chắn không thể hoặc không nên sử dụng mã nước ngoài.


9

Bạn không nên bắt đầu với dữ liệu cá nhân và đặt nó ở chế độ công khai nếu cần. Thay vào đó, bạn nên bắt đầu bằng cách tìm ra giao diện của đối tượng của bạn. Tức là bạn nên bắt đầu bằng cách tìm hiểu những gì thế giới nhìn thấy (những thứ công cộng) và sau đó tìm ra những thứ riêng tư nào là cần thiết để điều đó xảy ra.

Các ngôn ngữ khác khó có thể chuyển sang chế độ riêng tư mà đã từng là công khai. Tức là tôi sẽ phá vỡ rất nhiều mã nếu tôi đặt biến của mình ở chế độ riêng tư hoặc được bảo vệ. Nhưng với thuộc tính trong python thì không phải như vậy. Đúng hơn, tôi có thể duy trì cùng một giao diện ngay cả khi sắp xếp lại dữ liệu bên trong.

Sự khác biệt giữa _ và __ là python thực sự cố gắng thực thi cái sau. Tất nhiên, nó không cố gắng thực sự nhưng nó làm cho nó khó khăn. Có _ chỉ đơn thuần nói cho các lập trình viên khác biết ý định là gì, họ có thể tự do bỏ qua nguy cơ của mình. Nhưng bỏ qua quy tắc đó đôi khi lại hữu ích. Ví dụ bao gồm gỡ lỗi, hack tạm thời và làm việc với mã của bên thứ ba không được sử dụng theo cách bạn sử dụng.


6

Đã có rất nhiều câu trả lời hay cho vấn đề này, nhưng tôi sẽ đưa ra một câu trả lời khác. Đây cũng là một phần phản hồi cho những người luôn nói rằng dấu gạch dưới kép không phải là riêng tư (thực sự là như vậy).

Nếu bạn nhìn vào Java / C #, cả hai đều có private / protected / public. Tất cả đều là cấu trúc thời gian biên dịch . Chúng chỉ được thực thi tại thời điểm biên dịch. Nếu bạn sử dụng phản chiếu trong Java / C #, bạn có thể dễ dàng truy cập phương thức riêng tư.

Bây giờ mỗi khi bạn gọi một hàm trong Python, bạn vốn dĩ đang sử dụng phản xạ. Các đoạn mã này giống nhau trong Python.

lst = []
lst.append(1)
getattr(lst, 'append')(1)

Cú pháp "dấu chấm" chỉ là đường cú pháp cho đoạn mã sau. Chủ yếu là vì việc sử dụng getattr đã quá tệ với chỉ một lệnh gọi hàm. Nó chỉ trở nên tồi tệ hơn từ đó.

Vì vậy, không thể có phiên bản Java / C # riêng tư, vì Python không biên dịch mã. Java và C # không thể kiểm tra xem một hàm là riêng tư hay công khai trong thời gian chạy, vì thông tin đó đã biến mất (và nó không biết hàm đang được gọi từ đâu).

Bây giờ với thông tin đó, tên của gạch dưới kép có ý nghĩa nhất để đạt được "private-ness". Bây giờ khi một hàm được gọi từ thể hiện 'self' và nó nhận thấy rằng nó bắt đầu bằng '__', nó chỉ thực hiện việc đặt tên ngay tại đó. Nó chỉ là đường cú pháp hơn. Đường cú pháp đó cho phép tương đương với 'private' trong một ngôn ngữ chỉ sử dụng phản xạ để truy cập thành viên dữ liệu.

Tuyên bố từ chối trách nhiệm: Tôi chưa bao giờ nghe bất kỳ ai từ sự phát triển Python nói bất cứ điều gì như thế này. Lý do thực sự của việc thiếu "private" là do văn hóa, nhưng bạn cũng sẽ nhận thấy rằng hầu hết các ngôn ngữ kịch bản / thông dịch đều không có private. Một private có thể thực thi nghiêm ngặt là không thực tế ở bất cứ điều gì ngoại trừ thời gian biên dịch.


4

Thứ nhất: Tại sao bạn muốn ẩn dữ liệu của mình? Tại sao điều đó lại quan trọng?

Hầu hết thời gian bạn không thực sự muốn làm điều đó nhưng bạn làm vì những người khác đang làm.

Nếu bạn thực sự thực sự không muốn mọi người sử dụng thứ gì đó, hãy thêm một dấu gạch dưới trước nó. Vậy đó ... Pythonistas biết rằng những thứ có một dấu gạch dưới không đảm bảo hoạt động mọi lúc và có thể thay đổi mà bạn không biết.

Đó là cách chúng tôi sống và chúng tôi ổn với điều đó.

Việc sử dụng hai dấu gạch dưới sẽ làm cho lớp của bạn trở nên tồi tệ với lớp con đến mức bạn sẽ không muốn làm việc theo cách đó.


2
Bạn đã bỏ qua lý do dấu gạch dưới kép không tốt cho việc phân lớp ... điều này sẽ cải thiện câu trả lời của bạn.
Matt Joiner

2
Cho rằng các dấu gạch dưới kép thực sự chỉ để ngăn chặn xung đột tên với các lớp con (như một cách nói, "bó tay" với các lớp con), tôi không thấy việc ghép tên tạo ra vấn đề như thế nào.
Aaron Hall

4

Câu trả lời được chọn thực hiện rất tốt trong việc giải thích cách các thuộc tính loại bỏ nhu cầu về các thuộc tính riêng tư , nhưng tôi cũng sẽ thêm rằng các hàm ở cấp mô-đun loại bỏ nhu cầu đối với các phương thức riêng tư .

Nếu bạn biến một phương thức thành một hàm ở cấp độ mô-đun, bạn sẽ loại bỏ cơ hội cho các lớp con ghi đè nó. Di chuyển một số chức năng sang cấp độ mô-đun là Pythonic hơn là cố gắng ẩn các phương pháp với tên mangling.


3

Đoạn mã sau sẽ giải thích tất cả các trường hợp khác nhau:

  • hai dấu gạch dưới ở đầu (__a)
  • dấu gạch dưới hàng đầu (_a)
  • không có gạch dưới (a)

    class Test:
    
    def __init__(self):
        self.__a = 'test1'
        self._a = 'test2'
        self.a = 'test3'
    
    def change_value(self,value):
        self.__a = value
        return self.__a

in tất cả các thuộc tính hợp lệ của Đối tượng thử nghiệm

testObj1 = Test()
valid_attributes = dir(testObj1)
print valid_attributes

['_Test__a', '__doc__', '__init__', '__module__', '_a', 'a', 
'change_value']

Tại đây, bạn có thể thấy tên của __a đã được đổi thành _Test__a để ngăn biến này bị ghi đè bởi bất kỳ lớp con nào. Khái niệm này được gọi là "Name Mangling" trong python. Bạn có thể truy cập như thế này:

testObj2 = Test()
print testObj2._Test__a

test1

Tương tự, trong trường hợp _a, biến chỉ là để thông báo cho nhà phát triển rằng nó nên được sử dụng làm biến nội bộ của lớp đó, trình thông dịch python sẽ không làm bất cứ điều gì ngay cả khi bạn truy cập nó, nhưng đó không phải là một phương pháp hay.

testObj3 = Test()
print testObj3._a

test2

một biến có thể được truy cập từ bất cứ đâu, nó giống như một biến lớp công khai.

testObj4 = Test()
print testObj4.a

test3

Hy vọng câu trả lời đã giúp bạn :)


2

Thoạt nhìn, nó sẽ giống với các ngôn ngữ khác (dưới "khác", tôi có nghĩa là Java hoặc C ++), nhưng không phải vậy.

Trong Java, bạn đã đặt riêng tư cho tất cả các biến mà bên ngoài không thể truy cập được. Trong cùng một thời điểm với Python, bạn không thể đạt được điều này vì không có "tính riêng tư" (như một trong những nguyên tắc Python nói - "Chúng ta đều là người lớn"). Vì vậy, dấu gạch dưới kép chỉ có nghĩa là "Các bạn, không sử dụng trường này trực tiếp". Ý nghĩa tương tự có dấu gạch dưới đơn, đồng thời không gây ra bất kỳ đau đầu nào khi bạn phải kế thừa từ lớp được xem xét (chỉ là một ví dụ về vấn đề có thể xảy ra do dấu gạch dưới kép).

Vì vậy, tôi khuyên bạn nên sử dụng một dấu gạch dưới theo mặc định cho các thành viên "riêng tư".


Sử dụng dấu gạch dưới kép cho "riêng tư" và dấu gạch dưới đơn cho "được bảo vệ". Thông thường, mọi người chỉ sử dụng dấu gạch dưới đơn cho mọi thứ (dấu gạch dưới kép sẽ giúp thực thi quyền riêng tư, điều này thường chống lại kiểu Python).
Jonathan Sternberg

1
Nhưng điều đó không làm cho hai dấu gạch dưới tương tự như private và một dấu gạch dưới tương tự như được bảo vệ? Tại sao không chỉ bắt đầu từ "riêng tư"?
Paul Manta

@Paul Không, nó không. Không có private trong Python và bạn không nên cố gắng đạt được nó.
Roman Bodnarchuk

@Roman Nói một cách khái niệm ... Hãy để ý những câu trích dẫn xung quanh 'private'.
Paul Manta

1

"Nếu nghi ngờ về việc liệu một biến có nên là riêng tư hay được bảo vệ hay không, tốt hơn là nên chọn chế độ riêng tư." - vâng, tương tự trong Python.

Một số câu trả lời ở đây nói về 'quy ước', nhưng không cung cấp liên kết đến những quy ước đó. Hướng dẫn có thẩm quyền cho Python, PEP 8 nêu rõ ràng:

Nếu nghi ngờ, hãy chọn không công khai; sau này đặt thuộc tính công khai sẽ dễ dàng hơn là công khai thuộc tính không công khai.

Sự phân biệt giữa công khai và riêng tư, cũng như thay đổi tên trong Python đã được xem xét trong các câu trả lời khác. Từ cùng một liên kết,

Chúng tôi không sử dụng thuật ngữ "riêng tư" ở đây, vì không có thuộc tính nào thực sự là riêng tư trong Python (không có số lượng công việc thường không cần thiết).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.