2010-10-29 28 views
6

Tôi có một chức năng mà tôi cần để tạo ra các chuỗi đầu ra khác nhau cho một chương trình khác mà tôi gọi, tùy thuộc vào loại nó muốn.Cách kinh điển xử lý các loại khác nhau trong Python là gì?

Về cơ bản, chương trình được gọi cần một đối số dòng lệnh cho biết loại được gọi với nó.

Hạnh phúc tôi tìm thấy this answer trên SO về cách kiểm tra biến cho loại. Nhưng tôi nhận thấy mọi người cũng phản đối như thế nào, việc kiểm tra các loại phản bội thiết kế "không hướng đối tượng". Vì vậy, là có một số cách khác, có lẽ nhiều hơn "hướng đối tượng" cách xử lý này mà không kiểm tra một cách rõ ràng cho loại?

Code tôi có bây giờ đi một cái gì đó như thế này:

def myfunc(val): 
    cmd_type = 'i' 
    if instance(val, str): 
     cmd_type = 's' 

    cmdline = 'magicprogram ' + cmd_type + ' ' + val 
    Popen(cmdline, ... blah blah) 
    ... 

mà làm việc tốt, nhưng tôi chỉ muốn biết nếu có một số kỹ thuật Tôi không biết.

+0

Bạn chuyển mã nào bằng một loại trên dòng lệnh? – geoffspear

+0

@Wobble, tôi đã thêm một ví dụ. Tôi nhận ra câu hỏi không rõ ràng lắm. Hy vọng nó là tốt hơn bây giờ. –

+0

myfunc được gọi như thế nào? Tôi sẽ đề nghị có hai hàm khác nhau mà mong đợi một kiểu đối số khác, sau đó tạo một hàm riêng của phần dưới cùng của hàm mà bạn gọi với các đối số thích hợp từ mỗi hàm cũ. – teukkam

Trả lời

3

Tôi không nghĩ đúp Dispatching hoặc Multimethods đặc biệt có liên quan cũng không có nhiều việc phải làm với sự phản đối của người phải rằng khác SO trả lời.

Không ngạc nhiên, để làm những gì bạn đang làm hướng đối tượng hơn, bạn cần giới thiệu một số đối tượng (và các lớp tương ứng) vào nó. Làm cho mỗi giá trị một thể hiện của một lớp sẽ cho phép - trên thực tế, hầu như bắt buộc - bạn ngừng kiểm tra kiểu của nó. Các sửa đổi mẫu mã của bạn dưới đây cho thấy một cách rất đơn giản này có thể đã được thực hiện:

class Value(object): 
    """ Generic container of values. """ 
    def __init__(self, type_, val): 
     self.type = type_ # using 'type_' to avoid hiding built-in 
     self.val = val 

def myfunc(val): 
    # Look ma, no type-checking! 
    cmdline = 'magicprogram {obj.type} {obj.val}'.format(obj=val) 
    print 'Popen({!r}, ... blah blah)'.format(cmdline) 
    # ... 

val1 = Value('i', 42) 
val2 = Value('s', 'foobar') 

myfunc(val1) # Popen('magicprogram i 42', ... blah blah) 
myfunc(val2) # Popen('magicprogram s foobar', ... blah blah) 

Nó sẽ là nhiều hơn hướng đối tượng nếu có phương pháp trong lớp Value để truy cập thuộc tính của nó gián tiếp, nhưng chỉ cần làm ở trên được loại bỏ kiểm tra loại khét tiếng. Một thiết kế hướng đối tượng hơn có lẽ sẽ có một lớp con khác cho mỗi loại Value, tất cả đều chia sẻ một tập hợp các phương thức chung cho các máy khách, như myfunc(), để sử dụng để tạo, thao tác và trích xuất thông tin từ chúng.

Lợi ích khác của việc sử dụng đối tượng là bạn không cần phải sửa đổi myfunc() nếu/khi bạn thêm hỗ trợ cho loại mới 'Giá trị` vào ứng dụng của bạn - nếu trừu tượng của bạn về bản chất của "Giá trị" một cái tốt, đó là.

5

Bạn có thể sử dụng Double Dispatch hoặc Multimethods.

+1

Và bằng Python, đó sẽ là http://www.artima.com/weblogs/viewpost.jsp?thread=101605 và http://en.wikipedia.org/wiki/Multiple_dispatch#Python Tôi giả sử. Cảm ơn! –

+0

