教程:为什么变量不应该叫动态(eval)

4401(30天)
斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑: 斯蒂芬。 2021年8月12日
简介:
动态访问变量名可以产生负面影响代码的可读性,可以导致运行缓慢通过阻止MATLAB优化以及它可以如果你使用它替代技术。最常见的替代方法是使用简单和高效 索引
解释:
有时候初学者(和一些自学的教授)认为这将是一个好主意来动态创建或访问变量名称,通常命名的变量类似这些:
  • matrix1,matrix2,matrix3,matrix4,……
  • test_20kmh,test_50kmh,test_80kmh,……
  • ,nameB,nameC,命名,……
充分的理由 动态变量名应该避免 (点击链接跳转到下面的“答案”):
有多少 更好的选择 访问动态变量名:
请注意,避免 eval (和 assignin 等)并不是深奥的MATLAB限制,它也适用于许多其他编程语言:
MATLAB文档:
如果你不感兴趣阅读下面的答案那么至少读MATLAB的文档关于这个主题 的替代品eval函数 ,州 “频繁使用eval函数创建的变量如A1, A2,…,An, but this approach does not use the array processing power of MATLAB and is not recommended. The preferred method is to store related data in a single array." 可以非常有效地访问数据在一个数组 索引
请注意,所有这些问题和缺点也适用于功能 负载 (没有一个输出变量), assignin , evalin , evalc 明确建议,MATLAB文档 “避免等功能eval,evalc,evalin,函数宏指令(帧)
MATLAB的官方博客解释 为什么eval应该避免 越好 替代eval 显然, 建议不要神奇地创建变量 。使用 eval 出来的位置 一号 在这个列表 排名前十的MATLAB代码实践让我哭泣 。有经验的MATLAB用户 建议避免使用eval琐碎的代码 , 有写过大量关于这个主题吗
7评论
史蒂文的主”class=
史蒂文的主 2019年10月24日
斯蒂芬,这个页面已经多久,我建议总结的讨论 BLUF 为了避免顶部的问题 博士TL; 综合症的东西:
底线: 编号变量会影响代码的可读性和可导致运行缓慢通过阻止MATLAB优化以及它可以如果你使用它替代技术。最常见的选择是:
(项目符号列表和一个简短的描述不超过3常见的替代品)
有关更多信息,请参见讨论这个页面的其余部分的时间越长。”
我知道我自己能做的,但是你已经把很多精力创建和更新这个页面。

登录置评。

接受的答案

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2017年12月11日
2的评论
斯蒂芬。”class=
斯蒂芬。 2018年7月15日
@Cris Lengo:你仍然可以访问新闻阅读器线程:
相关的文本:
MATLAB是不会对你撒谎。
MATLAB运行你的函数时,需要确定每个标识符
你使用的是解析函数的过程的一部分。在那个时候,
没有显示在你的代码,调试应变量;然而,
有一个叫调试功能。因此,MATLAB决定的
实例调试的代码应该是调用该函数。当
实际执行的代码,创建一个名为调试的变量,
反映了这一事实,但在这一点上,太晚了MATLAB“改变
主意”,它试图调用调试函数的最后一行。调试
是一个脚本文件,所以您正确地收到一个错误。
这就是为什么你不应该“噗”变量到工作区中在运行时,
是否通过EVALIN ASSIGNIN、EVAL或负载。
- - -
史蒂夫的主

登录置评。

更多的答案(19)

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年4月18日
MATLAB的文档 替代eval函数 解释说,使用的代码 eval 是慢的,因为 “MATLAB®编译代码在您第一次运行它来提高未来的运行性能。然而,由于代码在一个eval语句可以在运行时改变,这不是编译”
MATLAB使用 JIT 加速工具,分析代码被执行,并优化代码更高效地运行。当 eval 使用JIT优化不是有效的,因为每一个字符串再次被编译并运行在每一个迭代中!这使得循环与 eval 非常缓慢。这也是为什么不干脆 创建 变量与动态变量名是缓慢的,但也 访问 他们。
即使是 eval 隐藏在 str2num 可以减缓代码:

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2018年2月28日
安全风险
eval 将评估任何字符串,它包含不管什么命令。你听起来安全吗?这个字符串命令可能是恶意的或者仅仅是一个错误,但它可以做 任何东西 你的电脑。你能运行代码可以吗 做任何事情都 你的电脑,不知道它要做什么?
对于一些初学者令人惊讶的答案是“是的!”。
初学者会愉快地运行代码,可以做 任何东西 与他们的电脑。例如,尝试运行这个(来自 乔斯的答案 ):
eval (char (”fkur *) Ykvj GXCN”{qw“pgxgt mpqy“yjcv”jcrrgpu0“伏特”eqwnf hqtocvvgf“jcxg {qwt“jctfftkxg”000) +2))
你真的在你的电脑上运行它,即使你不知道它会怎么做?每次初学者编写代码,用户输入并评估他们给该用户运行的能力 任何东西 。你听起来安全吗?
3评论
史蒂文的主”class=
史蒂文的主 2019年10月23日
运行 字符 命令是安全的,就创建一个 字符 你可以阅读。删除 eval () 字符 命令和它不会执行命令存储在 字符 向量。

