在Python中断言变量类型的正确方法


72

在使用函数时,我希望确保变量的类型符合预期。怎么做对?

这是一个伪函数示例,尝试在继续其作用之前执行此操作:

def my_print(begin, text, end):
    """Print 'text' in UPPER between 'begin' and 'end' in lower

    """
    for i in (begin, text, end):
        assert isinstance(i, str), "Input variables should be strings"
    out = begin.lower() + text.upper() + end.lower()
    print out

def test():
    """Put your test cases here!

    """
    assert my_print("asdf", "fssfpoie", "fsodf")
    assert not my_print("fasdf", 33, "adfas")
    print "All tests passed"

test()

断言是正确的方法吗?我应该改用try / except吗?

此外,我断言的一组测试似乎无法正常工作:S

谢谢pythoneers


10
我认为您遇到了Python的最大弱点:没有正式的方法可以在需要时指定类型。此问题的次要方面是您必须手动检查类型(如您的问题所示)。更大的问题是您的工具无法为您提供帮助。如果Python仅支持动态类型化,而且还可以在不需要动态类型时指定类型,则Python将是理想的语言。
汤姆(Tom)2010年

2
2018年的一条注释:即使typingpython 3.6,mypy和其他工具中的模块问世,上述声明也是如此:拥有静态类型的python很棒。
Evgeny

Answers:


65

isinstance内置的是,如果你真的必须的首选方式,但更重要的是要记住Python的座右铭:“它更容易请求原谅比许可” - )(它实际上是格雷斯穆雷Hopper的喜欢的格言;-)!即:

def my_print(text, begin, end):
    "Print 'text' in UPPER between 'begin' and 'end' in lower"
    try:
      print begin.lower() + text.upper() + end.lower()
    except (AttributeError, TypeError):
      raise AssertionError('Input variables should be strings')

顺便说一句,顺便说一句,该函数可以在Unicode字符串上正常工作-无需任何额外的努力!-)


9
assert有时对于仅在开发阶段需要进行的完整性检查很有用(不是在优化的生产代码中,它不会进行优化)—因此,不对有效输入进行检查(您必须执行其他操作),而是自行进行完整性检查逻辑(循环变量,类不变式等)-当然与类型无关。第三方测试框架py.test使用assert标准unittest使用assertEqual&c之类的方法的方式。
Alex Martelli'4

5
my_print函数实际上并不关心参数是否为str或unicode类型。它只是在乎的论据有lower()upper()__add__()方法。这被称为鸭子类型(即使它实际上根本不是鸭子,它看起来像鸭子,说话像鸭子(即,具有相同的方法),这是python的首选方法。如果由于传入的参数类型错误而引发异常,则应引发TypeError

3
@ 007brendan,en.wikipedia.org / wiki / Duck_typing在“历史记录”下为我提供了最早可追溯使用“鸭子打字”一词的信息(10年前,当我还是Python的初学者时)。指向,我实际上并没有使用该帖子中的短语(我做了很多鸭子式的类比,但大多使用更传统的术语,例如“类型转换”),无论如何,我认为这使我对这个概念相当熟悉;-)。我同意类型错误是一个很好的匹配(try / except可以将属性错误(总是杂物)转换为类型错误)。
亚历克斯·马丁里

1
@Alex,我在许多我自己的编程中都使用了您的建议和解决方案,因此我意识到您在所有这些领域都拥有令人难以置信的丰富知识和经验(我什至在使用您自己的类比!)。我的帖子旨在为OP提供更多有关您的解决方案为何为规范解决方案的背景信息。

1
@strpeter,这几天实际上城里有个新孩子,我把它称为“鹅打字”(对照抽象基类进行检查),但是它对字符串没有任何帮助,因此“鸭子打字”在大多数地方仍然占统治地位:- )
Alex Martelli 2015年

18

您可能想为2.6版的Python尝试此示例。

def my_print(text, begin, end):
    "Print text in UPPER between 'begin' and 'end' in lower."
    for obj in (text, begin, end):
        assert isinstance(obj, str), 'Argument of wrong type!'
    print begin.lower() + text.upper() + end.lower()

但是,您是否考虑过让函数自然失败?


我有点逆行,仍然使用2.6:P感谢您的'isinstance()'函数。
莫洛克

10

做事type('')实际上等效于strtypes.StringType

因此type('') == str == types.StringType将评估为“ True

请注意,如果仅通过这种方式检查类型,则仅包含ASCII的Unicode字符串将失败,因此您可能想要执行类似assert type(s) in (str, unicode)或的操作assert isinstance(obj, basestring),后者可能是007Brendan的注释中建议的,并且可能是首选。

isinstance() 如果您要询问对象是否是类的实例,则很有用,例如:

class MyClass: pass

print isinstance(MyClass(), MyClass) # -> True
print isinstance(MyClass, MyClass()) # -> TypeError exception

但对于基本类型,例如strunicodeintfloatlong等要求type(var) == TYPE将工作确定。


2
您可以做-断言isinstance(obj,basestring)-str和unicode都继承自basestring,因此这对两者都适用。

感谢您的建议-我已将其添加到答案中。
cryo 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.