关于python:如何使用“ isinstance(cls,io.IOBase)”使类似文件的类工作?

How to make a file-like class work with “isinstance(cls, io.IOBase)”?

似乎检查isinstance(..., io.IOBase)是确定对象是否类似于文件的"正确"方法。

但是,在定义自己的类似文件的类时,它似乎不起作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import io

class file_like():

    def __init__(self):
        pass

    def write(self, line):
        print("Written:", line)

    def close(self):
        pass

    def flush(self):
        pass

print(isinstance(file_like(), io.IOBase))
# Prints 'False'

我该如何运作?


检查isinstance(something, io.IOBase)仅检查somethingio.IOBase的实例还是从其派生的类—因此,我不明白您在哪里错误地认为这是确定对象是否为"正确"方式的误解。"类似文件"。

一种不同的方法是使用抽象基类。 Python有许多内置的,但是目前还没有一个可以与isinstance()一起使用的"类似文件"的文件。但是,您可以使用PEP 3119中概述的abc模块定义自己的模块。

每周的Python模块Webiste很好地解释了如何使用abc模块执行类似的操作。而这个对问题的高度评价的答案是正确的检测序列参数的方法吗?显示了定义自己的ABC的类似方法。

为了说明如何将其应用于您的案例,您可以定义一个这样的ABC及其所有抽象方法,从而强制派生类定义所有它们以便实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from abc import ABCMeta, abstractmethod

class ABCFileLike(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self): pass

    @abstractmethod
    def write(self, line): pass

    @abstractmethod
    def close(self): pass

    @abstractmethod
    def flush(self): pass

然后,您可以从中派生自己的具体类,并确保提供所有抽象方法的实现。 (如果未全部定义它们,则尝试进行实例化时将引发TypeError。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class FileLike(ABCFileLike):
   """ Concrete implementation of a file-like class.
        (Meaning all the abstract methods have an implementation.)
   """

    def __init__(self):
        pass

    def write(self, line):
        print("Written:", line)

    def close(self):
        pass

    def flush(self):
        pass

print(isinstance(FileLike(), ABCFileLike))  # -> True

您甚至可以通过向新的元类注册现有的类来添加现有类:

1
2
3
4
5
6
import io

print(isinstance(io.IOBase(), ABCFileLike))  # -> False

ABCFileLike.register(io.IOBase)
print(isinstance(io.IOBase(), ABCFileLike))  # -> True

isinstance(obj, some_class)只是迭代obj的继承链,寻找some_class。因此,isinstance(file_like, io.IOBase)将是错误的,因为您的file_like类的祖先中没有io.IOBasefile_like未指定显式父项,因此它仅隐式继承自object。这是唯一的类-除了file_like本身之外-对于使用isinstance()file_like实例将测试为阳性。

file_like中,您正在做的事情是定义类似文件的对象所期望的方法,而不是从任何特定的"类似文件"的类中继承。这种方法称为鸭子输入法,它在动态语言中有许多优点,尽管它在其他语言(例如Ruby)中比Python更为流行。但是,如果您提供的file_like实例遵循鸭式输入,只要file_like实际上确实"像文件一样嘎嘎",即行为像文件一样,不会在使用时引起错误,它就可以工作在接收端。

当然,如果接收端未遵循鸭式输入,例如像您在此处那样尝试通过isinstance()检查类型,则此方法将失败。

最后,一个小小的风格:不要在类中没有显式继承任何空括号。它们是多余的。