登录置评。


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年5月4日
很难处理
许多初学者来这里的问题,基本上都是“我有很多编号变量但我无法弄清楚如何做这个操作简单……”,或“我的代码非常缓慢/复杂/…”:
甚至的拥护者 eval 感到困惑,无法正常工作,甚至不能找出原因,这两个例子清楚地表明:
他们为什么不能弄清楚为什么它不工作?:
  • 完全混淆代码。间接评价代码。
  • 代码辅助工具不工作。
  • 语法高亮不工作。
  • 静态代码检查不起作用。
  • 没有有用的错误信息,等等

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年12月30日
使用 eval 使它真的很难追踪bug,因为它混淆了代码和禁用的 代码辅助工具 。为什么初学者甚至 想要 使用一个工具,使它 困难 为他们解决他们的代码吗?
这里有一些例子来说明应该是什么 简单的操作 调试变得非常困难,因为选择使用 eval :
根据进口数据动态生成的代码变量名或用户输入也容易名称的名称长度限制:
这句话 总结调试 eval 基于代码: “我从来没试图使用它自己,但似乎它会创建不可读,undebuggable代码。如果你不能读,不能修复它有什么好处?” 请注意, eval 同样邪恶的兄弟姐妹 evalc , evalin assignin 也使代码响应迟缓:

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2018年2月4日
混淆代码的意图
什么 这段代码 做什么?:
x1 =[119101、98、39104116116112, 58岁,47岁,47119119119年);
x2 = (46121111117116117, 98101, 99111109, 47119, 97];
x3 = [116、99104、63118、61100、81119、52119、57、87103、88];
x4 =(99年,81年,39岁,44岁,39岁,45岁,98114111119115101114年,39岁,41);
eval (char ((x1, x2, x3, x4)))
不幸的是 eval 很容易写的代码难以理解:目前尚不清楚 什么 ,或 为什么 。如果你跑的代码不知道,你应该知道它 可以 已经删除你所有的数据,或者发送电子邮件给你所有的联系人,或从互联网上下载任何东西,甚至更糟…
因为 eval 很容易隐藏了 意图 最终的代码很多初学者编写代码,很难理解。这使得代码缺陷,也更难调试!看到这些例子:
正确地写代码是明确的和可以理解的。清晰易懂的代码容易编写,bug修复和维护。代码读比写更多次,所以永远不要低估的重要性,写代码是明确的和可以理解的:写代码注释,写一个帮助部分,使用一致的格式、缩进等。
3评论
沃尔特·罗伯森”class=
沃尔特·罗伯森 2019年7月24日
我刚遇到有人使用num2str()计算变量名,为了一个eval()的影响没有在代码中直接使用eval ()。不用说,这是模糊的意图。

登录置评。


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年1月6日
代码辅助工具不工作
MATLAB编辑器 包含了许多高级用户的工具 不断 利用,初学者应该尤其欣赏学习使用MATLAB(提示:学会使用他们!)。然而 没有一个 这些工具的使用代码使用 eval
注意,这些 不工作 当使用 eval , evalc 等神奇地创建或访问变量的名字 。你想禁用的工具帮助你编写功能代码?下面是如何的例子 eval 隐藏代码错误,很难调试代码:
1评论
汤姆·霍金斯”class=
汤姆·霍金斯 2019年2月7日
关于这个主题,这将是伟大的如果代码分析器 checkcode 会标记一个警告什么时候 eval 使用等。也许会减少许多问题他们呢?

登录置评。


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2018年7月8日
选择:索引单元阵列或ND-Array
通常当一个用户想要使用 eval 他们试图创建编号的变量,这是有效的 指数 加入到一个名字。那么为什么不只是把 指数为 真正的 指数:MATLAB是非常快速和高效使用指数时,使用指数会让代码更简单得多比任何涉及动态变量名:
使用 ND-arrays 是一个特别有效的方法处理数据:可以执行许多操作完成数组(称为 向量化代码 ),ND-arrays很容易的获得数据,并减少错误的机会:
或者只是把数据进入细胞 单元阵列 :
和一些真实的例子,索引是要简单得多 eval :


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年10月21日
选择: 负载 成一个结构,而不是到工作区中
在几乎所有情况下,数据导入以编程方式(即不只是玩耍在命令窗口)是明智的 负载 数据转换为输出参数(这是一个 结构 如果文件是一个 .mat 文件):
S =负载();
可以直接访问的字段结构,如:
S.X
S.Y
或使用 动态字段名 。注意,这是反的 储蓄的一个标量结构
重要的是要注意,(相反很多初学者认为)它实际上是更容易在一个循环 保存 负载 数据的变量名 .mat 文件 不改变 ,在每个文件来处理不同的变量名称实际上是保存/加载文件更加困难。
摘要:当使用一个循环,保持所有变量名相同的!
这里是加载到变量的实际的例子:
最后史蒂文主的评论 负载 ing直接进入工作区:


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2017年12月18日
其他语言:不使用 eval !
如果你认为避免动态变量名称仅仅是一些“奇怪的MATLAB的事情”,这是相同的讨论一些其他编程语言,所有的建议 “不要创建动态变量名” :
有些语言可能使用,要求或鼓励动态变量名。如果这是他们如何有效地工作,那么我就当一回吧。但什么是有效的在一种语言就意味着什么都不相同的方法在其他语言……如果你想有效地利用MATLAB,使代码更容易处理,并编写MATLAB,其他用户将升值,那么你应该学习如何使用MATLAB功能和工具:

斯蒂芬。”class=
斯蒂芬。 2017年7月19日
编辑:斯蒂芬。 2019年1月6日
神奇地使变量出现在工作区中是危险的
首先这些变量将被重写没有警告,导致很难找错误。但还有一个更严重的问题,这是由MATLAB解析器寻找替代函数/对象/……和调用这些而不是使用magically-created变量:如果变量 不存在 然后解析器 它最好的 找到匹配的名字叫做/使用后……而且它可以找到!例如:
解决方法很简单:不会神奇地“噗”变量存在:永远 负载 成一个结构,没有动态地创建变量名。
6个评论
沃尔特·罗伯森”class=
沃尔特·罗伯森 2019年8月21日
目前所做的一些名字re-resolution只要MATLAB路径发生变化,包括当你cd()——这是一个理由避免cd()代码。
在过去,我把一些想法在你的结构类型必须到位,以处理这种情况下效率。我没有跟着它穿过,不过;只是一些思想实验。

登录置评。


斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2019年3月4日
把数据和代码
内包含的数据和元数据的变量名(如命名变量和用户的输入,测试主题的名称,或(通常)添加一个索引到一个变量名)是一个微妙的(但密切相关)的问题,它应该被避免。
包括变量名的元数据的问题是,这个优惠代码的想法 广义 ,因为它混合了 代码 数据 在一起。事实上应单独进行数据和代码保持代码广义。代码是那样写的 一般尽可能 更简单,更健壮,更具有适应能力,容易写,而且更容易修复,进而使得代码更少的车。混合 元- 数据变量名真的只是让一切更加复杂,这使得代码响应迟缓。
阅读这些讨论的一个解释为什么它是一个贫穷的实践把数据和元数据的变量名:
在许多情况下,元数据只是一个 实际 指数,即一个值的顺序,这节经文的数据。但在这种情况下, 实际 索引应该变成一个更有效 真正的 数值指数:

斯蒂芬。”class=
斯蒂芬。 2016年9月26日
编辑:斯蒂芬。 2017年1月31日
选择:更有效地使用工作区(适用于之间传递变量的方法 evalin , assignin 等)
使用 嵌套函数 、传递参数或使用任何其他的高效工作区之间传递数据的方法:

