简体   繁体   English

接受python函数中的不同类型?

[英]Accept different types in python function?

I have a Python function that does a lot of major work on an XML file. 我有一个Python函数,它在XML文件上做了很多重要的工作。

When using this function, I want two options: either pass it the name of an XML file, or pass it a pre-parsed ElementTree instance. 使用此函数时,我需要两个选项:将XML文件的名称传递给它,或者将其传递给预先解析的ElementTree实例。

I'd like the function to be able to determine what it was given in its variable. 我希望函数能够确定它在变量中给出的内容。

Example: 例:

def doLotsOfXmlStuff(xmlData):
    if (xmlData != # if xmlData is not ET instance):
        xmlData = ET.parse(xmlData)
    # do a bunch of stuff
    return stuff

The app calling this function may need to call it just once, or it may need to call it several times. 调用此函数的应用程序可能只需要调用一次,或者可能需要多次调用它。 Calling it several times and parsing the XML each time is hugely inefficient and unnecessary. 多次调用它并每次解析XML都是非常低效和不必要的。 Creating a whole class just to wrap this one function seems a bit overkill and would end up requiring some code refactoring. 创建一个完整的类只是为了包装这个函数似乎有点矫枉过正,最终需要一些代码重构。 For example: 例如:

ourResults = doLotsOfXmlStuff(myObject)

would have to become: 必须成为:

xmlObject = XMLProcessingObjectThatHasOneFunction("data.xml")
ourResult = xmlObject.doLotsOfXmlStuff()

And if I had to run this on lots of small files, a class would be created each time, which seems inefficient. 如果我必须在许多小文件上运行它,每次都会创建一个类,这似乎效率低下。

Is there a simple way to simply detect the type of the variable coming in? 是否有一种简单的方法可以简单地检测变量的类型? I know a lot of Pythoners will say "you shouldn't have to check" but here's one good instance where you would. 我知道很多Pythoners会说“你不应该检查”,但这里有一个很好的例子。

In other strong-typed languages I could do this with method overloading, but that's obviously not the Pythonic way of things... 在其他强类型语言中,我可以通过方法重载来实现这一点,但这显然不是Pythonic的方式......

This is a fairly normal pattern (eg Python function that accepts file object or path ). 这是一种相当普通的模式(例如,接受文件对象或路径的Python函数 )。 Just use isinstance : 只需使用isinstance

def doLotsOfXmlStuff(xmlData):
    if not isinstance(xmlData, ET):
        xmlData = ET.parse(xmlData)
    ...

If you need to do cleanup (eg closing files) then calling your function recursively is OK: 如果你需要进行清理(例如关闭文件),那么递归调用你的函数就可以了:

def doLotsOfXmlStuff(xmlData):
    if not isinstance(xmlData, ET):
        xmlData = ET.parse(xmlData)
        ret = doLotsOfXmlStuff(xmlData)
        ... # cleanup (or use a context manager)
        return ret
    ...

The principle of "duck typing" is that you shouldn't care so much about the specific type of an object but rather you should check whether is supports the APIs in which you're interested. “鸭子打字”的原则是你不应该太在意对象的具体类型,而应该检查是否支持你感兴趣的API。

In other words if the object passed to your function through the xmlData argument contains some method or attribute which is indicative of an ElementTree that's been parsed then you just use those methods or attributes ... if it doesn't have the necessary attribute then you are free to then pass it through some parsing. 换句话说,如果通过xmlData参数传递给您的函数的对象包含一些指示已解析的ElementTree的方法或属性,那么您只需使用这些方法或属性...如果它没有必要的属性那么您然后可以自由地通过一些解析。

So functions/methods/attributes of the result ET are you looking to use? 那么你想要使用结果ET的函数/方法/属性吗? You can use hasattr() to check for that. 您可以使用hasattr()来检查它。 Alternatively you can wrap your call to any such functionality with a try: ... except AttributeError: block. 或者,您可以通过try: ... except AttributeError: block来调用任何此类功能。

Personally I think if not hasattr(...): is a bit cleaner. 我个人认为if not hasattr(...):有点清洁。 (If it doesn't have the attribut I want, then rebind the name to something which has been prepared, parsed, whatever as I need it). (如果它没有我想要的属性,那么将名称重新绑定到已经准备,解析的内容,无论我需要什么)。

This approach has advantages over isinstance() because it allows users of your functionality to pass references to objects in their own classes which have extended ET through composition rather than inheritance. 这种方法优于isinstance()因为它允许您的功能用户将引用传递给自己的类中的对象,这些对象通过组合而不是继承来扩展ET。 In other words if I wrap an ET like object in my own class, and expose the necessary functionality then I should be able to pass reference s to your function and have you just treat my object as if it were a "duck" even if it wasn't a descendant of a duck. 换句话说,如果我在我自己的类中包装一个类似ET的对象,并公开必要的功能,那么我应该能够将引用传递给你的函数,让你只需将我的对象看作是一个“鸭子”,即使它不是鸭子的后代。 If you need feathers, a bill, and webbed feet then just check for one of those and try to use the rest. 如果您需要羽毛,帐单和蹼足,那么只需检查其中一个并尝试使用其余部分。 I may be a black box containing a duck and I may have provided holes through which the feet, duck-bill, and feathers are accessible. 我可能是一个装有鸭子的黑匣子,我可能已经提供了洞,脚,鸭嘴和羽毛都可以穿过。

您可以使用isinstance来确定变量的类型。

Can you try to put an if statement to check the type and determine what to run from there? 您是否可以尝试使用if语句来检查类型并确定从那里运行的内容?

if type(xmlData).__name__=='ElementTree':
    #do stuff
else: 
    #do some other stuff

I think you can just compare the data types: 我想你可以比较数据类型:

if (xmlData.dtype==something):
    call Function1
else:
    call Function2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM