2010-09-04 36 views
8

Có phải pythonic bắt chước quá tải phương thức như được tìm thấy trong các ngôn ngữ được gõ tĩnh không? Bằng cách đó tôi có nghĩa là viết một hàm kiểm tra các loại đối số của nó và hoạt động khác nhau dựa trên các loại đó.Có phải Pythonic bắt chước quá tải phương thức không?

Dưới đây là một ví dụ:

class EmployeeCollection(object): 
    @staticmethod 
    def find(value): 
     if isinstance(value, str): 
      #find employee by name and return 
     elif isinstance(value, int): 
      #find employee by employee number and return 
     else: 
      raise TypeError() 
+0

Tôi nghĩ rằng bạn quên để thêm 'self' làm tham số đầu tiên –

+0

Thực ra, nó có nghĩa là một phương thức tĩnh. Tôi đã cập nhật nó ngay bây giờ. – hwiechers

Trả lời

13

Không rất Pythonic, trừ có lẽ, trong 2.6 hoặc tốt hơn, nếu tất cả kiểm tra dựa vào các lớp cơ sở trừu tượng mới, được thiết kế trong phần chính xác để tạo điều kiện sử dụng đó. Nếu bạn từng thấy mình đánh máy cho lớp bê tông, thì bạn biết bạn đang làm cho mã của bạn trở nên mong manh và hạn chế việc sử dụng mã. Ví dụ:

Vì vậy, ví dụ: kiểm tra xem bạn có ví dụ numbers.Integral không quá tệ - ABC mới có tồn tại một phần chính xác để giảm bớt việc kiểm tra đó hay không. Kiểm tra xem bạn có một trường hợp của int là một thảm họa hay không, hãy loại trừ long, gmpy.mpz và một số lượng khác các số nguyên như thế, để hoàn toàn không có mục đích tốt: không bao giờ kiểm tra các lớp cụ thể!

Chuỗi là trường hợp khó, nhưng lớp trừu tượng basestring (không phải là một trong các loại ABC mới) là một khả năng. Một chút quá hạn chế, có lẽ, nhưng nếu bạn đang sử dụng ABC khác xung quanh nó, nó có thể kinda, sorta làm việc, nếu bạn thực sự có. Chắc chắn nhất là không phảistr - tại sao lại loại trừ unicode?!

13

Không thực sự, kể từ khi bạn mất khả năng sử dụng các loại mà không phải là-khá-mà-nhưng-gần-đủ. Thay vào đó, hãy tạo hai phương pháp riêng biệt (find_by_name()find_by_number()).

+0

-1, Bây giờ bạn chỉ cần mã hóa kiểu tĩnh thành tên của các phương thức - không phải là rất năng động! Và nếu bạn có 5 tham số khác nhau có thể là chuỗi hoặc số thì sao? Bạn có tạo 32 phương pháp khác nhau không? – Gabe

+3

Nếu bạn có 5 đối số có thể là chuỗi hoặc số thì bạn có vấn đề về kiến ​​trúc lớn hơn (và có thể là vấn đề sâu hơn mà không có diễn đàn phát triển phần mềm nào có thể trợ giúp ...). –

+0

Bạn nên có các tên phương thức khác nhau vì hàm ý với * kiểm tra * loại có nghĩa là bạn * hành động khác * tùy thuộc vào kết quả của kiểm tra đó. Tuy nhiên, trong python, chúng tôi thích làm cho mọi thứ rõ ràng hơn; nếu hành vi là khác nhau, thì tên phương thức cũng phải khác nhau. Thời gian duy nhất tôi xem xét việc phá vỡ quy tắc này là pythonic sẽ kiểm tra rằng một đối số 'là None', để gọi một hành vi mặc định hợp lý. – SingleNegationElimination

2

Tôi sẽ nói có, đó là 'Pythonic' Và có những ví dụ để trả lại điều này (mà các áp phích khác không được đưa ra). Để trả lời câu hỏi này đúng, cần có các ví dụ!

Từ lõi python:

  • string.startswith() Nó chấp nhận hoặc là một chuỗi hoặc một tuple (các chuỗi).
  • string.endswith()

Trong pymongo:

  • find_one() chấp nhận hoặc là một đối tượng dict để tra cứu, hoặc nó sẽ sử dụng một đối tượng khác như id.

Xin lỗi tôi không biết nhiều hơn, nhưng tôi nghĩ có rất nhiều ví dụ về các phương thức hoạt động khác nhau theo các thông số đã cho. Đó là một phần của vẻ đẹp của việc không thực thi các loại.

+1

-1 typechecking là __never__ pythonic. Kiểm tra giao diện nhưng không gõ. mức độ mà typechecking xảy ra trong thư viện chuẩn là để được thực hiện như là một thiếu hụt và không phải là một ví dụ. – aaronasterling

+0

@aaronasterling: Tôi nghĩ rằng 'không bao giờ' là một chút mạnh mẽ. Làm thế nào về trong '__init__' phương pháp? Ví dụ bạn có thể xây dựng một 'bytearray' từ một' bytearray' khác, một số nguyên, một số nguyên có thể lặp lại, một 'memory_view', một chuỗi hoặc (chỉ Python 3) một đối tượng' bytes'. Tất cả những thứ đó từ một loại được cài sẵn tương đối gần đây! –

+0

@Scott: Thực tế là bạn cần phải sử dụng kiểm tra kiểu không có loại kiểm tra thêm bất kỳ Pythonic. –

1

Một cách thức bắt mắt hơn đối với loại chức năng này là chỉ cần thử và sử dụng nó theo cách ưa thích (bất kỳ điều gì có thể có ý nghĩa) và nếu đối số không hỗ trợ điều đó, hãy thử thay thế.

Here'd hai cách để làm điều đó:

class EmployeeCollection(object): 
    def find(value): 
     try: 
      #find employee by name and return 
     catch: 
      try: 
       #find employee by employee number and return 
      catch: 
       raise TypeError() 

nhưng thats loại yucky. dưới đây là cách tôi thường làm điều này:

class EmployeeCollection(object): 
    def find(value): 
     if hasattr(value, 'join'): 
      #find employee by name and return 
     elif hasattr(value, '__div__'): 
      #find employee by employee number and return 
     else: 
      raise TypeError() 

Thực tế, thuộc tính thực tế tôi muốn kiểm tra phụ thuộc vào những gì xảy ra trong các nhận xét đó, tôi muốn kiểm tra thuộc tính mà tôi thực sự sử dụng.

+0

Tôi thực sự sẽ nói rằng cách tiếp cận đầu tiên của bạn là tốt hơn. – detly

+0

Chuyển đối số cho hàm tạo của loại bạn quan tâm và bắt bất kỳ ngoại lệ nào từ đó. –

+0

Ví dụ thứ hai là 'pythonic' hơn vì nó đang kiểm tra giao diện chứ không phải kiểu. Vì vậy, tôi sẽ nói đó là câu trả lời đúng của bạn. Tôi nghĩ rằng một số giáo điều về 'không bao giờ kiểm tra loại' là một chút ngớ ngẩn. – Amala

5

Không, nhập kiểm tra ở đây không phải là Pythonic. Một lựa chọn khác nếu bạn làm nhiều phương pháp không ưa thích là để gắn bó với một phương pháp nhưng sử dụng nhiều thông số:

def find(name=None, employee_number=None): 
    if sum(x != None for x in (name, employee_number)) != 1: 
     #raise exception - exactly one value should be passed in 
    if name is not None: 
     #find employee by name and return 
    if employee_number is not None: 
     #find employee by employee number and return 

Khi sử dụng mục đích là rõ ràng như với nhiều phương pháp:

employee1 = x.find(name="John Smith") 
employee2 = x.find(employee_number=90210) 
Các vấn đề liên quan