Xác định các chức năng mô-đun riêng trong python


238

Theo http://www.faqs.org/docs/diveintopython/fileinfo_private.html :

Giống như hầu hết các ngôn ngữ, Python có khái niệm về các yếu tố riêng tư:

  • Các hàm riêng, không thể được gọi từ bên ngoài mô-đun của chúng

Tuy nhiên, nếu tôi xác định hai tệp:

#a.py
__num=1

và:

#b.py
import a
print a.__num

Khi tôi chạy b.pynó in ra 1mà không đưa ra bất kỳ ngoại lệ. Là diveintopython sai, hoặc tôi đã hiểu sai một cái gì đó? Và có một số cách để làm xác định chức năng của một mô-đun như tư nhân?


Không phải diveintopython là sai, nhưng trong ví dụ của họ: >>> import fileinfo >>> m = fileinfo.MP3FileInfo() >>> m.__parse("/music/_singles/kairo.mp3") 1 Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'MP3FileInfo' instance has no attribute '__parse' fileinfo.MP3FileInfo () là một thể hiện của lớp. Điều này đưa ra ngoại lệ này khi bạn sử dụng dấu gạch dưới kép. Trong trường hợp của bạn, bạn không tạo một lớp, bạn chỉ tạo một mô-đun. Xem thêm: stackoverflow.com/questions/70528/
Mạnh

Câu trả lời:


323

Trong Python, "quyền riêng tư" phụ thuộc vào mức độ thỏa thuận "đồng ý của người lớn" - bạn không thể ép buộc (nhiều hơn mức bạn có thể có trong cuộc sống thực ;-). Một dấu gạch dưới hàng đầu duy nhất có nghĩa là bạn không cần phải truy cập "từ bên ngoài" - hai dấu gạch dưới hàng đầu (w / o dấu gạch dưới) mang thông điệp thậm chí còn mạnh mẽ hơn ... nhưng, cuối cùng, nó vẫn phụ thuộc vào xã hội quy ước và đồng thuận: Sự hướng nội của Python đủ mạnh để bạn không thể còng tay mọi lập trình viên khác trên thế giới để tôn trọng mong muốn của bạn.

