2010-09-04 74 views
8

模拟静态类型语言中发现的方法重载是pythonic吗?因此,我的意思是写一个函数,检查其参数的类型,并根据这些类型行为不同。模拟方法重载是Pythonic吗?

下面是一个例子:

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

我想你忘记了添加'self'作为第一个参数 – 2011-06-18 05:39:57

+0

实际上,它本意是一个静态方法。我现在更新了它。 – hwiechers 2011-06-18 09:28:58

回答

13

不是很符合Python,除了也许,在2.6或更好,如果所有的检查,依靠新的抽象基类,其目的之一正是促进这种利用。如果你发现自己的类型检查是具体类,那么你知道你让你的代码变得脆弱并削弱它的使用。

所以,例如,检查你是否有一个numbers.Integral的实例并不算太坏 - 新的ABC存在很大程度上是为了简化这种检查。检查你是否有一个int的实例是一个灾难,排除了long,gmpy.mpz和一个其他类型的整数类数字,绝对没有好的目的:从不检查具体的类!

字符串是一个困难的情况,但basestring抽象类(不是新的类型的ABC)是一种可能性。可能有点过于严格,但如果你在其他地方使用其他ABCs,那么可能就是,如果你真的必须的话,还是可以的。最肯定的是不是str - 为什么要排除unicode?!

13

不是真的,因为你失去了使用类型的能力不在-相当,也就是说,但是,足够接近的。改为创建两个单独的方法(find_by_name()find_by_number())。

+0

-1,现在你只是静态编码类型到你的方法的名称 - 不是很动态!如果你有5个不同的参数可能是字符串或数字呢?你创建了32种不同的方法吗? – Gabe 2010-09-05 08:05:14

+3

如果您有5个参数可能是字符串或数字,那么您的体系结构问题会更大(并且可能存在更深层次的根本性问题,即没有软件开发论坛可以帮助...)。 – 2010-09-05 08:38:26

+0

您应该有不同的方法名称,因为含有*检查*类型的含义意味着您的行为不同*取决于该检查的结果。然而,在Python中,我们更愿意将事情明确化;如果行为不同,那么方法名称也应该不同。唯一一次我会考虑打破这个规则pythonic会检查一个参数为“无”,以调用一个合理的默认行为。 – SingleNegationElimination 2011-06-18 11:06:07

2

我会说是,它是'Pythonic'并且有些例子可以支持它(其他海报没有给出)。要正确回答这个问题,应该有例子!

在Python核心:

  • string.startswith()它接受一个字符串或(串)的元组。
  • string.endswith()

在pymongo:

  • find_one()可以接受一个字典对象查找,或将使用另一个其他对象作为id。

对不起,我不知道更多,但我认为有很多方法的例子,根据给定的参数行为不同。这是不强制类型的美丽的一部分。

+1

-1类型检查是__never__ pythonic。检查接口但不输入。在标准库中发生类型检查的程度将被视为一个缺陷,而不是一个例子。 – aaronasterling 2010-09-05 01:52:45

+0

@aaronasterling:我认为'从不'有点强。在'__init__'方法中怎么样?例如,你可以从另一个'bytearray',一个整数,一个可迭代的整数,一个'memory_view',一个字符串或者(仅用于Python 3)和一个'bytes'对象构造'bytearray'。所有这些都来自于最近添加的内置类型! – 2010-09-05 06:15:53

+0

@Scott:你需要在那里使用类型检查的事实不会让类型检查更多的Pythonic。 – 2010-09-05 08:00:23

1

获得这种功能的更多pythonic方法是尝试并以优选的方式使用它(无论这可能意味着什么),如果参数不支持,请尝试替代方法。

Here'd两种方式做到这一点:

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() 

但那是一种令人讨厌的。这里的如何我通常这样做:

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() 

在现实中,我会检查的实际属性取决于这些评论会发生什么,我会更喜欢来检查,我实际使用的属性。

+0

我实际上会说你的第一种方法更好。 – detly 2010-09-05 07:29:53

+0

将参数传递给您关心的类型的构造函数,并从中捕获任何异常。 – 2010-09-05 07:46:45

+0

第二个例子是更'pythonic',因为它检查界面,而不是类型。所以我会说这是你的正确答案。我认为有关'从不检查'的教条有点愚蠢。 – Amala 2010-09-05 11:32:39

5

不,这里检查的类型不是Pythonic。另一种选择,如果你不喜欢多种方法是坚持使用一个方法,但使用多个参数:

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 

当使用的目的是作为一个具有多个方法一样明显:

employee1 = x.find(name="John Smith") 
employee2 = x.find(employee_number=90210)