2009-05-25 31 views
16

Hãy nói rằng tôi có lớp sauMột cách gọn gàng mở rộng một thuộc tính lớp trong lớp con

class Parent(object): 
    Options = { 
     'option1': 'value1', 
     'option2': 'value2' 
    } 

Và một lớp con gọi là Child

class Child(Parent): 
    Options = Parent.Options.copy() 
    Options.update({ 
     'option2': 'value2', 
     'option3': 'value3' 
    }) 

Tôi muốn để có thể ghi đè lên hoặc thêm tùy chọn trong lớp trẻ em. Giải pháp tôi đang sử dụng hoạt động. Nhưng tôi chắc chắn có một cách tốt hơn để làm điều đó.


EDIT

Tôi không muốn thêm các tùy chọn như lớp thuộc tính bởi vì tôi có các thuộc tính lớp khác mà không phải là lựa chọn và tôi muốn giữ tất cả các tùy chọn ở một nơi. Đây chỉ là một ví dụ đơn giản, mã thực tế phức tạp hơn thế.

+0

Tại sao không xuất xưởng logic copy/cập nhật trong một phương thức của lớp cha mẹ? Nếu bạn đặt nó trong '__init__' và luôn gọi' super() .__ init __() 'ở cuối lớp con' __init__ 'như bạn đang nghĩ, nó sẽ hoạt động. – asmeurer

Trả lời

8

Một cách sẽ được sử dụng đối số từ khóa để dict để xác định phím bổ sung:

Parent.options = dict(
    option1='value1', 
    option2='value2', 
) 

Child.options = dict(Parent.options, 
    option2='value2a', 
    option3='value3', 
) 

Nếu bạn muốn nhận được fancier, sau đó sử dụng giao thức mô tả bạn có thể tạo một đối tượng proxy sẽ đóng gói tra cứu. (chỉ cần đi bộ chủ sở hữu .__ mro__ từ các thuộc tính chủ sở hữu để __get __ (tự, ví dụ, chủ sở hữu) phương pháp). Hoặc thậm chí là người giàu có, vượt qua lãnh địa có lẽ không phải là một ý tưởng tốt, các trang trí lớp học/lớp học.

+0

Điều này sẽ chỉ hoạt động nếu các khóa của bạn là tất cả các chuỗi là số nhận dạng biến hợp lệ của Python. – asmeurer

4

Tại sao không chỉ sử dụng thuộc tính lớp học?

class Parent(object): 
    option1 = 'value1' 
    option2 = 'value2' 

class Child(Parent): 
    option2 = 'value2' 
    option3 = 'value3' 
+0

bạn, giành chiến thắng. đánh bại tôi trong 20 giây :) – SpliFF

+0

Tôi thích giữ các tùy chọn trong một thuộc tính vì tôi có các thuộc tính lớp khác không phải là các tùy chọn. –

+0

Bạn có thể đánh dấu các attirbutes đặc biệt bằng một tiền tố, ví dụ: 'opt_foo' và' opt_bar' và sau đó truy cập vào các ví dụ đó '[getattr (self, x) cho x trong dir (self) nếu x.startswith ("opt _")] ' –

2
class ParentOptions: 
    option1 = 'value1' 
    option2 = 'value2' 

class ChildOptions(ParentOptions): 
    option2 = 'value2' 
    option3 = 'value3' 

class Parent(object): 
    options = ParentOptions() 

class Child(Parent): 
    options = ChildOptions() 
+0

Hmmm, tôi không biết. Tôi thích một cách tự động để làm điều đó. Tôi có hàng chục lớp con. Thêm một lớp riêng biệt cho mỗi tùy chọn sẽ là một mớ hỗn độn. –

21

Ngữ nghĩa tương đương với mã của bạn nhưng cho là gọn gàng:

class Child(Parent): 
    Options = dict(Parent.Options, 
     option2='value2', 
     option3='value3') 

Hãy nhớ rằng, "cuộc sống tốt hơn mà không cần niềng răng", và bằng cách gọi dict rõ ràng bạn thường có thể tránh niềng răng (và dấu ngoặc kép thêm xung quanh các phím được nhận dạng liên tục giống như chuỗi).

Xem http://docs.python.org/library/stdtypes.html#dict để biết thêm chi tiết - bit quan trọng là: "Nếu một phím được quy định cả trong đối số vị trí và như một đối số từ khóa, giá trị liên quan đến từ khóa được giữ lại", tức là từ khóa args override Key- các liên kết giá trị trong arg vị trí, giống như phương thức update cho phép bạn ghi đè chúng).

6

Sau khi suy nghĩ thêm về nó, và nhờ @SpliFF đề nghị này là những gì tôi đã đưa ra:

class Parent(object): 
    class Options: 
     option1 = 'value1' 
     option2 = 'value2' 


class Child(Parent): 
    class Options(Parent.Options): 
     option2 = 'value2' 
     option3 = 'value3' 

Tôi vẫn mở cửa cho giải pháp tốt hơn mặc dù.

+0

Nhược điểm của phương pháp này là nó xấu hơn nhiều để làm thiết lập năng động của các tùy chọn. Ví dụ để đọc các tùy chọn của một lớp từ một tệp cấu hình. –

+0

Giải pháp này phù hợp hơn trong trường hợp đặc biệt của tôi. Nhưng như một giải pháp chung, giải pháp của bạn tốt hơn. –

+0

Các phương thức '__getitem__' /' __setitem__' thích hợp có thể được thêm vào sau nếu cần. Đây là một giải pháp tốt, sạch sẽ. –

2

Dưới đây là một cách sử dụng một metaclass

class OptionMeta(type): 
    @property 
    def options(self): 
     result = {} 
     for d in self.__mro__[::-1]: 
      result.update(getattr(d,'_options',{})) 
     return result 

class Parent(object): 
    __metaclass__ = OptionMeta 
    _options = dict(
     option1='value1', 
     option2='value2', 
     ) 

class Child(Parent): 
    _options = dict(
     option2='value2a', 
     option3='value3', 
     ) 

print Parent.options 
print Child.options 
Các vấn đề liên quan