【问题标题】:MATLAB: overriding table() methodsMATLAB:覆盖 table() 方法
【发布时间】:2023-03-18 23:07:01
【问题描述】:

设置 Win7 64b、R2015b、16 GB RAM、CPU i7-2700

table() 是一个fundamental Matlab class,它也是密封,因此我不能继承它。

我想修复这个类的一些方法并添加新的方法。 例如,table.disp() 从根本上被破坏了,例如不要尝试disp(table(rand(1e7,1))),或者忘记命令窗口中的;。该变量在 RAM 中仅占用 76 MB,但显示没有缓冲,它会停止您的系统!

  1. 我可以在不写入matlabroot\toolbox\matlab\datatypes\@table 的情况下覆盖table.disp() 这样的方法吗?
  2. 我可以用C:\MATLAB\@table\ismatrixlike.m 下的新方法扩展表类吗?为什么我会得到

    ismatrixlike(table)
    Undefined function 'ismatrixlike' for input arguments of type 'table'. 
    

    显然,我做到了

    addpath C:\MATLAB\
    rehash toolboxcache
    

    我也试过clear all

    路径优先于matlabroot,但缺少table.m 类定义。如果我将本机类定义添加到C:\MATLAB\@table,那么我可以运行我的新方法(在clear all 之后)。然而:

    >> methods(table)
    
    Methods for class table:
    
    classVarNames   ismatrixlike    table           varfun          
    convertColumn   renameVarNames  unstack      
    

    仅列出新 \@table 文件夹中的方法,即使(某些)旧方法仍然有效,例如

    size(table)
    

    这部分解决了问题,因为现在原生的\@table\private 文件夹无法再访问,因此许多原生方法都被破坏了!

我为什么要这样做?因为我不想再等 2 年才能修复 table()。我已经失去了一整天,因为我只是在命令窗口中忘记了;,如果我的电脑正在运行多日模拟,我无法强制重启,但我必须等待磁盘交换结束:(。

附录 有关disp(table(rand(1e7,1))) 的更多上下文。当我击中它时会发生这种情况(幸运的是我足够快,可以用 CTRL-C 退出它):

罪魁祸首是table.disp() 的第 172 行,它将数值数组转换为单元字符串(也有填充!):

[cells, err, isLeft] = sprintfc(f, x, b);

【问题讨论】:

  • 让 Matlab 做任何 没有 已经在工具箱中的事情......肯定会很痛苦。放弃所有希望,你们进入这里!
  • 请注意istable 不是表类的方法,而是它自己的函数调用isa(t, 'table')
  • @Suever 感谢您注意到这一点。我会改成table.size()
  • 有一点需要注意——我发现我可以 CTRL-C 退出那个表 display 你抱怨的例子......
  • 一个问题:ismatrixlike 与现有的ismatrix 有何不同?

标签: matlab oop methods overriding


【解决方案1】:

在尝试了几种替代方案后,我采用了与 Matlab 的原生 @table 实现最少的解决方案,如果出现问题,它很容易删除。

解决办法:

  • 复制整个@table文件夹,即fullfile(matlabroot,'toolbox','matlab','datatypes','@table'),到您拥有写入权限的目的地。

    我选择 destinationfullfile(matlabroot,'toolbox','local','myfiles'),因为我不必担心操作系统的交叉兼容性,即 matlabroot 会为我处理这些问题。

  • 粘贴destination您的@table文件夹中,使用新的、重载的和覆盖的方法(部分覆盖复制的原始文件)

  • 添加 destination 到 matlab 路径,在原始 @table 之前,例如addpath your_destination -begin

效果、优点和缺点:

  • 本机 @table 类/方法现在已被遮蔽,请尝试例如which table -all。不过这个效果还是挺清晰的,很容易检测,也很容易移除(delete destination and remove path);
  • 原生@table(现在被遮蔽)和新@table之间没有奇怪的冲突;
  • 所有新旧方法都可见,试试methods(table)
  • 可以访问私有表方法...
  • ...但你不得不使用它们。
  • 将新方法(用户实现)暴露给私有方法需要更多维护和直接处理表实现中的版本冲突。
  • 您需要在某些符合条件的目标上具有写入权限。

对细节感兴趣的可以关注https://github.com/okomarov/tableutils。特别是install_tableutils(自述文件可能不会更新)。

【讨论】:

  • 优先顺序与字母无关。您链接到备份的页面也没有提到字母顺序。目录按特定顺序添加到path。如果您将新的@table 放在其他所有内容之前 (addpath dir -begin),它将具有优先权。
  • @CrisLuengo 感谢您注意到这一点。我不记得为什么我提到了字母优先级,我通常会测试一些这样的陈述。但是,您的评论在逻辑上听起来更相关,并且文档中确实没有明确提及字母优先级。所以,我个人可能更喜欢用字母排序而不是path 来控制优先级,现在这听起来像是一个很大的不,不...... :)
  • 你为什么说这是一个很大的不,不?这是建立严格排序的一致且安全的方式。字母顺序随语言环境而变化,所以使用它会很糟糕,IMO(即用你的计算机搬到另一个国家,让 MATLAB 突然选择不同的功能!)
  • 我的意思是字母顺序是一个很大的禁忌!
