我如何从同一个 class 调用前一个实例的实例?

How can I call an instance on a former instance from the same class?

如果这个问题有明显的解决方案或者是重复的,我提前道歉。

我有一个class如下:

class Kernel(object):
    """ creates kernels with the necessary input data """
    def __init__(self, Amplitude, random = None):
        self.Amplitude = Amplitude
        self.random = random
        if random != None:
            self.dims = list(random.shape)

    def Gaussian(self, X, Y, sigmaX, sigmaY, muX=0.0, muY=0.0):
        """ return a 2 dimensional Gaussian kernel """
        kernel = np.zeros([X, Y])
        theta = [self.Amplitude, muX, muY, sigmaX, sigmaY]
        for i in range(X):
            for j in range(Y):
                kernel[i][j] = integrate.dblquad(lambda x, y: G2(x + float(i) - (X-1.0)/2.0, \
                                                 y + float(j) - (Y-1.0)/2.0, theta), \
                                                 -0.5, 0.5, lambda y: -0.5, lambda y: 0.5)[0]
        return kernel

它基本上只是创建了一堆卷积核(我只包含了第一个)。

我想向这个 class 添加一个实例(方法?),这样我就可以使用类似

的东西
conv = Kernel(1.5)
conv.Gaussian(9, 9, 2, 2).kershow()

并使用 Matplotlib 弹出数组。我知道如何编写这个实例并用 Matplotlib 绘制它,但我不知道如何编写这个 class 以便对于每种方法我都希望拥有这种额外的能力(即 .kershow()),我可以这样称呼它。

认为我可以使用装饰器吗?但我以前从未使用过它们。我该怎么做?

我会这样做:

class Kernel(object):

    def __init__ ...

    def Gaussian(...):
        self.kernel = ...
        ...
        return self  # not kernel

    def kershow(self):
        do_stuff_with(self.kernel)

基本上 Gaussian 方法不是 return numpy 数组,它只是将它存储在 Kernel 对象中,以便在 class 的其他地方使用。特别是 kershow 现在可以使用它了。 return self 是可选的,但允许在您编写

的地方使用您想要的接口类型
conv.Gaussian(9, 9, 2, 2).kershow()

而不是

conv.Gaussian(9, 9, 2, 2)
conv.kershow()

您要找的东西的名称是函数或 method chaining

字符串是 Python 中的一个很好的例子。因为字符串是不可变的,所以每个字符串方法 return 都是一个新字符串。因此,您可以在 return 值上调用字符串方法,而不是存储中间值。例如:

lower = '       THIS IS MY NAME: WAYNE      '.lower()
without_left_padding = lower.lstrip()
without_right_padding = without_left_padding.rstrip()
title_cased = without_right_padding.title()

你可以这样写:

title_cased = '       THIS IS MY NAME: WAYNE      '.lower().lstrip().rstrip().title()

当然你真的会这样做.strip().title(),但这是一个例子。

因此,如果您想要一个 .kernshow() 选项,那么您需要在任何 return 上包含该方法。在你的情况下,numpy 数组没有 .kernshow 方法,所以你需要 return 一些东西。

您的选择主要是:

  • numpy 数组的子class
  • 一个class包裹了numpy数组

我不确定 subclassing numpy 数组涉及什么,所以我将坚持以后者为例。您可以使用内核 class,或者创建第二个 class.

Alex 提供了一个使用您的内核 class 的示例,但您也可以像这样使用另一个 class:

class KernelPlotter(object):
    def __init__(self, kernel):
        self.kernel = kernel

    def kernshow(self):
        # do the plotting here

那么您几乎可以遵循您现有的代码,但您会 return KernelPlotter(kernel).

而不是 return kernel

您选择哪个选项实际上取决于什么对您的特定问题域有意义。


函数链的另一个姊妹函数称为 fluent interface,它基本上是函数链,但目标是使界面读起来像英语。例如你可能有这样的东西:

Kernel(with_amplitude=1.5).create_gaussian(with_x=9, and_y=9, and_sigma_x=2, and_sigma_y=2).show_plot()

虽然显然可以 some problems 以这种方式编写代码。