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

3.282视图(30天)
简介:
动态访问变量名可以产生负面影响代码的可读性,可以导致运行缓慢通过阻止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琐碎的代码 , 有写过大量关于这个主题吗
11日评论
Stephen23”class=
Stephen23 2023年4月5日
编辑:Stephen23 2023年4月5日
@Sivaprakasam米 :这个页面已经包括解释的几种常见方法避免动态变量名,与许多例子:搜索的文本” 更好的选择 ”。如果阅读本页面不给你一个解决方案,然后请一个 新问题 有足够的解释,有人可以帮助你。

登录置评。

接受的答案

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

登录置评。

更多的答案(19)

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

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

登录置评。


Stephen23”class=
Stephen23 2016年9月26日
编辑:Stephen23 2022年11月25日
很难处理
许多初学者来这里,基本上是一些版本的问题 “我有很多编号变量但我无法弄清楚如何做这个操作简单……” ,或称“ 我的代码非常缓慢/复杂/车……我怎样才能做得更好?” :
甚至的拥护者 eval 感到困惑,无法正常工作,甚至不能找出原因,这两个例子清楚地表明:
他们为什么不能弄清楚为什么它不工作?:
  • 完全混淆代码由于间接评估。
  • 比它需要复杂。
  • 代码辅助工具不工作。
  • 语法高亮不工作。
  • 静态代码检查不起作用。
  • 没有有用的错误信息,等等。
写代码是很难的。不要让它更难通过关闭检查,帮助提高你的代码的工具。

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

Stephen23”class=
Stephen23 2016年9月26日
编辑:Stephen23 2021年11月7日
混淆代码的意图
什么 这段代码 做什么?:
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修复和维护。代码读比写更多次,所以永远不要低估的重要性,写代码是明确的和可以理解的:写代码注释,写一个帮助部分,使用一致的格式、缩进等。
4评论
Stephen23”class=
Stephen23 2021年11月7日
编辑:Stephen23 2021年11月7日
@Walter罗伯森 :这个例子应该STR2NUM吗?(包含EVAL里面)

登录置评。


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

登录置评。


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


Stephen23”class=
Stephen23 2016年9月26日
编辑:Stephen23 2022年11月25日
选择: 负载 成一个结构,而不是到工作区中
MATLAB文档中详细解释了这一点:
在几乎所有情况下,数据导入以编程方式(即不只是玩耍在命令窗口)是明智的 负载 数据转换为输出参数(这是一个 结构 如果文件是一个 .mat 文件):
S =负载();
可以直接访问的字段结构,如:
S.X
S.Y
或使用 动态字段名 。注意,这是反的 储蓄的一个标量结构
重要的是要注意,(相反一些用户认为)它实际上是更容易、更健壮 保存 负载 数据在一个循环的变量名 .mat 文件 不改变 ,在每个文件来处理不同的变量名称实际上是保存/加载文件数据更复杂,效率低下,脆弱。
摘要:当使用一个循环,保持所有变量名相同的!
这里是加载到变量的实际的例子:
最后史蒂文主的评论 负载 ing直接进入工作区:

Stephen23”class=
Stephen23 2016年9月26日
编辑:Stephen23 2021年11月7日
选择:种基本结构(索引)
使用一个 种基本结构 比试图访问简单动态变量名。下面是一些例子:
一个非常简洁的例子是使用DIR存储进口的输出文件数据:
S = dir (. .);
k = 1:元素个数(S)
(k)。数据= readmatrix(S(k).name);
结束

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

Stephen23”class=
Stephen23 2017年7月19日
编辑:Stephen23 2023年2月17日
神奇地使变量出现在工作区中是危险的
这导致很多微妙的错误很难追踪,甚至如果他们注意到!
1)首先同名变量没有警告将被重写。即使只是一个拼写错误或添加额外的变量垫文件可以改变您的代码的行为,因为这取决于你使用的数据文件,可以很难追踪。
2)导入多个文件在一个循环中 毁了你的数据 :考虑会发生什么,如果你的代码流程垫的序列文件,你 认为 所有包含相同的变量。但是其中一个包含不同的变量(是的,我知道,你的数据文件是完美的…确定)。考虑会发生什么在写得很糟糕,脆弱的代码直接加载到工作区中:它将愉快地处理数据 以前 加载文件时,不给你任何警告或通知,您的数据现在从错误的文件。处理持续使用错误的数据。
3)还有一个严重的但微妙的问题,这是由MATLAB解析器寻找替代函数/对象/……和调用这些而不是使用magically-created变量:如果变量 不存在 然后解析器 它最好的 找到匹配的名字叫做/使用后……而且它可以找到!例如:
或在某些情况下,解析器 找到任何:
解决方法很简单:不会神奇地“噗”变量存在:永远 负载 成一个结构,没有动态地创建变量名。
6个评论
沃尔特·罗伯森”class=
沃尔特·罗伯森 2019年8月21日
目前所做的一些名字re-resolution只要MATLAB路径发生变化,包括当你cd()——这是一个理由避免cd()代码。
在过去,我把一些想法在你的结构类型必须到位,以处理这种情况下效率。我没有跟着它穿过,不过;只是一些思想实验。

登录置评。


