2010-09-14 24 views
9

Tôi muốn kiểm soát các biến toàn cục (hoặc biến toàn cầu) theo cách chúng được thiết lập chỉ một lần trong mã khởi tạo chương trình và khóa chúng sau đó.Tôi có thể ngăn không cho sửa đổi một đối tượng bằng Python không?

Tôi sử dụng UPPER_CASE_VARIABLES cho các biến toàn cầu, nhưng tôi muốn có một cách chắc chắn không thay đổi biến.

  • Python có cung cấp tính năng (hoặc tương tự) không?
  • Làm cách nào để bạn kiểm soát các biến phạm vi toàn cầu?
+4

Tại sao các bạn dành thời gian về vấn đề này? Mọi người có nguồn Python của bạn. Họ chỉ có thể thay đổi nó. Tại sao lộn xộn xung quanh với "cuối cùng" và "liên tục"? –

+1

Bạn biết đấy, đó là mục đích. Các chàng trai Python có ý kiến, rằng chúng ta đều là người lớn và nên hành động như những người thân. Vậy tại sao lại cấm truy cập? Hành động như một người lớn và không bao giờ thay đổi chúng trong mã của bạn. Nếu một lập trình viên khác làm, đó là lỗi của anh ta, nếu mã bị phá vỡ, và bạn có một VCS để tìm ra ai để đổ lỗi (tôi giả định). – Boldewyn

+1

Hơn nữa, đó là một điều dễ dàng để kiểm toán. Bất kỳ trường hợp nào của 'UPPER_CASE =' là một lỗi vì ai đó đã phá vỡ các quy tắc. –

Trả lời

11

ActiveState có một công thức mang tên Constants in Python bởi đáng kính Alex Martelli để tạo một module const với các thuộc tính mà không thể được phục hồi sau khi tạo. Điều đó nghe có vẻ giống như những gì bạn đang tìm kiếm ngoại trừ việc tăng lên — nhưng điều đó có thể được thêm bằng cách làm cho nó kiểm tra xem liệu tên thuộc tính có phải là chữ hoa hay không.

Tất nhiên, điều này có thể bị phá vỡ bởi xác định, nhưng đó là cách Python là — và được coi là "điều tốt" của hầu hết mọi người. Tuy nhiên, để làm cho nó khó khăn hơn một chút, tôi khuyên bạn không nên thêm phương thức __delattr__ được cho là rõ ràng vì mọi người có thể chỉ xóa tên và sau đó thêm chúng trở lại các giá trị khác nhau.

Đây là những gì tôi đang tham gia về:

# Put in const.py... 
# from http://code.activestate.com/recipes/65207-constants-in-python 
class _const: 
    class ConstError(TypeError): pass # base exception class 
    class ConstCaseError(ConstError): pass 

    def __setattr__(self, name, value): 
     if name in self.__dict__: 
      raise self.ConstError("Can't change const.%s" % name) 
     if not name.isupper(): 
      raise self.ConstCaseError('const name %r is not all uppercase' % name) 
     self.__dict__[name] = value 

# replace module entry in sys.modules[__name__] with instance of _const 
# (and create additional reference to module so it's not deleted -- 
# see Stack Overflow question: http://bit.ly/ff94g6) 
import sys 
_ref, sys.modules[__name__] = sys.modules[__name__], _const() 

if __name__ == '__main__': 
    import const # test this module... 

    try: 
     const.Answer = 42 # not OK, mixed-case attribute name 
    except const.ConstCaseError as exc: 
     print(exc) 
    else: # test failed - no ConstCaseError exception generated 
     raise RuntimeError("Mixed-case const names should't have been allowed!") 

    const.ANSWER = 42 # should be OK, all uppercase 

    try: 
     const.ANSWER = 17 # not OK, attempts to change defined constant 
    except const.ConstError as exc: 
     print(exc) 
    else: # test failed - no ConstError exception generated 
     raise RuntimeError("Shouldn't have been able to change const attribute!") 

Output:

const name 'Answer' is not all uppercase 
Can't change const.ANSWER 
+0

Chỉ cần một nhận xét: Nếu bạn nhập một "hằng số" như vậy vào không gian tên cục bộ, nó không còn "liên tục" nữa. Tên địa phương có thể dễ dàng được phục hồi. Và sau khi tất cả, các đối tượng mô-đun luôn có thể được phục hồi. – lunaryorn

