繁体   English   中英

在 Python 中,如何继承和覆盖类实例上的方法,将这个新版本分配给与旧版本相同的名称?

[英]In Python, how can I inherit and override a method on a class instance, assigning this new version to the same name as the old one?

在Matplotlib,一个常见的问题是之间的不必要的白线Patch对象与绘制pcolorpcolormeshcontourf (见这个问题,并为前两种这个问题,后者)。

我试图通过使用MethodType向我的Axes类/子类实例添加新方法来自动修复此MethodType 我这样做而不是子类化只是因为我想通过将GridSpec对象的切片传递给Figure实例上的add_subplot方法来生成Axes ,而且我不知道如何使用某种子类化matplotlib.axes.Subplot (但我欢迎建议)。 下面是一些示例代码:

from types import MethodType
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

f = plt.figure()
gs = GridSpec(2,1)
ax = f.add_subplot(gs[0,0])

def _pcolormesh(self, *args, **kwargs):
    p = self.pcolormesh(*args, **kwargs)
    p.set_edgecolor('face')
    p.set_linewidth(0.2) # Will cover white lines, without making dot in corner of each square visible
    return p

def _contourf(self, *args, **kwargs):
    c = self.contourf(*args, **kwargs)
    for _ in c.collections:
        _.set_edgecolor('face')
    return c

ax.mypcolormesh = MethodType(_pcolormesh, ax)
ax.mycontourf = MethodType(_contourf, ax)

在最后一行中,我希望能够编写ax.pcolormesh而不是ax.mypcolormesh ,但这会引发RecursionError ,因为_pcolormesh调用原始方法名称...现在别名为它自己。

那么,如何访问此Axes实例上的方法、覆盖它并保留原始名称?

高效的解决方案

由于单独替换每个轴的方法比使用简单函数要多得多,因此最有效的方法是使用相应的函数创建 Python 文件myhacks.py

def pcolormesh(ax, *args, **kwargs):
    p = ax.pcolormesh(*args, **kwargs)
    p.set_edgecolor('face')
    p.set_linewidth(0.2)
    return p

并在需要 pcolormesh 的改进版本时使用它:

import matplotlib.pyplot as plt
import myhacks as m
# ...other imports

fig, ax = plt.subplots()
m.pcolormesh(ax, other_arguments)

这对于已经创建的文件也很有效,在其中可以简单地搜索替换"ax.pcolormesh(""m.pcolormesh(ax," (如有必要,使用正则表达式表示可能的其他轴名称)。

学术解决方案

当然可以将matplotlib.axes.Axes子类化以包含所需的函数。 由于这没有真正的好处,除了知道如何去做之外,我将其称为“学术解决方案”。

所以,我们可以再次为我们的自定义类创建一个文件myhacks.py ,将自定义类注册为 Matplotlib 的投影,

from matplotlib.axes import Axes
from matplotlib.projections import register_projection

class MyAxes(Axes):
    name = 'mycoolnewaxes'
    def pcolormesh(self,*args, **kwargs):
        p = Axes.pcolormesh(self,*args, **kwargs)
        p.set_edgecolor('face')
        p.set_linewidth(0.2)
        return p

register_projection(MyAxes)

并通过导入它并使用投影创建轴来使用它:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import myhacks as m

fig = plt.figure()
gs = GridSpec(2,1)
ax = fig.add_subplot(gs[0,0], projection='mycoolnewaxes')

z = np.random.rand(10,13)
ax.pcolormesh(z)

plt.show()

嗯...我解决了,有点。 只需使用

ax._contourf = ax.contourf 

它保存了旧方法的副本,然后,例如,

def _contourf(self, *args, **kwargs):
    c = self._contourf(*args, **kwargs)
    for _ in c.collections:
        _.set_edgecolor('face')
    return c
ax.contourf = MethodType(_contourf, ax)

它分配新方法来调用旧方法的副本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM