【问题标题】:Pythonic Way To Check for A Parameter Type检查参数类型的 Pythonic 方法
【发布时间】:2014-01-07 12:19:12
【问题描述】:

我正在为工作做一个小项目,并制作了一些类和方法。其中一个类别代表我们库存中的一个货架,另一个类别代表货架上的每个垃圾箱。我有一种方法可以将新箱添加到架子上,并且我添加了一些逻辑以确保在将其添加到架子之前将其传递给 Location 对象(现在我在将所有内容移动到数据库之前在开发时使用列表)。

但是,我刚刚在一本 Python 书籍中读到,通常最好在出现异常时处理它们,而不是添加额外的代码。我删除了逻辑以查看我会得到什么错误,但我没有得到任何允许使用字符串代替 Location 对象的内容。

有没有更 Pythonic 的方式来强制参数是什么类型?

我的书架上有什么:

class CrossDock:
locations = []

def add_location(self, location):
    if isinstance(location, Location): #if this is commented out it will take what ever is passed to it
        self.locations.append(location)
    else:
        print("location parameter must be of type: Location. Parameter is of type" + str(type(location)))

有没有办法使用 try/except 块来做到这一点?

【问题讨论】:

  • 注意:您的 locations 字段是类字段,而不是实例字段。所有CrossDock 实例将共享同一个副本。要解决此问题,请定义一个 __init__ 方法并在其中设置 self.locations
  • 只有一个 CrossDock 实例,我还应该将位置字段放在 init 方法中吗?
  • 是的。它在概念上属于那个实例;如果您要制作更多 CrossDocks,您会希望它们有单独的列表。

标签: python class exception-handling parameter-passing


【解决方案1】:

向调用者传播异常。当他们滥用该类时,这会强制您的类的用户修复无效类型。打印没有用,因为它不强制执行接口契约。

class CrossDock(object):
    def __init__(self):
        self.locations = []

    def add_location(self, location):
        if isinstance(location, Location):
            self.locations.append(location)
        else:
            raise TypeError("location must be Location, got: " +
                            repr(type(location)))

【讨论】:

  • 我认为您有一些 Java 泄漏,并且您在 __init__ 上缺少括号。此外,这不是一个错误,但我建议让 CrossDock 继承自 object,所以它是一个新型类。
  • 我已根据@user2357112 的评论使其成为有效的 Python,并对其进行了更改以提出更惯用的TypeError。随意回滚
【解决方案2】:

最pythonic的方法是不检查类型...一切都是鸭子类型的。

What's the canonical way to check for type in python?

【讨论】:

    【解决方案3】:

    当您尝试使用 Location 实例但在那里发现了其他东西时,您最终可能会在代码中的其他地方发生异常。当参数来自不可靠的来源时,检查参数并没有错。这会将异常置于问题的根源,而不是在代码中可能更难诊断的次要位置。

    你可能会做你所拥有的,只是引发一个异常而不是打印错误。

    def add_location(self, location):
        if not isinstance(location, Location):
            tmpl = "location parameter must be of type: Location, got %s"
            raise TypeError(tmpl % str(type(location)))
        ... do other processing here after guarding check ...
    

    如果您无法控制调用代码,这种类型的检查是最合适的。如果你只是想捕捉你自己犯的一个编程错误,你可以使用一个断言:

    def add_location(self, location):
        assert isinstance(location, Location), "location must be of type: Location"
        ... do other processing here
    

    反对进行参数类型检查的建议是为了让您的代码具有最大的灵活性,例如如果有人想传入一个与 location 具有相同方法的对象。即使代码可以工作,检查硬编码类型也会引发异常。

    【讨论】:

      【解决方案4】:

      在 try/except 块中使用 assert

      class Location():
          pass
      
      class CrossDock:
          locations = []
      
          def add_location(self, location):
              try:
                  assert(isinstance(location, Location))
                  self.locations.append(location)
                  print("added")
              except AssertionError:
                  print("error: Parameter is of type" + str(type(location)))
      
      
      c = CrossDock()
      loc = Location()
      c.add_location("2")
      c.add_location(loc)
      

      第一次调用add_location 会失败

      location parameter must be of type: Location. Parameter is of type<type 'str'>
      
      added
      

      【讨论】:

      • 断言严格用于调试;它们不应该用于验证作为公共接口一部分的方法的先决条件,因为它们可以被禁用。此外,捕获异常并打印错误消息远不如让它传播有用。
      • OP 要求尝试/例外,这就是我发现异常的原因。打印是为了演示,符合 OP 问题中的操作。
      • 我有什么作品,但我不确定这是否是阅读后的最佳方式。所以我有一些可行的方法,但我想知道它是否/什么是最好的前进方式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-05
      • 2020-02-09
      • 2023-03-09
      • 2020-04-01
      • 2021-12-28
      • 2019-05-04
      相关资源
      最近更新 更多