Stephen23”class=
Stephen23 2016年9月26日
编辑:Stephen23 2022年11月25日
把数据和代码
内包含的数据和元数据的变量名(如命名变量和用户的输入,测试主题的名称,或(通常)添加一个索引到一个变量名)是一个微妙的(但密切相关)的问题,它应该被避免。 这句话从图像分析 简洁地解释了问题: “当你开始编写代码来生成变量名,你不再编写代码来处理你的数据,你写的代码生成的代码将处理你的数据,并增加了复杂性的元编程总是一个额外的风险(bug、安全问题等)。”
阅读这些讨论的一个解释为什么它是一个贫穷的实践把数据和元数据的变量名:
在许多情况下,元数据只是一个 实际 指数,即一个值的顺序,这节经文的数据。但在这种情况下, 实际 索引应该变成一个更有效 真正的 数值指数:
2的评论
沃尔特·罗伯森”class=
沃尔特·罗伯森 2022年1月26日
MATLAB支万博1manbetx持定位系统 哈佛体系结构 ——系统的指令和数据居住在不同地址空间,所以这种系统的指令没有数据。

登录置评。



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

Stephen23”class=
Stephen23 2019年4月17日
编辑:Stephen23 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评论
Stephen23”class=
Stephen23 2019年4月30日
编辑:Stephen23 2021年11月7日
更简单和更强大的方式来生成一个表 .mat 文件:
S =负载(“patients.mat”);
T = struct2table(年代,“RowNames”,S.LastName);

登录置评。


Econstudent”class=
Econstudent 2017年1月17日
你在长为什么我们不应该讨论,B或C,你也评论如何访问特定的对象。
现在,假设我们需要导入一些时间序列,但我只能进口这些系列一次。背后的意图创造一个变量在一个循环序列通常是存储每次时间序列在不同的对象。也就是说,您想将数据分配给不同的对象每次和做的远远不止一次…
你有什么其他选择除了循环中创建对象?
18岁的评论
塞缪尔·格雷”class=
塞缪尔·格雷 2022年2月20日
编辑:塞缪尔·格雷 2022年2月20日
“但首先你需要看任何重要的C程序用于多个操作系统,看看庞大数量的# ifdef头。”
我认为这只是一个问题,因为我们不知道哪些#定义需要包含在程序中,和他们需要什么值,让他们的地方。
有缺乏标准化在C / c++,你总是可以编写程序在Python,这样一个“更高的”语言,让Python开发人员处理这些“C级”的问题。我肯定会帮助你女士和他们如果你刚刚采用VS 2019 +作为IDE,没问题。
我个人同意,C是最令人沮丧的编程语言之一,原因很简单。c++是试图在C程序后酸。让我们很难把代码在一个特定于平台的库的头文件。但部分是因为被微软和微软的走进一个人玩游戏的一部分,改变规则,改变所有的片段并调用相同的游戏。他们只是相关操作系统在控制。这就是为什么你有整段的x86市场拒绝去任何地方靠近窗户。
但BSD的人群只是负责这简单,未能坚持自身发展的指导方针和让即使是最环保的makefile,拼出C新手,如何制作和安装程序。当然,虽然这取决于准确的构建环境。女士很擅长的一件事是牵绊到操作系统无需OS-style错误。他们不论斯泰尔犯错,我们仍然使用Matlab的原因之一。没有Matlab你有一堆小营的人编程在不同的语言中几乎没有共同之处。现在有Matlab在Linux上的伟大之处是,希望你们会放弃COM。和Matlab功能依赖于COM和同样在Windows。其中大部分可以用VBA很容易写的。COM是一个绝望的试图复制功能在Unix中几十年的现在,规范合作与Windows捆绑在一起,Ubuntu女士,为什么你甚至需要COM首先吗?你可以用Ubuntu包Matlab,那就这样吧。
你只需要弄清楚如何收费Matlab;)
(这就是工具包!)
…最终BSD的人群是精英,不关心如果有人发现很难开发Unix的个人最喜欢的味道。这就意味着更多的工作,更多的收入。你想要的东西容易发展,总是有Python,对吧?Python编程是一个伟大的想法,直到你发现Python也依赖库文件版本。和认证代码?哈哈

登录置评。


约翰Dzielski”class=
约翰Dzielski 2022年2月19日
我有一个问题关于一个具体的用例eval命令。这是一个我经常使用,我想了解如果和为什么它是坏的。我从一块仪表数据集在文件名或变量名经常包括一些识别字符串和编号。当我编写分析脚本时,我一般会假设数据存储在一个变量类似“数据”。我将使用一个命令就像eval ([“data =”, namedVariable]) assigne价值的“数据”,然后运行脚本。我将经常使用复制加工的参数数据的反向回相同的变量并将其保存到一个文件。这些脚本通常LiveScripts和情节的标题往往来自“namedVariable”,所以一个函数调用并不是一个有用的解决方案。这样做有什么问题吗?(如果有的话)。
14日的评论
里克”class=
里克 2022年2月20日
没有任何羞耻不知道一个特定的语法,避免了需要eval。你的错误是在重复“我不认为这里有一个方法可以避免eval。我们已经多次证明,通常是。
请下一个作为一个单独的问题,这样其他人也可以找到解决方案。(不要以为的唯一方法是eval)

登录置评。


翻译的