首页 > 解决方案 > 如何在 python 中将父类的实例转换为其子类之一?

问题描述

我对 python 很陌生,在玩PIL. 我曾写过:

from PIL import Image

class FImage(Image.Image):
    def foo(self):

我正在使用该Image.open()函数来初始化图像,但我不知道如何将其转换为FImage. 这是可行的吗?如果是这样,我将如何去做?

只是为了清除某些内容而进行的编辑,ImageinImage.open()指的是.py文件,而不是类本身。

标签: pythonooppython-imaging-library

解决方案


由于open()它是Image模块的函数而不是Image.Image类的方法,因此您不能只覆盖它并让它返回 FImage。

但是,您可以open()在自己的 FImage 模块中定义一个函数,而不是继承自Image.Image(这也意味着实现其抽象方法),您可以封装一个Image.Image实例并将任何您无法处理的引用传递给它:

from PIL import Image


class FImage:
    def __init__(self, img: Image.Image):
        self._img = img

    def foo(self):
        print(f'Hello foo, from {type(self)}')

    def __getattr__(self, attr):
        return getattr(self._img, attr)


def open(*args, **kwargs):
    return FImage(Image.open(*args, **kwargs))


# calling your open, not Image.open directly, passing all parameters
fimg = open('test.png')

# just showing the resulting fimg is an FImage, with all Image functionality
size = 16, 16
fimg.thumbnail(size)
fimg.save("test.icon.png", "PNG")

# but also any FImage functionality
fimg.foo()

顺便说一句,如果您不想Image用对您自己的FImage(?) 模块的引用替换对模块的引用,我非常建议更改替换open()函数的名称,因为open会隐藏内置函数。枕头不应该一开始就用它……也许fopen()吧?

请注意,FImage我提出的解决方案在技术上不是Image.Image. 无论如何,您都可以决定继承,但是您也必须实现抽象方法。

最后,在我看来,这是 Pillow 模块中的一个设计缺陷。如果他们为该类创建了open()一个类方法Image,您将能够覆盖它并更轻松地创建Image后代。无论出于何种原因,Pillow 的作者似乎都希望您不要创建后代。


推荐阅读