2012-03-15 38 views
6

Tôi cần gọi phương thức không được tham số first, nhưng cũng được tham số first, nhưng lỗi đó gây ra lỗi.phương pháp quá tải trong python

>>> class A: 
...  def first(self): 
...    print 'first method' 
...  def first(self,f): 
...    print 'first met',f 
... 
>>> a=A() 
>>> a.first() 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: first() takes exactly 2 arguments (1 given) 

Có thể thực hiện quá tải phương thức bằng Python như trong Java không?

+1

* Xin vui lòng * kế thừa từ đối tượng! Bạn không * thực sự * muốn một lớp học kiểu cũ, phải không? (Điều này sẽ không phải là vấn đề trong Python 3, nhưng các câu lệnh in của bạn cho tôi biết rằng bạn đang sử dụng Python 2.) –

Trả lời

9

Phương thức first thứ hai của bạn sẽ ghi đè phương thức gốc first. Trong Python, không thể tạo các phương thức quá tải giống như trong Java.

Tuy nhiên, bạn có thể tạo các phương pháp với các đối số tùy chọn và/hoặc dựa trên từ khóa và xử lý các đối số đó cho phù hợp. Dưới đây là một ví dụ:

class A: 
    def first(self, f=None): 
     if f is not None: 
      print 'first met', f 
     else: 
      print 'first method' 

Cách sử dụng:

a = A() 
a.first() 
a.first('something') 
+2

Vâng. Kiểu đối số mặc định của python thực sự ngắn gọn hơn, và, imo, dễ đọc hơn và duy trì sau đó danh sách khổng lồ kiểu Java của các phương thức ghi đè với số lượng đối số giảm dần. –

0

Python không phải là C++ hay Java; bạn không thể quá tải phương pháp theo cùng một cách.

Thực sự, cách duy nhất để làm những gì bạn muốn là để kiểm tra sự hiện diện hay vắng mặt của tham số thứ hai:

class A: 
    def first(self, f=None): 
     if f is None: 
     print 'first method' 
     else: 
     print 'first met',f 

Bạn có thể chưa tinh vi hơn và kiểm tra các loại f nhưng điều đó có thể nguy hiểm, và không phải lúc nào cũng "pythonic". (Tuy nhiên, cần lưu ý rằng một trường hợp sử dụng cho function annotations trong Python 3 là cho phép loại "Lập trình chung" này.)

0

Mặc dù có thể tạo ra một hệ thống dường như sử dụng các phương thức quá tải, có một chút liên quan, và thường không cần thiết.

Các thành ngữ thông thường là có thể không cần thiết thông số mặc định để None, như vậy:

class A: 
    def first(self, f=None): 
     if f is None: 
      print 'first method' 
     else: 
      print 'first met',f 

Trong trường hợp của bạn, nơi bạn muốn hành vi khác nhau dựa trên hay không đây là cuộc gọi đầu tiên đến phương pháp đó, đây là những gì tôi sẽ làm:

class A: 
    def first(self): 
     print 'first method' 
     self.first = self._first 
    def _first(self, f):     # '_' is convention for private name 
     print 'first met',f 

và đầu ra mẫu:

a = A() 
a.first() 
a.first(3) 

in:

first method 
first met 3 
5

Python không thực hiện quá tải chức năng. Đây là một hệ quả của nó là một ngôn ngữ lỏng lẻo. Thay vào đó, bạn có thể chỉ định một số lượng các đối số không xác định và xử lý việc diễn giải của chúng trong logic chức năng.

Có một số cách bạn có thể thực hiện việc này. Bạn có thể chỉ định đối số tùy chọn cụ thể:

def func1(arg1, arg2=None): 
    if arg2 != None: 
     print "%s %s" % (arg1, arg2) 
    else: 
     print "%s" % (arg1) 

Gọi đó là chúng tôi nhận được:

>>> func1(1, 2) 
1 2 

Hoặc bạn có thể chỉ định một số không rõ các đối số giấu tên (ví dụ:đối số được truyền vào một mảng):

def func2(arg1, *args): 
    if args: 
     for item in args: 
      print item 
    else: 
     print arg1 

Gọi đó là chúng tôi nhận được:

>>> func2(1, 2, 3, 4, 5) 
2 
3 
4 
5 

Hoặc bạn có thể chỉ định một số không rõ các đối số được đặt tên (ví dụ: đối số được truyền trong một cuốn từ điển):

def func3(arg1, **args): 
    if args: 
     for k, v in args.items(): 
      print "%s %s" % (k, v) 
    else: 
     print arg1 

Gọi điện cho chúng tôi là:

>>> func3(1, arg2=2, arg3=3) 
arg2 2 
arg3 3 

Bạn có thể sử dụng những công trình này để tạo ra hành vi mà bạn đang tìm kiếm trong quá tải.

+1

'func1()' của bạn không hoạt động như được gọi là có thể mong đợi khi nó được gọi là 'func1 (1, 0)' – bgporter

+0

Ah yeah, bắt tốt. Thực hiện thay đổi. – cjm

3

Thông thường bạn chỉ có thể xác định một phương thức trong một lớp học với một tên đã cho. Trong ví dụ của bạn, phương thức first() của đối số 2 đã ghi đè đối số 1 đầu tiên(). Nếu bạn muốn hai phương thức có cùng tên, trong python 3 bạn phải sử dụng functools.singledispatch và ánh xạ tên phương thức cá thể cho trình điều phối phương thức tĩnh của bạn, Ouch!

Điều đó nói rằng, tôi thực sự thích tiềm ẩn công văn động trong lập trình OO và tôi thấy nó sạch hơn viết logic thủ công trong một số hàm 'master' đầu tiên(), lặp lại và giòn để mở rộng.

Câu hỏi thách thức: thêm phương thức khác như A.first (A arg).

Có thể bạn sẽ học được rất nhiều về hệ thống kiểu python nếu bạn cố gắng làm điều này!

#!/opt/local/bin/python3.4 

from functools import singledispatch; 

class A(object): 

    # default method handles dispatch for undefined types 
    # note reversed positional args to match single dispatch functools 
    @singledispatch 
    def _first(arg, self): 
     raise TypeError("no match for A._first(%s)" % type(arg)); 

    # adapter maps instance call to (reversed) static method call 
    def first(self, arg = None): return A._first(arg, self); 

    # def first() 
    @_first.register(type(None)) 
    def _(none, self): 
     print("A.first() called"); 

    # def first(float f) 
    @_first.register(float) 
    def _(f, self): 
     print("A.first(float %s) called" % f); 

a = A(); 
a.first();    # A.first() called 
a.first(None);   # A.first() called 
a.first(3.14);   # A.first(float 3.14) called 

class B(object): pass; 
b = B();     
try: a.first(b);  # no match for A._first(<class '__main__.B'>) 
except TypeError as ex: print(ex); 
+0

bạn là tốt! ví dụ tốt – madjardi

+0

Ồ, đó là * thông minh * :-) –

1

Kiểm tra mã này nếu nó là hữu ích:

from math import pi 

class Geometry: 

    def area(self,length = None,breadth = None,side = None,radius = None): 
     self.length = length 
     self.breadth = breadth 
     self.side = side 
     self.radius = radius 

     if length != None and breadth != None: 
      return length * breadth 
     elif side != None: 
      return side * side 
     else: 
      return pi * radius * radius 

obj1 = Geometry() 
print('Area of rectangle is {0}.'.format(obj1.area(length=5,breadth=4))) 
print('Area of square is {0}.'.format(obj1.area(side=5))) 
print('Area of circle is {0:.6}.'.format(obj1.area(radius=10))) 
Các vấn đề liên quan