+0

@lunaryorn: Khá đúng. Công thức cũng xuất hiện trong "Python Cookbook, 2d ed" và có Martelli đề cập đến thực tế là giá trị bị ràng buộc vẫn có thể được thay đổi nếu nó có thể thay đổi, chẳng hạn như danh sách. Để ngăn chặn điều đó, anh đề cập đến một công thức khác trong cuốn sách cho phép người ta quấn các đối tượng có thể thay đổi và biến chúng thành chỉ đọc. Công thức khác này có tiêu đề "Ủy nhiệm tự động như là một thay thế cho thừa kế" và có rất nhiều tài liệu trong phần Thảo luận của nó - nhiều hơn tôi cảm thấy thích hợp để đưa vào câu trả lời của tôi - vì vậy tôi đã không đến đó ... – martineau

+0

'đối tượng .__ setattr __ (const, 'this_is_not_a_costant', 88)' .sẽ làm việc để đặt hằng số không hợp lệ hoặc xác định lại hằng số. Một thủ thuật tương tự cũng có sẵn bằng cách sử dụng '__class__' sửa đổi, có thể được thực hiện mà không sử dụng' object '__ setattr__' ('class o (object): pass' theo sau là' object .__ dict __ ['__ class __'] .__ set __ (const, o)), sau đó người ta có thể thiết lập các thuộc tính như một lớp bình thường. – ppperry

2

Bạn có thể quấn các biến toàn cục của mình vào đối tượng và ghi đè đối tượng .__ setattr__. Sau đó bạn có thể ngăn chặn các thuộc tính thiết lập đã được thiết lập. Tuy nhiên, điều này không đối phó với các đối tượng phức tạp được truyền qua tham chiếu. Bạn sẽ cần phải tạo các bản sao nông/sâu của các đối tượng đó để chắc chắn rằng chúng không thể sửa đổi được. Nếu bạn đang sử dụng các lớp phong cách mới, bạn có thể ghi đè lên đối tượng .__ getattribute __ (tự, tên) để tạo các bản sao.

class State(object): 
    def __init__(self): 
     pass 

    def __setattr__(self, name, value): 
     if name not in self.__dict__: 
      self.__dict__[name] = value 

** Tôi thường không lo lắng quá nhiều nếu có ai đó cố gắng thực sự phá vỡ mã của tôi. Tôi thấy trọng số __setattr__ là đủ (đặc biệt là nếu bạn ném một ngoại lệ) để cảnh báo bất cứ ai đang chơi với mã mà mục tiêu cho Nhà nước là chỉ đọc. Nếu ai đó vẫn cảm thấy cần phải sửa đổi trạng thái thì bất cứ hành vi không xác định nào họ gặp đều không phải lỗi của tôi.

+1

Và điều gì sẽ ngăn ai đó ghi đè lên đối tượng? – mikerobi

+0

Điểm tốt: P. Tôi cho rằng không có nhiều thứ có thể làm được? Có lẽ một singleton? – GWW

+4

Mỗi lần ai đó cố gắng thi đua các hằng số, các thành viên riêng, kiểm tra kiểu đề cử, vv ... bằng Python (hoặc các ngôn ngữ động khác), anh ta thất bại. Khi nào mọi người sẽ học? (Một lớp đơn có thể được định nghĩa lại dễ dàng) – delnan

6

Python là ngôn ngữ rất mở và không chứa từ khóa final. Python mang lại cho bạn nhiều sự tự do hơn để làm việc và cho rằng bạn biết mọi thứ sẽ hoạt động như thế nào. Do đó, giả định rằng những người sử dụng mã của bạn sẽ biết rằng không nên gán giá trị SOME_CONSTANT tại một số điểm ngẫu nhiên trong mã.

Nếu bạn thực sự muốn, bạn có thể kèm theo hằng số bên trong hàm getter.

def getConstant() 
    return "SOME_VALUE" 
+5

Nó vẫn còn có thể (và chỉ hơi phức tạp hơn) để làm 'getConstant = lambda: new_value'. Và vì 'ALL_CAPS' là quy ước cho các hằng số nên, bạn chỉ nên dính vào đó. – delnan

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