2013-04-08 87 views
1

以前可能已经提到过这个问题,但我不知道如何查找答案,因为我不确定什么是解决问题的好方法。Python中的灵活参数

该主题是函数参数,可以用许多不同的方式在语义上表达。例如,要将文件提供给函数,可以直接提供文件,也可以提供一个字符串,即文件的路径。要指定一个数字,你可以允许一个整数作为参数,或者你可以允许一个字符串(数字),或者你甚至可以允许一个字符串,比如“one”。另一个例子可能是一个函数,它需要一个列表(例如数字),但为了方便起见,它会将一个数字转换为包含一个元素的列表:该数字。

在Python中是否有一个或多或少标准的方法来实现这种灵活性?如果你不确定参数是什么类型的话,它肯定会使程序的代码复杂化,所以我的猜测是试图将便利函数分解到一个地方,而不是分散到任何地方,但我真的不知道最好做这样的保理。

+1

我猜测会有一些回复说:不要那么做!这可能是一个好建议,但仍然存在一个问题:何时需要在不同形式的语义等价对象之间进行转换,应该在何处进行转换?在调用函数中?这可能会导致很多重复的代码。 – 2013-04-08 15:30:54

+0

提出的具体示例(不是我的代码,而是由我工作的人编写的代码)是文件。以文件作为参数的函数可以将字符串作为参数(解释为路径),也可以取实际文件(open()函数的结果)。 在同一代码中出现的另一个例子是一个函数,它可以接收消息列表或单个消息。后一种情况被解释为与长度为1的列表相同。 我已经给出了这些示例,因此它们可能仍然太抽象了?什么使他们对你更具体? – 2013-04-08 15:42:09

+0

在第二个示例中,您可以使用'* args'来完全避免检查(即使存在缺陷)。 – Bakuriu 2013-04-08 15:44:55

回答

0
  1. 不要那样做! ;)

但是,如果你仍然想,我建议你有一个中间类或函数处理这个给你:

伪代码:

def printTheNumber(num): 
    print num 


def intermediatePrintTheNumber(input): 

    num_int_dict = {'one':1, "two":2 .... 
    if input.isstring(): 
     printTheNumber(num_int_dict[input]) 
    elif input.isint(): 
     printTheNumber(input) 
    else: 
     print "Sorry Dave, I don't understand you" 

如果这是pythonic我不知道,但这就是我必须要解决的问题,当然还需要对输入进行更多的检查以确定它是否有效。

说到你的评论,你提到语义相似性,即"one"1可能意味着同样的事情。

你应该问这种类型的转换在哪里。

那么这取决于你的系统的设计,但我可以告诉你,它不应该在一个非常简单的原因,我叫printTheNumber相同的功能,这就是那将使功能的方式责任重大。

根据输入的复杂性,可能是integer 1string "1"或者,在最坏的情况下,"one"或者甚至更糟"uno"|"one"|"yxi"|"ett" .. and so on。这应该由一个函数来处理,该函数只有处理映射的数据库才有责任。

我会分裂它,让我有一个函数处理字符串“一”,“两”...等等,一个处理整数,并有第三个函数,检查输入,看看它是否可以转换为整数或不。

在我看来,有一个在设计一个fundamental缺陷警告,如果你要采取措施,对这种复杂的,但你似乎是意识到这一点,所以我不会去左右对它。

0

一个很好的方法来分解出几个函数的共同代码是decorators。例如,

from functools import wraps 

def takes_list(func): 
    @wraps(func) 
    def wrapper(arg): 
     if not isinstance(arg, list): 
      arg = [arg] 
     return func(arg) 
    return wrapper 

@takes_list 
def my_func(x): 
    "Does something with list x." 

我要指出,对于案件,如文件,你不希望在Python的鸭打字的方式来获得:做一个检查isinstance(arg, file)有它不会允许文件级的问题喜欢的东西如io.StringIO。相反,检查str(或basestring)或甚至让open检查你,除了尝试除外。

但是,通常情况下最好的做法是让调用者将他们喜欢的内容传递给该函数,如果该函数无效则失败。

+0

关于你采取了错误的“方向”的文件。你通常希望执行'str - > file'转换,而不是相反,因此你应该检查对象是否是'str'而不是'file'。此外,'open' **会检查参数的类型,因此执行'isinstance(file,str):file = open(file)'不会消除方法的灵活性。 – Bakuriu 2013-04-08 15:48:50

+0

@Bakuriu好点。我已经编辑了我的答案,包括检查'str'而不是'file',还提到了EAFP使用'open'的方式。 – 2013-04-08 16:11:14

-1
  1. 既然你不能添加在运行时的方法来内建类,如intstr你会作出一个开关case语句状结构由丹尼尔·菲格罗亚提及。

  2. 另一种方法是只转换:

    def func(i): 
        if not isinstance(i, int): 
         i = int(i) # objects can overwrite __int__ if needed. 
    
  3. 如果你有自己的类,你可以添加方法,你可以使用双派遣做同样的事情你。 Smalltalk将此用于整数浮点型转换。

  4. 另一种方法是使用对此我还没有找到一个实现尚未面向主题的节目,但我想:https://gist.github.com/niccokunzmann/4971938

+0

'既然你不能扩展内建类,比如int或str',那么你的想法是什么? – 2013-04-08 15:43:34

+1

您是否使用“extend”表示“在运行时添加方法”或通过子类继承? – Bakuriu 2013-04-08 15:46:29

+0

Smalltalk,Ruby - 在运行时添加方法 - 添加了这个 – User 2013-04-08 15:46:44

0

没有,没有更多或更少的“标准”的方式来这。