2014-05-02 22 views
7

Tôi tương đối mới đối với Python vì vậy tôi hy vọng tôi không bỏ lỡ điều gì đó, nhưng ở đây ...Thuộc tính thuộc tính "Riêng tư" trong Python

Tôi đang cố gắng viết mô-đun Python và tôi ' d muốn tạo một lớp với thuộc tính "riêng tư" có thể (hoặc có thể 'nên') chỉ được sửa đổi thông qua một hoặc nhiều hàm trong mô-đun. Đây là một nỗ lực để làm cho mô-đun mạnh mẽ hơn, vì việc thiết lập thuộc tính này bên ngoài các chức năng này có thể dẫn đến hành vi không mong muốn. Ví dụ, tôi có thể có:

  1. Một lớp học mà các cửa hàng giá trị x và y cho một âm mưu phân tán, Data
  2. Một chức năng để đọc giá trị x và y từ một tập tin và lưu trữ chúng trong lớp, read()
  3. Một chức năng để mưu họ, plot()

Trong trường hợp này, tôi sẽ thích nếu người dùng đã không thể làm điều gì đó như thế này:

data = Data() 
read("file.csv", data) 
data.x = [0, 3, 2, 6, 1] 
plot(data) 

Tôi nhận thấy rằng việc thêm một dấu gạch dưới hàng đầu vào tên cho biết người dùng không được thay đổi thuộc tính, tức là đổi tên thành _x và thêm trình trang trí thuộc tính để người dùng có thể truy cập giá trị mà không cảm thấy có lỗi. Tuy nhiên, những gì nếu tôi muốn thêm một tài sản setter cũng như:

class Data(object): 
    _x = [] 
    _y = [] 
    @property 
    def x(self): 
     return self._x 
    @x.setter 
    def x(self, value): 
     # Do something with value 
     self._x = value 

Tôi bây giờ ở vị trí giống như tôi trước kia - người dùng có thể không còn trực tiếp truy cập vào thuộc tính _x, nhưng họ vẫn có thể thiết lập nó sử dụng:

data.x = [0, 3, 2, 6, 1] 

Lý tưởng nhất là tôi muốn đổi tên các định nghĩa chức năng tài sản để _x(), nhưng điều này dẫn đến sự nhầm lẫn về những gì thực sự có nghĩa self._x (tùy thuộc vào thứ tự mà chúng được khai báo, điều này dường như dẫn đến một trong hai setter được gọi là đệ quy hoặc setter bị bỏ qua ủng hộ thuộc tính).

Một vài giải pháp tôi có thể nghĩ:

  1. Thêm một lãnh đạo đôi nhấn vào thuộc tính, __x, do đó tên trở nên nham nhở và không bị lẫn lộn với chức năng setter. Theo tôi hiểu nó, điều này nên được dành riêng cho các thuộc tính mà một lớp không muốn chia sẻ với các lớp con có thể, vì vậy tôi không chắc chắn nếu đây là một sử dụng hợp pháp.
  2. Đổi tên thuộc tính, ví dụ: _x_stored. Trong khi điều này giải quyết hoàn toàn vấn đề, nó làm cho mã khó đọc hơn và giới thiệu các vấn đề quy ước đặt tên - thuộc tính nào tôi đổi tên? chỉ những cái có liên quan? chỉ là những người có tài sản? chỉ là những người trong lớp học này?

Một trong các giải pháp trên có được áp dụng không? Và nếu không, có cách nào tốt hơn để giải quyết vấn đề này không?

Sửa

Cám ơn các câu trả lời cho đến nay.Một vài điểm được ném ra bởi các ý kiến:

  1. Tôi muốn giữ lại logic thêm rằng các tài sản setter mang lại cho tôi - những # Do something with value phần trong ví dụ trên - vì vậy trong nội bộ thiết lập các thuộc tính thông qua tiếp cận trực tiếp của self._x không giải quyết vấn đề.
  2. Xóa thuộc tính setter và tạo một hàm riêng biệt _set_x() giải quyết vấn đề, nhưng không phải là giải pháp rất gọn gàng vì nó cho phép thiết lập _x theo hai cách khác nhau - bằng cách gọi hàm đó hoặc truy cập trực tiếp self._x. Sau đó tôi phải theo dõi các thuộc tính nào nên được thiết lập bởi hàm setter (không thuộc tính) của riêng chúng và cần được sửa đổi thông qua truy cập trực tiếp. Tôi có lẽ sẽ sử dụng một trong những giải pháp mà tôi đã đề xuất ở trên, bởi vì mặc dù chúng tạo ra một mớ hỗn độn của các quy ước đặt tên trong lớp chúng ít nhất là nhất quán trong việc sử dụng chúng bên ngoài lớp, tức là tất cả chúng đều sử dụng đường cú pháp của các thuộc tính . Nếu không có cách nào để làm điều này một cách neater sau đó tôi đoán tôi chỉ cần chọn một trong đó gây ra sự gián đoạn ít nhất.