((Btw, mặc dù đó là một bí mật được giữ kín, rất giống với C ++: với hầu hết các trình biên dịch, một #define private publicdòng đơn giản trước khi nhập tệp #includecủa bạn .hlà tất cả để các lập trình viên khôn ngoan tạo ra băm "quyền riêng tư" của bạn ...! -) )


82
Lưu ý của bạn về C ++ là không chính xác. Bằng cách sử dụng #define private, bạn sẽ thay đổi mã được gửi đến trình biên dịch, đó là nơi diễn ra việc xáo trộn tên.
rhinoinrepose

14
Ngoài ra, việc xáo trộn C ++ là tối nghĩa, nhưng hầu như không bí mật. Bạn cũng có thể "hướng nội" một tệp nhị phân do C ++ tạo ra. Xin lỗi
Hợp đồng của giáo sư Falken vi phạm

47
Là một bản cập nhật cho @rhinoinrepose, nó không chỉ không chính xác, đó là hành vi không xác định theo tiêu chuẩn để xác định lại từ khóa với macro tiền xử lý.
Cory Kramer

3
@AlexMartelli Không static void foo()riêng tư như vậy. Nó ít nhất được ẩn cho trình liên kết và chức năng có thể được loại bỏ hoàn toàn bằng cách nội tuyến.
dùng877329

3
Trong cuộc sống thực, mọi người sẽ bị truy tố nếu họ vi phạm pháp luật
Lay González

288

Có thể có sự nhầm lẫn giữa tư nhân lớptư nhân mô-đun .

Một mô-đun riêng bắt đầu bằng một dấu gạch dưới
Như vậy một phần tử không được sao chép cùng khi sử dụng from <module_name> import *hình thức của lệnh nhập; tuy nhiên, nó được nhập nếu sử dụng import <moudule_name>cú pháp ( xem câu trả lời của Ben Wilhelm )
Chỉ cần xóa một dấu gạch dưới khỏi .__ num của ví dụ câu hỏi và nó sẽ không hiển thị trong các mô-đun nhập a.py bằng from a import *cú pháp.

Một lớp riêng bắt đầu bằng hai dấu gạch dưới (còn gọi là dunder tức là d-ouble under-points)
Một biến như vậy có tên "mangled" để bao gồm tên lớp, v.v.
Nó vẫn có thể được truy cập bên ngoài logic lớp, thông qua tên được đọc
Mặc dù tên xáo trộn có thể phục vụ như một thiết bị phòng ngừa nhẹ chống lại truy cập trái phép, mục đích chính của nó là để ngăn chặn các xung đột tên có thể xảy ra với các thành viên lớp của các lớp tổ tiên. Xem tài liệu tham khảo hài hước nhưng chính xác của Alex Martelli để đồng ý với người lớn khi anh mô tả quy ước được sử dụng liên quan đến các biến này.

>>> class Foo(object):
...    __bar = 99
...    def PrintBar(self):
...        print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar  #direct attempt no go
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar()  # the class itself of course can access it
99
>>> dir(Foo)    # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar  #and get to it by its mangled name !  (but I shouldn't!!!)
99
>>>

Vâng, TIL. Bất kỳ lý do tại sao họ không thực thi cấp mô-đun __private_function, mặc dù? Tôi chạy vào đây và gặp lỗi vì nó.
Santa

Cảm ơn bạn vì những lời tốt đẹp @Terrabits, nhưng tôi sẵn sàng đứng thứ hai sau Alex (đứng sau!) Trên tất cả mọi thứ 'Python'. Hơn nữa, câu trả lời của anh ta thường ngắn gọn và hài hước hơn trong khi vẫn giữ được mức độ ủy quyền cao nhờ Alex đóng góp nhiều cho ngôn ngữ và cộng đồng.
mjv

1
@mjv Đây là một lời giải thích hữu ích! Cảm ơn bạn! Tôi đã khá bối rối về hành vi này trong một thời gian. Tôi ước gì sự lựa chọn là đưa ra một loại lỗi nào đó ngoài AttributionError nếu bạn cố truy cập trực tiếp vào lớp riêng tư; có lẽ là "PrivateAccessError" hoặc thứ gì đó rõ ràng / hữu ích hơn. (Vì nhận được lỗi rằng nó không có thuộc tính không thực sự đúng).
HFBrown

82

Câu hỏi này không được trả lời đầy đủ, vì quyền riêng tư của mô-đun không hoàn toàn thông thường và vì việc sử dụng nhập có thể hoặc không thể nhận ra quyền riêng tư của mô-đun, tùy thuộc vào cách sử dụng.

Nếu bạn xác định tên riêng trong một mô-đun, những tên đó sẽ được nhập vào bất kỳ tập lệnh nào sử dụng cú pháp, 'nhập mô-đun tên '. Do đó, giả sử bạn đã xác định chính xác trong ví dụ của mình mô-đun riêng tư, _num, trong a.py, như vậy ..

#a.py
_num=1

.. bạn sẽ có thể truy cập nó trong b.py với ký hiệu tên mô-đun:

#b.py
import a
...
foo = a._num # 1

Để chỉ nhập những người không phải là tư nhân từ a.py, bạn phải sử dụng cú pháp từ :

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

Tuy nhiên, để rõ ràng, tốt hơn là nên rõ ràng khi nhập tên từ các mô-đun, thay vì nhập tất cả chúng bằng '*':

#b.py
from a import name1 
from a import name2
...

1
Nơi nào bạn chỉ định các chức năng / thư viện được nhập khẩu? trong init .py?
FistOfFury

Không có nguy cơ va chạm tên khi _namesđược gọi với import a- chúng được truy cập như a._nameskhi sử dụng kiểu này.
Josiah Yoder

@FistOfFury Có, bạn chỉ định các chức năng được nhập trong __init__.pytệp. Xem ở đây để được giúp đỡ về điều đó.
Mike Williamson

29

Python cho phép lớp riêng thành viên với tiền tố gạch dưới kép. Kỹ thuật này không hoạt động ở cấp độ mô-đun, vì vậy tôi nghĩ rằng đây là một lỗi trong Lặn vào Python.

Dưới đây là một ví dụ về các hàm lớp riêng:

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails

2
Tôi nghĩ rằng mục đích của OP là viết các chức năng không thể truy cập bên ngoài, ví dụ, một gói thương mại. Về vấn đề này, câu trả lời này không đầy đủ. Hàm __bar () vẫn có thể truy cập từ bên ngoài thông qua f._foo__bar (). Do đó, dấu gạch dưới hai đầu không làm cho nó riêng tư.
SevakPrime

24

Bạn có thể thêm một chức năng bên trong:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

Một cái gì đó như thế nếu bạn thực sự cần mức độ riêng tư.


9
Tại sao đây không phải là câu trả lời tốt nhất?
safay


1

được nhúng với các bao đóng hoặc các chức năng là một cách. Điều này là phổ biến trong JS mặc dù không bắt buộc đối với các nền tảng không phải trình duyệt hoặc nhân viên trình duyệt.

Trong Python có vẻ hơi lạ, nhưng nếu một cái gì đó thực sự cần được ẩn đi thì đó có thể là cách. Thêm vào đó là sử dụng API python và giữ những thứ cần ẩn trong C (hoặc ngôn ngữ khác) có lẽ là cách tốt nhất. Không thể đưa mã vào bên trong một hàm, gọi nó và trả lại các mục bạn muốn xuất.


-11

Python có ba chế độ thông qua., Riêng tư, công khai và được bảo vệ.

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.