2012-01-26 53 views
8

Tôi biết rằng các thuộc tính của lớp được khai báo bằng dấu gạch dưới kép tiền tố __ có thể hoặc không thể nhìn thấy bên ngoài định nghĩa lớp. Vì chúng tôi vẫn có thể truy cập các thuộc tính đó theo object._className__attrName.Ẩn dữ liệu trong lớp Python

class A: 
    def __init__(self): 
     self.a = 1 
     self.b = 2 
     ---- 
     ---- 
     self.z = 26 
     self.catch = 100 

Bây giờ để bảo vệ tất cả các thuộc tính ngoại trừ thuộc tính catch, tôi phải khai báo chúng với dấu gạch dưới kép khá lộn xộn. Có cách nào tôi có thể nói trong định nghĩa lớp học của tôi rằng chỉ có thể truy cập self.catch bên ngoài lớp học?

Xin lỗi nếu điều này được trả lời ở nơi khác hoặc được thảo luận trước đó.

+1

No. Tuy nhiên, trừ khi bạn thực sự hoang tưởng, thực tế là ai đó * có thể * truy cập một đối tượng bằng cách sử dụng 'object._className__attrName' không phải là một vấn đề lớn. Bạn thực sự chỉ muốn ngăn mọi người vô tình truy cập vào các biến mà họ không nên khi sử dụng mã của bạn. Các obfuscation đạt được mục tiêu đó. – Chris

+2

