【问题标题】:Extending a (native) class in Python在 Python 中扩展(本机)类
【发布时间】:2012-08-27 04:36:37
【问题描述】:

我正在尝试从 Python Imaging Library 向 Image 类添加一个新方法。我想要一个名为 DilateImage 的新类,它与原始 Image 类完全一样,除了它还包括一个 dilate() 函数,该函数在类实例上执行时会修改它。这是我的示例代码(不起作用):

import Image

def DilateImage(Image):
   def dilate(self):
      imnew = self.copy()
      sourcepix = imnew.load()
      destpix = self.load()

      for y in range(self.size[1]):
         for x in range(self.size[0]):
            brightest = 255
            for dy in range(-1,2):
               for dx in range(-1,2):
                  try:
                     brightest = min(sourcepix[x+dx,y+dy], brightest)
                  except IndexError:
                     pass
            destpix[x, y] = brightest

当我尝试使用这种新的类类型来创建一个使用基类的“打开”函数的实例时,它失败了:

>>> test = DilateImage.open("test.jpg")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'open'

【问题讨论】:

    标签: python class python-imaging-library extend


    【解决方案1】:

    我不知道这是否是最近的更改,但在与以前的 cmets 相同的样式中,您实际上可以修改/添加到现有类。例如:

    class list(list):
        #Create an Empty List
        def empty(N:int):
            """Create an N-Long Empty List"""
            return [None]*int(N)
    

    这不会改变 'list' 类的现有功能,但会添加一个执行此操作的方法:

    >>> list.empty(5)
    [None, None, None, None, None]
    

    您也可以对其他类执行此操作,因此提供示例代码以更直接地回答您的问题:

    #Import Libraries
    import Image
    
    #Add Methods to Image
    class Image(Image):
        def dilate(*args, **kwargs):
            ...
    

    我不确定这是否被推荐,但你能做到这一点很酷!

    【讨论】:

      【解决方案2】:

      您的代码有两个问题。其中之一已经指出,在定义类时,需要使用class 关键字,因为def 关键字定义了一个函数或一个方法。

      第二个问题是调用

      import Image
      

      会将名为 Image 的 模块 导入到 Image 命名空间中,以便您的代码中的 Image 将引用该模块。它不是对象或类,所以

      class MyImage(Image)
      

      将尝试从 模块 派生一个新类,这将失败。

      Image 模块包含一个名为Image 的类。将模块导入Image 命名空间后,您可以将此类称为Image.Image。要扩展此类,您可以这样做:

      import Image
      
      class MyImage(Image.Image)
      

      为了减少混淆,您还可以将 Image 模块导入不同的命名空间:

      import Image as Img
      
      class MyImage(Img.Image)
      

      问题在于,PIL 似乎并未设计为允许对 Image 类进行这种扩展。它的模块提供了一堆函数,它们将 Image 的实例作为参数并返回 Image 的新实例。实际 Image 类中只有几个方法。因此,您可能想要做的是编写一个函数,该函数将采用 Image 的实例并创建 Image 的新实例,而不是通过新方法扩展 Image 类。例如,像这样:

      import Image
      
      def DilateImage(source):
            dest = source.copy()
            sourcepix = source.load()
            destpix = dest.load()
      
            for y in range(source.size[1]):
               for x in range(source.size[0]):
                  darkest = 255
                  for dy in range(-1,2):
                     for dx in range(-1,2):
                        try:
                           darkest = min(sourcepix[x+dx,y+dy], darkest)
                        except IndexError:
                           pass
                  destpix[x, y] = darkest
      
            return dest
      
      
      im1 = Image.open("test.jpg")
      
      img2 = DilateImage(im1)
      
      img2.show()
      

      【讨论】:

        【解决方案3】:

        当您应该使用class 关键字时,您将DilateImage 定义为一个函数(通过使用def)。因此AttributeError,因为函数没有open 属性。

        【讨论】:

        • 谢谢,我不知道我是怎么错过的。正如我在另一个答案的评论中提到的那样,现在我得到另一个错误,我不知道如何解释:Traceback (most recent call last):File "piltest.py", line 3, in &lt;module&gt;class DilateImage(Image):TypeError: Error when calling the metaclass basesmodule.__init__() takes at most 2 arguments (3 given)
        【解决方案4】:

        使用

        class DilateImage(Image)
        

        不是

        def DilateImage(Image)
        

        【讨论】:

        • 谢谢。现在我在“类”行收到以下错误:Traceback (most recent call last):File "piltest.py", line 3, in &lt;module&gt;class DilateImage(Image):TypeError: Error when calling the metaclass basesmodule.__init__() takes at most 2 arguments (3 given)
        • 这里,“Image”不是一个类,它是你要导入的模块的名称。该模块包含一个名为“Image”的类。您可以尝试通过说class DilateImage(Image.Image) 来扩展该类,但是,open() 函数不是Image.Image 类的方法,而只是Image 模块中的一个函数,并将返回@987654332 的实例@。据我所知,PIL 并没有真正设计为以这种 OO 方式进行扩展。
        • @JanHlavacek 您应该将其发布为答案。
        • 我想你是对的。一开始我不认为它回答了这个问题,但现在当我再次阅读它时,我想我可以把它变成一个答案。
        猜你喜欢
        • 2010-09-07
        • 1970-01-01
        • 2010-09-26
        • 1970-01-01
        • 1970-01-01
        • 2014-06-06
        • 2011-01-20
        • 2021-12-08
        • 2015-01-27
        相关资源
        最近更新 更多