【解决方案2】:

以下对我有用:

  1. 定义一个修改后的disp函数,比如disp_modified.m,如下,并将它放在你的路径中:

    function disp_modified(t)
    if istable(t)
        %// Do whatever you want to display tables
        builtin('disp', '''disp'' function intercepted!')
    else
        %// For non-tables, call `disp` normally
        builtin('disp', t)
    end
    
  2. disp 定义为修改后的函数的function handle(您可以在startup.m 中执行此操作以始终默认使用它):

    disp = @disp_modified;
    

在此之后,在命令窗口中我得到

>> disp(1:5)
     1     2     3     4     5
>> disp({1 2 3 'bb'})
    [1]    [2]    [3]    'bb'
>> disp(table(rand(1e3,1)))
'disp' function intercepted!

【讨论】:

  • 这需要你显式调用disp。我相信他想要重载table 对 disp 的内部调用,这将始终(无论您的本地函数如何)使用内置的disp。这至少是防止省略分号时发生的情况所需要的。
  • 这个解决方案很hacky。它不会通过丢失; 来拦截隐含的disp(),并且可能会鼓励危险的做法。此外,它不是可扩展的和临时的。在clear 之后我应该做什么?为每个方法重新定义所有类似 disp 的变量?
  • 不调用函数disp_modified你可以调用它disp,那么它不受clear影响。
  • @Daniel 你试过了吗?它仍然首先调用table.disp()(尝试在那里放置一个断点)。虽然which disp -all 首先返回新的disp()
  • @Oleg:我的 matlab 版本太旧了,无法支持table,我只是假设它可以解决clear 的问题,就像其他类一样。
【解决方案3】:

根据新类的使用情况,也许您可​​以采用更简洁的方法。您帖子中描述的建议方法有一个缺点,即您更新的环境中使用的代码可能不容易移植到新环境,或者在您的环境中执行的程序可能会在不同的环境中表现出不同的行为。

您可以考虑(或许还需要澄清)的一些问题是:您打算如何使用新课程?你想替换所有现有的表使用吗?您希望能够使用它而不是表类参数吗?或者您是否要更改表,以便环境中原始表类的每次使用都使用新类。

如果您只需要一个新的改进表供您使用,您可以考虑将原始表类封装在一个新类中。例如 MyTable,将您不需要的所有方法委托给原始表方法,替换您想要改进的方法或添加新方法。

更新:刚刚在 Github 上看到了完整的解决方案,并理解了您的意图。不错的作品。如果有人觉得它有用,我会留下这个帖子。

【讨论】:

  • 正如我在第一句话中所说,表类是密封的,因此我不能对其进行子类化。另外,我不太确定您所说的“可移植到新环境”是什么意思。我确实说我的解决方案的缺点之一是明确需要处理影响表类的 matlab 版本的变化。根据操作系统,保持兼容性取决于每种方法(因此它会影响任何解决方案)。我想要做的用途列在问题的第 1 点和第 2 点中。
  • 1.我所说的“解决方案易于移植到新环境”是指“能够以最少的努力在新环境中使用您的解决方案”。看过您的解决方案后,我认为它很容易移植。 2. 我不是要子类表。只是为了创建一个新类(不对原始“表”进行子类化),创建相同的方法签名,并添加您自己的方法以便能够在您的代码中使用这个新表。缺点是它不是表的子类。也许这个解决方案没有你想要的所有属性。
猜你喜欢
  • 1970-01-01
  • 2013-04-28
  • 2018-06-21
  • 1970-01-01
  • 2016-03-06
  • 2018-03-27
  • 2014-05-27
  • 2014-01-04
  • 2021-11-11
相关资源
最近更新 更多