为什么在以下示例中 b 的值不是打印而是符号名?如何强制打印变量的实际动态值?
a = {1, 2, 3};
DynamicModule[{b},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
,
Initialization :> (b = Length[a]; a = a + 2)
]
输出:
b$107
Out[2]= {{3, 4, 5}, 3}
修改(阅读您的回答/评论后):
考虑一个更简单的例子,没有Initialization
代码(绕过WReach的例子):
a = {1, 2, 3};
DynamicModule[{b = Length[a]},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
]
输出:
During evaluation of In[4]:= b$602
Out[5]= {{1, 2, 3}, 3}
请注意,如果我使用Module
代替DynamicModule
或从Dynamic
行中遗漏Print
,则此示例会执行我想要的操作。我担心的是:
为什么第二个示例无法正确打印 b 的值?没有初始化,它(根据帮助)包含“一个表达式,用于评估何时首次显示DynamicModule”。另外根据帮助:“首次评估DynamicModule
时,首先进行局部变量的初始分配,然后评估Initialization
选项的任何设置。”
帮助应为:“初始化:用于评估何时首次显示 DynamicModule
的结果的表达式”,表示屏幕上的Print
语句执行不构成DynamicModule
的“结果”。如果这是正确的,那么(并且只有那时)我理解为什么Print
语句并不意味着Dynamic
对象正确显示。
答案 0 :(得分:6)
我相信这是因为Dynamic
对象b
在调用Print
语句时尚未显示,因此尚未进行初始化。我记得,Dynamic
功能在实际可见之前不会运行。
有关详细信息,请参阅Why won't this work? Dynamic in a Select。
为了响应您的更新,我的理论是前端内部从未显示Dynamic
内的Print
语句,因此它实际上从未初始化。也就是说,它仍然是一个独特的占位符,等待最终显示时b
的动态值。
从下面的示例可以看出,赋值RHS评估发生在正文Print
之前,至少通过测量FrontEnd中的显示顺序。此外,我们看到Print
“进入”Dynamic
并获取由DynamicModule
创建的唯一符号名称,并打印出来。我们可以使用ToString
使Print
按原样显示整个表达式。同样,如果我们从该字符串中提取符号名称,并将其转换为实际符号,则在打印之前,我们会得到确实已经分配的预期值。
alarm := (Print["Initialized!"]; 3)
DynamicModule[{b = alarm},
Print @ ToString @ Dynamic @ b;
Print @ Symbol @ StringTake[ToString@Dynamic@b, {9, -2}];
Print @ Dynamic @ b;
];
输出:
Initialized! Dynamic[b$701] 3 b$701
答案 1 :(得分:3)
关键行为在DynamicModule文档的更多信息部分中描述:
DynamicModule 首先为 expr 中的局部变量赋予唯一名称, 就像 Module 一样,然后评估结果表达式,然后 返回包含在 DynamicModule 中的此版本。
如果向Print
选项添加Initialization
语句,事件的确切顺序就会变得更加明显,因此:
a = {1, 2, 3};
DynamicModule[{b},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
,
Initialization :> (b = Length[a]; Print["init:", b]; a = a + 2)
]
产生三个细胞:
b$107
Out[7]= {{3, 4, 5}, 3}
init:3
包含b$107
的单元格是Print
内DynamicModule
的结果。然后,我们得到结果单元格(此处标记为Out[7]
)。最后,我们在Print
中通过Initialization
语句看到第三个单元格输出。
如果检查Out[7]
单元格的单元格表达式,您会发现本地化变量为b$$
。这与第一个单元格中的变量不同,即b$107
。这种差异可归因于DynamicModule
文档中描述的“双重范围”。 b$107
单元格包含Dynamic
框,如果我们为b$107
分配值,就会看到。
<强>更新
回应更新后的问题......
返回原始表达式(Print
中没有额外Initialization
),事件的确切顺序如下:
首先,在给出“模块”之类的“局部变量[...]的唯一名称”之后,对DynamicModule
的主体进行评估。也就是说,评估此表达式:
Print[Dynamic[b$107]]; {Dynamic[a], Dynamic[b$107]}
此表达式的结果是列表{Dynamic[a], Dynamic[b$107]}
。作为副作用,创建了包含b$107
的动态单元格,但现在不再考虑该单元格,因为它不是评估结果的一部分。现在,“[{Dynamic[a], Dynamic[b$107]}
]的一个版本包含在 DynamicModule ”中并返回。对此进行评估并隐式打印以生成输出单元格表达式,如下所示:
Cell[BoxData[
DynamicModuleBox[{$CellContext`b$$ = 3},
RowBox[{"{",
RowBox[{
DynamicBox[ToBoxes[$CellContext`a, StandardForm],
ImageSizeCache->{57., {2., 8.}}], ",",
DynamicBox[ToBoxes[$CellContext`b$$, StandardForm],
ImageSizeCache->{7., {0., 8.}}]}], "}"}],
DynamicModuleValues:>{},
Initialization:>($CellContext`b$$ =
Length[$CellContext`a]; $CellContext`a = $CellContext`a + 2)]], "Output"]
请特别注意b$107
作为$CellContext`b$$
符号本地化的函数重命名为DynamicModule
。现在评估Initialization
表达式,因为该框显示并可见。
关键是包含b$107
的打印单元格没有以任何方式耦合到最终的DynamicModule
单元格。