+0

tôi c onfused về lý do tại sao bạn muốn xác định một setter mà bạn không muốn mọi người sử dụng. – cmd

+0

@cmd - Tôi vẫn muốn có thể sử dụng trình thiết lập trong các chức năng khác trong mô-đun. Ví dụ, tôi có thể có một hàm 'nội suy()' cần để có thể thiết lập các giá trị x và y. – sftd

+0

Nhưng những người đó chỉ có thể đặt '_x' và' _y'. – kindall

Trả lời

3

Nếu bạn muốn ngăn cản người dùng thay đổi một tài sản, nhưng muốn nó được rõ ràng rằng họ có thể đọc nó, tôi muốn sử dụng @property mà không cung cấp một setter, tương tự như những gì bạn mô tả ở trên:

class Data(object): 
    def __init__(self): 
     self._x = [] 
     self._y = [] 

    @property 
    def x(self): 
     return self._x 

    @property 
    def y(self): 
     return self._x 

Tôi biết bạn đề cập đến "Điều gì xảy ra nếu tôi muốn thêm người đặt vào thuộc tính?", Nhưng tôi đoán tôi sẽ phản đối điều đó với: Tại sao phải thêm người đặt nếu bạn không muốn khách hàng của mình có thể đặt thuộc tính ? Bên trong, bạn có thể truy cập trực tiếp self._x.

Đối với khách hàng truy cập trực tiếp _x hoặc _y, bất kỳ biến nào có tiền tố '_' được hiểu là "riêng tư" bằng Python, vì vậy bạn nên tin tưởng khách hàng của mình tuân theo điều đó. Nếu họ không tuân theo điều đó, và cuối cùng vặn vẹo mọi thứ, đó là lỗi của chính họ. Kiểu tư duy này là đối với nhiều ngôn ngữ khác (C++, Java, v.v.), nơi giữ cho dữ liệu riêng tư được coi là rất quan trọng, nhưng văn hóa của Python chỉ khác nhau về mặt này.

Sửa

Một lưu ý khác, vì tính chất cá nhân của bạn trong trường hợp đặc biệt này là danh sách, đó là có thể thay đổi (không giống như chuỗi hoặc ints, mà là không thay đổi), một khách hàng có thể sẽ thay đổi chúng một chút vô tình:

>>> d = Data() 
>>> print d.x 
['1', '2'] 
>>> l = d.x 
>>> print l 
['1', '2'] 
>>> l.append("3") 
>>> print d.x 
['1', '2', '3'] # Oops! 

Nếu bạn muốn tránh điều này, bạn cần phải sở hữu của bạn để trả về một bản sao của danh sách:

@property 
def x(self): 
    return list(self._x) 
+0

Tôi hiểu rằng việc đặt giá trị bằng cách sử dụng truy cập trực tiếp 'self._x' thật dễ dàng, nhưng điều đó sẽ loại bỏ lợi thế mà việc đặt setter cho tôi, tức là bit' # Do something with value'. – sftd

+0

Ah, bạn có nghĩa là có setter làm nhiều hơn một 'self._x = blah' đơn giản?Tôi đoán trong trường hợp đó, bạn phải thêm @property vào tài sản cá nhân (mà tôi nghĩ bạn đã đề cập bạn không thích), hoặc luôn luôn nhớ gọi một số hàm trợ giúp nội bộ khi bạn muốn gán cho riêng tư bất động sản. – dano

+0

Có cách nào thanh lịch hơn để thực hiện điều này không đưa ra quy ước đặt tên không phù hợp? Vui lòng xem chỉnh sửa bài đăng gốc. (@cmd, @kindall) – sftd

Các vấn đề liên quan