2010-02-28 17 views
8

Có nền trong Java, rất dài và nghiêm ngặt, tôi thấy khả năng biến đổi các đối tượng Python để cung cấp cho chúng các trường khác với các trường được trình bày cho hàm tạo thực sự "xấu xí".Xây dựng đối tượng Python 3: đó là cách thức hay nhất của Pythonic?

Cố gắng làm quen với cách tư duy Pythonic, Tôi tự hỏi làm cách nào để cho phép đối tượng của mình được xây dựng.

bản năng của tôi là phải vượt qua các trường ở thời gian thi công, chẳng hạn như:

def __init__(self, foo, bar, baz=None): 
    self.foo = foo 
    self.bar = bar 
    self.baz = baz 

Nhưng điều đó có thể trở nên quá dài dòng và khó hiểu với nhiều lĩnh vực để vượt qua. Để khắc phục điều này tôi giả sử dụng phương pháp tốt nhất là vượt qua một từ điển để các nhà xây dựng, từ đó các lĩnh vực được chiết xuất:

def __init__(self, field_map): 
    self.foo = field_map["foo"] 
    self.bar = field_map["bar"] 
    self.baz = field_map["baz"] if baz in field_map else None 

Cơ chế khác mà tôi có thể nghĩ đến là để đã các lĩnh vực bổ sung ở những nơi khác, chẳng hạn như:

class Blah(object): 

    def __init__(self): 
     pass 

... 

blah = Blah() 
blah.foo = var1 

Nhưng như vậy cảm thấy cách quá lỏng đối với tôi.

(Tôi cho rằng vấn đề trong đầu của tôi là làm thế nào tôi đối phó với giao diện bằng Python ...)

Vì vậy, để nhắc lại câu hỏi: Làm thế nào tôi nên xây dựng đối tượng của tôi bằng Python? Có một quy ước được chấp nhận không?

+0

Thời gian xây dựng sẽ là khi '__new__' được gọi. Vào thời điểm '__init__' được gọi, cá thể đã tồn tại và đó là * thời gian khởi tạo *. – u0b34a0f6ae

+0

@ kaizer.se Chúc mừng về thuật ngữ. –

Trả lời

9

Mô tả đầu tiên của bạn rất phổ biến. Một số sử dụng

class Foo: 
    def __init__(self, foo, bar): 
     self.foo, self.bar = foo, bar 

tiếp cận thứ hai của bạn ngắn hơn là không phổ biến, nhưng một phiên bản tương tự là thế này:

class Thing: 
    def __init__(self, **kwargs): 
     self.something = kwargs['something'] 
     #.. 

cho phép tạo các đối tượng như

t = Thing(something=1) 

Điều này có thể được tiếp tục được sửa đổi thành

class Thing: 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

phép

t = Thing(a=1, b=2, c=3) 
print t.a, t.b, t.C# prints 1, 2, 3 

Như Debilski chỉ ra trong các ý kiến, phương pháp cuối cùng là một chút không an toàn, bạn có thể thêm một danh sách các thông số được chấp nhận như thế này:

class Thing: 
    keywords = 'foo', 'bar', 'snafu', 'fnord' 
    def __init__(self, **kwargs): 
     for kw in self.keywords: 
      setattr(self, kw, kwargs[kw]) 

Có rất nhiều biến thể, có không có tiêu chuẩn chung mà tôi biết.

+1

Cẩn thận: Nếu bạn cập nhật một cách mù quáng bản thân 'self .__ dict__', mọi người có thể ghi đè lên tất cả các phương thức và biến thể hiện của bạn. – Debilski

+0

@Debilski: bạn hoàn toàn có một điểm, vì nó rất dễ bị che khuất các thuộc tính hiện tại do nhầm lẫn, nhưng tôi cũng muốn lưu ý rằng trong Python bất cứ ai cũng có thể ghi đè lên các phương thức và biến của bạn, nếu chúng muốn. – u0b34a0f6ae

+0

Trưng bày đẹp về các phương pháp khác nhau. –

3

Tôi chưa thấy nhiều trong số field_map giây của bạn trong cuộc sống thực. Tôi nghĩ rằng sẽ chỉ có ý nghĩa nếu bạn sử dụng field_map ở một số nơi khác trong mã của bạn.

Liên quan đến ví dụ thứ ba của bạn: Mặc dù bạn không cần phải gán cho chúng (khác với None), thực tế phổ biến là khai báo một cách rõ ràng các thuộc tính trong phương thức __init__. .

Vì vậy, sau đây là tốt hơn so với chỉ đơn giản là có một phương pháp __init__ rỗng (bạn cũng sẽ nhận được một cao pylint điểm cho rằng):

class Blah(object): 
    def __init__(self): 
     self.foo = None 
     self.bar = None 

blah = Blah() 
blah.foo = var1 

Vấn đề với phương pháp này là, đối tượng của bạn có thể ở trạng thái không được xác định rõ ràng sau khi khởi tạo, bởi vì bạn chưa định nghĩa tất cả các thuộc tính của đối tượng của bạn. Điều này phụ thuộc vào logic của đối tượng của bạn (logic trong mã và ý nghĩa) và cách đối tượng của bạn hoạt động. Tuy nhiên, nếu đúng như vậy, tôi khuyên bạn không phải để thực hiện theo cách này. Nếu đối tượng của bạn dựa trên foobar để được xác định một cách có ý nghĩa, bạn nên thực sự đặt chúng bên trong phương thức __init__ của bạn.

Nếu, tuy nhiên, các thuộc tính foobar không bắt buộc, bạn có thể tự do xác định chúng sau đó.

Nếu khả năng đọc của danh sách đối số là vấn đề đối với bạn: Sử dụng đối số từ khóa.