斯蒂芬。”class=
斯蒂芬。 2017年11月30日
编辑:斯蒂芬。 2018年10月26日
PS: eval 不是错误的:
一些初学者显然认为 eval (和朋友)必须有缺陷,应该从MATLAB完全删除。他们会问“如果 eval 太坏了,为什么它没有被移除?”…但重要的是要理解,问题是由神奇地访问变量名 不管使用什么工具或操作 ,这 eval (或 assignin ,或 evalin ,或 负载 没有一个输出参数等)仅仅是使用不当,因为有太多 更好的 方法( 更好的 在某种意义上更快,整洁,更简单,更少的车,等等)。阅读这些讨论这种混淆的好例子:
重要的是要注意这一点 任何 功能可以使用语言的效率低下或以不恰当的方式,不仅 eval ,这是 可以由语言本身控制。例如,它是常见的,有人会解决有缓慢的循环和没有的东西 preallocating输出数组 :这是 意味着 循环是“错误的”,需要从MATLAB !
由程序员编写高效的代码。

斯蒂芬。”class=
斯蒂芬。 2019年4月17日
编辑:斯蒂芬。 2019年4月17日
选择: 保存 领域的一个标量结构
保存 命令有一个选项保存领域的一个标量结构作为独立的变量中 .mat 文件。例如,给定一个标量结构:
年代。= 1;
年代。B = (2、3);
这将保存变量A和B在.mat文件:
保存(“myfile.mat”,“结构”,“年代”)
这是逆函数的 加载到一个结构 。一些线程显示如何使用这个:

史蒂文的主”class=
史蒂文的主 2019年4月30日
编辑:史蒂文的主 2019年4月30日
选择:使用一个 时间表 数组
(介绍发布R2013b)和 时间表 (介绍发布R2016b)数组允许您存储数据的行和/或列的名字你可以访问数据。例如,如果您创建一个 与变量命名的年龄、性别、身高、体重、吸烟和病人行命名的姓氏:
负载病人
病人=表(年龄、性别、身高、体重、吸烟,
“RowNames”、LastName);
你可以问所有前五岁的患者:
患者(1:5,“年龄”)
或所有患者姓史密斯的数据或琼斯:
病人({“史密斯”,“琼斯”},:)
你也可以添加新的变量 通过硬编码的变量的名称 :
%表示如果病人大于五个半英尺高
病人。veryTall =患者。高度> 66
或者使用存储在变量名 字符 字符串 变量。下面的代码示例创建新变量命名over40和under35病人 使用不同的索引技术。
newname1 =“over40”;
病人。病人(newname1) =。年龄> 40岁;
newname2 =“under35”;
患者{:newname2} =患者。年龄< 35岁;
:患者(1:10)%显示前十行
下面的代码示例选择身高或体重和显示所选变量第五到第十的病人使用动态的名字。
如果兰德> 0.5
selectedVariable =“高度”;
其他的
selectedVariable =“重量”;
结束
病人。(selectedVariable) (5:10)
看到 这个文档页面 关于技术的更多信息可以用来访问和操作数据 时间表 数组中。 这个文档页面 包含的信息访问数据 时间表 使用时间与行相关联的信息。
1评论
斯蒂芬。”class=
斯蒂芬。 2019年4月30日
简单的方法来生成一个表 .mat 文件:
S =负载(“patients.mat”);
T = struct2table(年代,“RowNames”,S.LastName);

登录置评。


Econstudent”class=
Econstudent 2017年1月17日
你在长为什么我们不应该讨论,B或C,你也评论如何访问特定的对象。
现在,假设我们需要导入一些时间序列,但我只能进口这些系列一次。背后的意图创造一个变量在一个循环序列通常是存储每次时间序列在不同的对象。也就是说,您想将数据分配给不同的对象每次和做的远远不止一次…
你有什么其他选择除了循环中创建对象?
7评论
斯蒂芬。”class=
斯蒂芬。 2021年8月10日
“我还想知道如果我使用eval仍弃用”
使用负载导入文本文件数据被弃用很久以前支持更多功能功能专门为文本文件:

登录置评。


扫罗卡马乔”class=
扫罗卡马乔 2021年3月10日
我怎样到工作区中的varibals部分?
1评论
亚当Danz”class=
亚当Danz 2021年3月10日
这不是正确的问题要问。问题是这些变量如何在开始(?)工作区和该方法如何变化,这样他们被加载到空间或作为输入传递函数。

登录置评。