Vì mục đích của tôi, tôi nghĩ tôi sẽ kiểm tra loại này, nhưng đây là một trải nghiệm rất sáng suốt, cả về cách thức hoạt động của Python và cách mọi người nghĩ về những vấn đề này. Chấp nhận câu trả lời của bạn vì câu trả lời gần giống nhất câu hỏi của tôi khi nó được xây dựng. –

1

Đây là một kỹ thuật trong câu hỏi lớn hơn là cách thiết kế một chức năng nhỏ. Có rất nhiều cách khác nhau để đi về nó, nhưng họ ít nhiều bị phá vỡ theo cùng một quá trình suy nghĩ chung. Quay lại nơi mà loại val được biết, nó sẽ xác định cách nó nên được dịch thành một dòng lệnh arg. Nếu đó là tôi, tôi có lẽ sẽ làm cho val là một lớp học có chức năng To Command Line đã làm điều đúng. Bạn cũng có thể gán một hàm myfunc cụ thể cho một biến sau đó gọi đó là khi bạn cần.

chỉnh sửa: Để giải thích phiên bản cuối cùng một cái gì đó dọc theo dòng của

Val = "a string" 
myfunc = myfuncStringVersion 

nhiều hay ít làm điều tương tự bạn làm với gói val trong một lớp học chỉ chia ra thành một giá trị và chức năng kể từ khi bạn có thể không muốn quấn val trong một lớp học.

+0

"Bạn cũng có thể gán một loại hàm myval cụ thể cho một biến sau đó gọi đó khi bạn cần." <---- Tôi đã đọc hết lần này đến lần khác, tôi không hiểu. –

+0

@Amigable Clark Kant Xin lỗi về điều đó hy vọng nó có ý nghĩa hơn bây giờ. – stonemetal

3
But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design 

Trên thực tế nó được gọi là Duck typing style ("Nếu nó trông giống như một con vịt và quacks như một con vịt, nó phải là một con vịt."), Và đó là ngôn ngữ python mà khuyên bạn nên sử dụng phong cách này của chương trình.

và gõ vịt đi một cái gì đó gọi EAFP (dễ dàng hơn để hỏi Tha thứ hơn Permission)

presumable more "more object oriented" way of handling this without 
    explicitly checking for type? 

bạn có nghĩa là pythonic hơn, về cơ bản những gì sẽ là pythonic hơn trong trường hợp của bạn là một cái gì đó như thế này:

def myfunc(val): 
    cmd_type = 'i' 

    # forget about passing type to your magicprogram 
    cmdline = 'magicprogram %s ' % val 
    Popen(cmdline, ... blah blah) 

và trong chương trình ảo thuật của bạn (tôi không biết đó là tập lệnh của bạn hay ...) và vì trong mọi trường hợp, chương trình của bạn sẽ nhận được chuỗi để chỉ chuyển đổi nó thành bất kỳ tập lệnh nào của bạn t;

from optparse import OptionParser 

# .... 

if __name__ == '__main__': 

    parser = OptionParser(usage="blah blah") 

    # ... 
    (options, args) = parser.parse_args() 

    # Here you apply the EAFP with all type accepted. 
    try: 
     # call the function that will deal with if arg is string 
     # remember duck typing. 
    except ... : 
     # You can continue here 

Tôi không biết tất cả các mã của bạn là gì, nhưng bạn có thể làm theo ví dụ trên đó là pythonic hơn, và nhớ mọi quy tắc có ngoại lệ của họ như vậy có lẽ trường hợp của bạn là một ngoại lệ và bạn sẽ được tốt hơn với loại kiểm tra.

Hy vọng điều này sẽ xóa mọi thứ cho bạn.

+0

Ok, trong trường hợp của tôi chương trình ảo thuật là NET-SNMP, và thay đổi nó không phải là một lựa chọn. Nhưng cảm ơn cho những suy nghĩ anyways. –

+0

Ahh ok, nhưng tôi hy vọng rằng câu trả lời của tôi có những điều rõ ràng về triết học python; Duck gõ và EAFP :) – mouad

+0

"nó có một cái gì đó để làm kiểu gõ Duck, và triết lý python của nó và không phải đối tượng theo định hướng" là không đúng sự thật và không yêu cầu Duct Typing. Đó là sự thật đối với bất kỳ ngôn ngữ nào hỗ trợ [đa hình] (http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming) và nhiều (nhất là?) OO làm, tôi tin. – martineau

Các vấn đề liên quan