2010-02-07 17 views
18

Tôi có một lớp:Tránh xác định tất cả các đối số trong một lớp con

class A(object): 
    def __init__(self,a,b,c,d,e,f,g,...........,x,y,z) 
     #do some init stuff 

Và tôi có một lớp con mà cần thêm một arg (người cuối cùng W)

class B(A): 
    def __init__(self.a,b,c,d,e,f,g,...........,x,y,z,W) 
     A.__init__(self,a,b,c,d,e,f,g,...........,x,y,z) 
     self.__W=W 

Dường như câm để viết tất cả mã lò hơi này, ví dụ: chuyển tất cả các số arg từ số's Ctor đến cuộc gọi bên trong tới số' s ctor, từ đó mọi thay đổi đến cpu của A phải được áp dụng cho hai vị trí khác trong mã của B.

Tôi đoán python có một số thành ngữ để xử lý các trường hợp như vậy mà tôi không biết. Bạn có thể chỉ cho mình hướng chính xác được không?

linh cảm tốt nhất của tôi, là phải có một loại Copy-ctor cho A và sau đó thay đổi mã B vào

class B(A): 
    def __init__(self,instanceOfA,W): 
     A.__copy_ctor__(self,instanceOfA) 
     self.__W=W 

này sẽ phù hợp với nhu cầu của tôi kể từ khi tôi luôn luôn tạo ra các lớp con khi đưa ra một thể hiện của người cha lớp học, Mặc dù tôi không chắc chắn liệu nó có thể ...

+0

Nếu bạn có nhiều lý lẽ, tôi sẽ không sử dụng đối số vị trí nhưng có tất cả/nhất trong số họ như kwargs và sử dụng cú pháp py3 '*' 'def __initi __ (arg1, arg2, * kwarg1 = ..., ..., kwargx = ..., w = ...)' để buộc kwargs (= không dựa vào gọi món). Việc sử dụng 'def __init __ (self, arg1, arg2, *, ** kwargs)' ngắn hơn, nhưng tôi không thích nó bởi vì nó làm rối tung mã hoàn thành trong các IDE như pycharm. Ngoài một chút chất thải màn hình, tác hại của việc viết ra tất cả các kwarg là gì? Bạn sẽ phải ghi lại tất cả chúng trong docstring ... –

Trả lời

17

Xét rằng lập luận có thể được thông qua hoặc theo tên hoặc theo vị trí, tôi muốn mã:

class B(A): 
    def __init__(self, *a, **k): 
     if 'W' in k: 
     w = k.pop('W') 
     else: 
     w = a.pop() 
     A.__init__(self, *a, **k) 
     self._W = w 
+0

Tôi thích ý tưởng này, nhưng tôi không nghĩ rằng ví dụ hoạt động. Vì '* a' khiến' a' thành [nhận được ** tuple **] (http://docs.python.org/tutorial/controlflow.html?highlight=kwargs#keyword-arguments), 'a' doesn ' t có phương thức 'pop()'. 'a' cần phải được chuyển đổi thành danh sách trước tiên. Ngoài ra, nếu tất cả các đối số được truyền theo tên, 'a' là rỗng (vì vậy bạn không thể' pop() 'nó). –

+0

Er, không bao giờ là câu cuối cùng trong bình luận trước của tôi. –

+1

'Thuộc tínhError: đối tượng 'tuple' không có thuộc tính 'pop'' –

0

Bạn có muốn một cái gì đó như thế này?

class A(object): 
    def __init__(self, a, b, c, d, e, f, g): 
     # do stuff 
     print a, d, g 

class B(A): 
    def __init__(self, *args): 
     args = list(args) 
     self.__W = args.pop() 
     A.__init__(self, *args) 
+0

tốt, điều này làm việc cho phiên bản rất đơn giản. Nhưng bây giờ B có bất kỳ số lượng args (ít hạn chế) ... Không phải là có một cái gì đó thành ngữ hơn? – olamundo

+1

B chỉ loại có bất kỳ số lượng đối số nào; nó gọi A và nếu A nhận sai số, nó sẽ tăng 'TypeError'. Bạn có thể kiểm tra rõ ràng số lượng đối số nếu bạn muốn. Tôi có lẽ sẽ trong mã sản xuất. –

+0

Nếu bạn tìm thấy số lượng các đối số sai, bạn sẽ tự mình tăng TypeError. – Dinoboff

7

Chỉnh sửa: dựa trên đề xuất của Matt và để giải quyết mối quan ngại của gnibbler về cách tiếp cận đối số vị trí; bạn có thể kiểm tra để chắc chắn rằng đối số lớp con cụ thể thêm được quy định tương tự như-Alex's answer:

class B(A): 
    def __init__(self, *args, **kwargs): 
    try: 
     self._w = kwargs.pop('w') 
    except KeyError: 
     pass 
    super(B,self).__init__(*args, **kwargs) 

>>> b = B(1,2,w=3) 
>>> b.a 
1 
>>> b.b 
2 
>>> b._w 
3 

câu trả lời gốc:
Cùng ý tưởng như Matt's answer, sử dụng super() để thay thế.

Sử dụng super() để gọi phương thức lớp cha của __init__(), sau đó tiếp tục initialising các lớp con:

class A(object): 
    def __init__(self, a, b): 
    self.a = a 
    self.b = b 

class B(A): 
    def __init__(self, w, *args): 
    super(B,self).__init__(*args) 
    self.w = w 
+0

Giải pháp này yêu cầu rằng w phải được chuyển thành arg đầu tiên hoặc theo tên. Câu hỏi có nó là arg –

+0

@gnu nibbler cuối cùng: cảm ơn bạn đã bình luận của bạn. Tôi đã chỉnh sửa câu trả lời của mình để giải quyết vấn đề này; tương tự như những gì Alex đăng nhiều giờ trước đây :-) – bernie

2

Trong trường hợp một số hoặc tất cả đối số được chuyển đến __init__ có giá trị mặc định, có thể hữu ích để tránh lặp lại chữ ký phương thức __init__ trong các lớp con.

Trong những trường hợp này, __init__ có thể vượt qua bất kỳ đối số thêm phương pháp khác, mà lớp con có thể ghi đè:

class A(object): 
    def __init__(self, a=1, b=2, c=3, d=4, *args, **kwargs): 
     self.a = a 
     self.b = b 
     # … 
     self._init_extra(*args, **kwargs) 

    def _init_extra(self): 
     """ 
     Subclasses can override this method to support extra 
     __init__ arguments. 
     """ 

     pass 


class B(A): 
    def _init_extra(self, w): 
     self.w = w