2009-04-14 8 views
7

Tôi đang gặp sự cố khi triển khai borg trong python. Tôi tìm thấy một ví dụ trong một câu trả lời cho this question nhưng nó không làm việc cho tôi, trừ khi tôi đang thiếu một cái gì đó. Đây là mã:Vấn đề mẫu borg Python


class Config: 
    """ 
    Borg singleton config object 
    """ 
    __we_are_one = {} 
    __myvalue = "" 

    def __init__(self): 
     #implement the borg pattern (we are one) 
     self.__dict__ = self.__we_are_one 
     self.__myvalue = "" 

    def myvalue(self, value=None): 
     if value: 
      self.__myvalue = value 
     return self.__myvalue 

conf = Config() 
conf.myvalue("Hello") 
conf2 = Config() 
print conf2.myvalue() 

Tôi cho rằng điều này có nghĩa là in "Hello", nhưng đối với tôi, nó chỉ in một dòng trống. Vài ý tưởng tại sao nó như thế?

+1

Tại sao bạn sử dụng tên __ gấp đôi cho thuộc tính của mình? Một đơn hàng đầu _ sẽ làm để làm cho nó "riêng tư". –

+0

Tôi đã sao chép mã từ câu hỏi khác mà tôi đã liên kết đến. Nhưng dù sao, tôi nghĩ rằng một _ đơn gợi ý rằng nó là riêng tư, trong khi một _ đôi gây ra tên mangling mà là một gợi ý mạnh mẽ hơn rằng nó * thực sự * là riêng tư, mặc dù nó vẫn có thể được truy cập nếu người dùng được xác định. – chrism1

+2

Không! Các dấu gạch dưới hàng đầu sẽ KHÔNG làm cho chúng riêng tư, chỉ làm cho nó sao cho các biến cấp mô-đun không được nhập vào 'từ foo import *' Nếu không, nó không có tác dụng khác với 'gợi ý' ở tính riêng tư. –

Trả lời

13

Dường như nó làm việc chứ không phải quá tốt :-)

Vấn đề là sự phân công self.__myvalue = "" trong __init__ sẽ luôn clobber giá trị của myvalue mỗi khi một Borg mới là, er, tạo ra. Bạn có thể thấy điều này nếu bạn thêm một số câu lệnh in bổ sung vào thử nghiệm của mình:

conf = Config() 
conf.myvalue("Hello") 
print conf.myvalue() # prints Hello 
conf2 = Config() 
print conf.myvalue() # prints nothing 
print conf2.myvalue() # prints nothing 

Xóa self.__myvalue và mọi thứ sẽ ổn.

Có nói rằng, việc thực hiện myvalue() là một chút lạ. Tốt hơn, tôi muốn nói, để có getters rõ ràng và setters sử dụng tài sản. Bạn cũng sẽ muốn có một số mã trong số __init__ để khởi tạo giá trị myvalue nếu chưa tồn tại hoặc ít nhất là xử lý rằng mã đó có thể không tồn tại trong bộ nạp. Có lẽ cái gì đó như:

class Config(object): 
    """ 
    Borg singleton config object 
    """ 
    _we_are_one = {} 

    def __init__(self): 
     #implement the borg pattern (we are one) 
     self.__dict__ = self._we_are_one 

    def set_myvalue(self, val): 
     self._myvalue = val 

    def get_myvalue(self): 
     return getattr(self, '_myvalue', None) 

    myvalue = property(get_myvalue, set_myvalue) 

c = Config() 
print c.myvalue # prints None 
c.myvalue = 5 
print c.myvalue # prints 5 
c2 = Config() 
print c2.myvalue #prints 5 
+0

Ha! Khá rõ ràng thực sự, nên đã phát hiện ra nó. Cảm ơn tất cả các mẹo. – chrism1

+0

Tôi nghĩ rằng việc triển khai Borg này không hoạt động với các lớp kiểu mới. Tui bỏ lỡ điều gì vậy? – legesh

+0

@legesh Dường như nó hoạt động tốt trong Python 2.6. Có lẽ tôi đang thiếu một cái gì đó ... những gì thông tin hoặc kinh nghiệm cung cấp cho bạn tạm dừng với các lớp học theo phong cách mới? –

1

Sự cố có vẻ là init() đang đặt lại giá trị của tôi thành chuỗi rỗng. Khi tôi loại bỏ dòng đó tôi nhận được kết quả mong đợi.

4

Kết hợp việc loại bỏ các self.__myvalue = "" với new-style Borg và những gợi ý để tránh __ trong tên biến, chúng tôi nhận được:

class Config(object): 
    """ 
    Borg singleton config object 
    """ 
    _we_are_one = {} 
    _myvalue = "" 

    def __new__(cls, *p, **k): 
     self = object.__new__(cls, *p, **k) 
     self.__dict__ = cls._we_are_one 
     return self 

    def myvalue(self, value=None): 
     if value: 
      self._myvalue = value 
     return self._myvalue 

if __name__ == '__main__': 
    conf = Config() 
    conf.myvalue("Hello") 
    conf2 = Config() 
    print conf2.myvalue() 
1
class Borg(object): 
    """Demonstrating the Borg-pattern: All the instances of a class already 
    know what one of them learned... Scary, isn't it?""" 

    def __init__(self, name): 
     self.name = name 

    @classmethod 
    def borg_knowledge(cls, who_is_it): 
     if hasattr(cls, "b_knowledge"): 
      return "%s: I already know that the borg pattern is awesome!" % who_is_it 
     else: 
      cls.b_knowledge = True 
      return "%s: Learning about the borg pattern..." % who_is_it 

    def personal_experience(self): 
     if hasattr(self, "p_knowledge"): 
      return "%s: I already know that!" % self.name 
     else: 
      self.p_knowledge = True 
      return "%s: Learning something..." % self.name 


b1 = Borg("b1") 
b2 = Borg("b2") 
print ">> Created b1 and b2, both Borg"; print 

print ">> Usual class behavior. One instance does not know what the other does." 
print b1.personal_experience() 
print b2.personal_experience() 

print 
print ">> Borg have a shared knowledge a.k.a. why classmethods are different!" 
print b1.borg_knowledge(b1.name) 
print b2.borg_knowledge(b2.name) 
0
> The problem appears to be that init() is resetting myvalue to an 
> empty string. When You remove that 
> line ('self.__myvalue = ""') then you will get the expected 
> output. 
0

tôi đã cố gắng thực hiện điều này bằng cách sử "kiểu cũ" cũng như "kiểu mới" và tôi không thể thấy sự khác biệt giữa chúng. Có lợi thế nào so với cái kia không? Hoặc về cơ bản là tương đương?

class Borg(object): 
    shared_state = {'a_value': True} 
    def __init__(self): 
     self.__dict__ = self.shared_state 


class NewBorg(object): 
    shared_state = {'a_value': True} 

    def __new__(cls, *p, **k): 
     self = object.__new__(cls, *p, **k) 
     self.__dict__ = cls.shared_state 
     return self 


borg_a = Borg() 
borg_b = Borg() 

print id(borg_a), '!=', id(borg_b) 
assert borg_a.shared_state == borg_b.shared_state 
borg_a.shared_state['a_value'] = False 
assert borg_a.shared_state == borg_b.shared_state 

new_borg_a = NewBorg() 
new_borg_b = NewBorg() 

print id(new_borg_a), '!=', id(new_borg_b) 
assert new_borg_a.shared_state == new_borg_b.shared_state 
new_borg_a.shared_state['a_value'] = False 
assert new_borg_a.shared_state == new_borg_b.shared_state