có thể trùng lặp của [Có python có 'tư nhân' biến trong các lớp học?] (Http://stackoverflow.com/questions/1641219/does-python-have-private-variables-in-classes) –

+0

@ BjörnPollex, đây isn ' những gì anh ta yêu cầu. Anh ta muốn sự cần thiết của một nhà điều hành "công khai" rõ ràng, không phải ngược lại. –

Trả lời

16

Vâng, nó có thể che giấu dữ liệu cá nhân trong một đóng cửa - ít nhất, nếu có một cách để truy cập từ bên ngoài privatemake_A, tôi đã không tìm thấy nó:

def make_A(): 
    private = { 
     'a' : 1, 
     'b' : 2, 
     'z' : 26, 
     } 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private['a'] = 2 # you can modify the private data 
     def foo(self): 
      print(private['a']) # you can access the private data 
    return A 

A = make_A() 

a=A() 

a.foo() 
# 2 

ý rằng private không có trong số dir(a)

print('private' in dir(a)) 
# False 

Mặc dù điều này là có thể, tôi không nghĩ đây là cách được khuyến nghị để lập trình bằng Python.


Trên, private được chia sẻ bởi tất cả các trường hợp A. Để sử dụng dữ liệu cá nhân trên cơ sở mỗi sơ thẩm, thêm self đến khóa dict:

def make_A(): 
    private = {} 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private[self,'a'] = 1 # you can modify the private data 
      private[self,'b'] = 2  
      private[self,'z'] = 26  
     def foo(self): 
      print(private[self,'a']) # you can access the private data 
    return A 
+2

+1 để ẩn dữ liệu kiểu đóng. – 9000

+0

Thumbs up for *** closures **. Điều này có thể quan tâm: [Biến bí mật i Python] (http://www.jotflow.com/jot/Secret-Variables-In-Python/5). Nó so sánh ẩn dữ liệu chức năng trong Python với các biến riêng trong Java. –

1

Không, vì đó là một phần của tên, bạn không thể làm điều đó.

Vâng, thực sự bạn có thể thông qua hack với getters/setters, nhưng bạn thường không nên.

1

Tại sao bạn có thể muốn bảo vệ thuộc tính?

Nếu bạn muốn bảo vệ các thuộc tính khỏi ghi đè vô tình, hãy sử dụng dấu gạch dưới kép và, có thể, thuộc tính chỉ sẵn sàng để truy cập dễ dàng hơn. Nhưng hầu hết thời gian, you aint't gonna need it. Chỉ cần làm cho bạn một ưu và để lại các thuộc tính mở, điều này làm cho gỡ lỗi dễ dàng hơn nhiều.

Nếu bạn muốn bảo vệ đối tượng của bạn từ giả mạo do các bên thứ ba, bạn có thể chơi với __getattr____setattr__, nhưng có lẽ bạn không nên vượt qua một ứng dụng không tin cậy các đối tượng với các dữ liệu được bảo vệ ở tất cả, sử dụng facade pattern thay vào đó và giấu vật có giá trị của bạn thêm opaquely. Bạn cũng có thể muốn suy nghĩ lại kiến ​​trúc của mình.

+1

* Tại sao bạn có thể muốn bảo vệ các thuộc tính? * Tôi chỉ có thể chỉ cho bạn mục nhập wiki về đóng gói, nhưng tôi sẽ cung cấp cho bạn một ví dụ thực tế. Giả sử bạn có một ứng dụng python lớn và phức tạp, trong đó bạn có một số lớp với thuộc tính 'name'. Lỗi được tìm thấy trong đó tên của quản trị viên lớp đang bị ghi đè không chính xác. Nếu bạn đã để lại thuộc tính tên mở như bạn đề xuất, bạn sẽ tìm thấy dòng mã vi phạm như thế nào? Nếu bạn đã ẩn thuộc tính và sử dụng accessors, bạn có thể đặt một breakpoint trên getter và tìm thủ phạm nhanh. – dar512

+0

@ dar512: nếu lớp học của bạn là một phần của giao diện công khai và khách hàng có thể giả mạo các thuộc tính, bằng mọi cách, hãy bảo vệ họ bằng những người truy cập! Tuy nhiên, số lượng các lớp công khai khá hạn chế trong một ứng dụng điển hình. Ngoài ra, sử dụng dữ liệu bất biến có nhiều lợi thế; Tôi thường sử dụng các lớp con của 'namedtuple' để biểu diễn dữ liệu theo cách chống đạn. – 9000

+0

Là một lập trình viên, nếu tôi đã chọn để bắn ra chân của riêng tôi với một khẩu súng ngắn, do đó, được nó. Bạn đang hạn chế khả năng sửa chữa/thay đổi mã của bạn bằng cách ẩn mọi thứ. Các từ khóa 'được bảo vệ' và 'riêng tư' chỉ là chống mẫu. Xin vui lòng từ bỏ quan niệm rằng bạn đang làm bất cứ ai một ưu tiên bằng cách 'ẩn' những thứ từ các lập trình viên khác. Nếu bạn muốn làm một cái gì đó như thế này, sử dụng '_variable' và cung cấp một' biến' getter tài sản và không có setter. Tôi vẫn có thể tự sửa đổi '_variable' theo cách này nếu tôi muốn. Nhưng không sử dụng ngôn ngữ hacks để obfuscate internals của bạn từ các lập trình viên khác. – Rebs

3

Trong khi câu trả lời chấp nhận bởi unutbu trông giống như một ý tưởng tốt để ẩn dữ liệu, các private điển vẫn truy cập sử dụng __closure__ (thuộc tính này không thể được gỡ bỏ):

def make_A(): 
    private = {} 
    class A: 
     def __init__(self): 
      self.catch = 100 
      private[self,'a'] = 1 # you can modify the private data 
      private[self,'b'] = 2  
      private[self,'z'] = 26  
     def foo(self): 
      print(private[self,'a']) # you can access the private data 
    return A 


A = make_A() 
a = A() 
a.foo() # 1 
a.foo.__closure__[0].cell_contents[(a, 'a')] = 42 
a.foo() # 42 

Hoặc theo liên kết được cung cấp bởi Sumukh Barve trong nhận xét:

def createBankAccount(): 
    private = {'balance': 0.0} 
    def incr(delta): 
     private['balance'] += delta; 
    account = { 
     'deposit': lambda amount: incr(amount), 
     'withdraw': lambda amount: incr(-amount), 
     'transferTo': lambda otherAccount, amount: (
      account['withdraw'](amount), 
      otherAccount['deposit'](amount) 
     ), 
     'transferFrom': lambda otherAccount, amount: (
      otherAccount['transferTo'](account, amount) 
     ), 
     'getBalance': lambda : private['balance'] 
    } 
    return account; 


account = createBankAccount() 

print(account['getBalance']()) 
account['getBalance'].__closure__[0].cell_contents['balance'] = 1000**1000 
print(account['getBalance']()) # I can buy a couple of nations 

tôi bevile cách duy nhất để tạo private thuộc tính được viết một số k số máy lẻ trong số CPython.

+0

cảm ơn vì điều đó –

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