检查isinstance(..., io.IOBase)
似乎是'正确'的方法来确定对象是否像'文件一样'。
但是,在定义我自己的类文件类时,它似乎不起作用:
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'
我怎样才能让它发挥作用?
答案 0 :(得分:1)
isinstance(obj, some_class)
只是迭代obj的继承链,寻找some_class
。因此,isinstance(file_like, io.IOBase)
将是假的,因为您的file_like
类在其祖先中没有io.IOBase
。 file_like
未指定显式父级,因此它仅隐式继承自object
。除了file_like
本身之外,这是唯一一个对file_like
实例isinstance()
测试为正的课程。
您在file_like
中所做的是定义类文件对象所期望的方法,而不是从任何特定的“类文件”类继承。这种方法称为duck-typing,它在动态语言中有许多优点,尽管它在其他方面(例如Ruby)比Python更受欢迎。尽管如此,如果您提供的file_like
实例跟随鸭子类型,它应该可以工作,前提是您的file_like
确实“像文件一样嘎嘎”,即表现得像文件一样充足在接收端使用时会导致错误。
当然,如果接收端不遵循鸭子类型,例如尝试按isinstance()
检查类型,则此方法将失败。
最后,一个小小的风格:如果它没有明确地继承任何东西,就不要把空的parens放在一个类上。它们是多余的。
答案 1 :(得分:1)
检查isinstance(something, io.IOBase)
仅检查something
是io.IOBase
的实例还是从中派生的类 - 所以我不明白你在哪里错误地认为它是“纠正“确定对象是否像文件一样”的方法。
另一种方法是使用抽象基类。 Python有一些built-in ones,但目前没有一个可用于isinstance()
的“类文件”。但是,您可以使用PEP 3119中列出的abc
模块来定义自己的模块。
The Python Module of the Week网站管理员good explanation使用abc
模块执行此操作。这个问题answer的高评价Correct way to detect sequence parameter?显示了定义自己的ABC的类似方式。
为了说明将它应用于您的案例,您可以定义一个像这样的ABC,其所有方法都是抽象的 - 从而强制派生类定义所有这些以便实例化:
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
。)
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
您甚至可以通过向新元类注册它们来添加现有类:
import io
print(isinstance(io.IOBase(), ABCFileLike)) # -> False
ABCFileLike.register(io.IOBase)
print(isinstance(io.IOBase(), ABCFileLike)) # -> True