如何全局关闭隐藏消息(符号::shdw)?或任何其他“良好实践”;建议?

发布于 2024-12-01 01:14:10 字数 612 浏览 1 评论 0原文

我有以下情况:

On[t::shdw]

Message[t::shdw,"t","Foobar","Dork"]
-> t::shdw: Symbol t appears in multiple contexts Foobar; definitions in context Dork may shadow or be shadowed by other definitions. >>

Off[t::shdw]
Message[t::shdw,"t","Foobar","Dork"]
-> **No Warning**

<<MASStoolbox`
-> t::shdw: Symbol t appears in multiple contexts {MASStoolbox`MASS`,Global`}; definitions in context MASStoolbox`MASS` may shadow or be shadowed by other definitions. >>

怎么可能? OnOff是否只影响当前Notebook,加载包时没有任何效果?如果是这样,如何摆脱这样的消息呢?应该如何处理阴影错误?

I have the following situation:

On[t::shdw]

Message[t::shdw,"t","Foobar","Dork"]
-> t::shdw: Symbol t appears in multiple contexts Foobar; definitions in context Dork may shadow or be shadowed by other definitions. >>

Off[t::shdw]
Message[t::shdw,"t","Foobar","Dork"]
-> **No Warning**

<<MASStoolbox`
-> t::shdw: Symbol t appears in multiple contexts {MASStoolbox`MASS`,Global`}; definitions in context MASStoolbox`MASS` may shadow or be shadowed by other definitions. >>

How can that be? Does On and Off only affect the current Notebook and have no effect when loading packages? If so, how can one get rid of messages like these? How should shadowing errors be treated?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

她如夕阳 2024-12-08 01:14:10

您观察到的原因是语句 Off[t::shdw] 禁用了当前位于 $ContextPath< 上的符号 t 的隐藏消息/code>,但不适用于在加载另一个包期间创建的另一个 t。如果您不想看到第二个 t,您应该禁用它。这是一个示例:

In[1]:= Off[Test1`a::shdw]
In[2]:= 
BeginPackage["Test`"]
a
EndPackage[]

Out[2]= Test`
Out[3]= a

In[5]:= BeginPackage["Test1`"]
a
EndPackage[]

Out[5]= Test1`
Out[6]= a

这里没有生成任何消息。

不过,一般来说,我不想禁用隐藏消息,因为隐藏是一个严重的问题。隐藏只是意味着符号搜索路径 ($ContextPath) 上当前存在多个上下文,其中包含具有相同(短)名称的符号。基本上,如果符号被隐藏,并且您通过其短名称引用它(即,不包含其包含包的符号),您无法保证具有相同短名称的几个符号中的哪一个实际上将被使用。因此,处理这个问题的正确方法是完全避免阴影,这总是可能的,尽管并不总是方便。

避免阴影的最简单方法是将所需的包加载到包的私有部分,该部分在 Begin["`Private`"] 行之后开始。与往常一样,您可以通过调用 Needs[your-package] 来完成此操作。这样,加载的包的上下文不会与包的上下文一起保留在 $ContextPath 上。最糟糕的情况是当您需要加载两个具有冲突符号的包时。一种解决方法是为其中之一构建一个包装程序包,该包装程序包将私下加载该程序包并重命名冲突的符号。但这可能很不方便,因为您必须重命名包中的所有函数,即使是那些不冲突的函数。下面是一个更灵活变体的示例:

第一个包:

BeginPackage["Test`"];
g[x_?NumericQ] := x^2;
EndPackage[];

第二个包:

BeginPackage["Test1`"];
g[x_?NumericQ] := x^3;
EndPackage[]

主包:

BeginPackage["Main`"];
f::usage = "A test function of a single  argument";
Begin["`Private`"];

Block[{$ContextPath = $ContextPath},
  Needs["Test`"];
  (* Define first delegate private function *)
  g1 = Symbol["g"]];


Block[{$ContextPath = $ContextPath},
  Needs["Test1`"];
  (* Define second delegate private function *)
  g2 = Symbol["g"];
];

f[x_] := g1[x]*g2[x]
End[]
EndPackage[]

现在,假设系统知道在哪里可以找到您的包:

In[2]:= Needs["Main`"]

In[3]:= f[x]
Out[3]= Test`g[x] Test1`g[x]

In[4]:= f[2]
Out[4]= 32

我们对同一个公共函数使用了两个冲突的符号。使用上面的 Block 可以本地化使用 g 第一个或第二个定义的代码。请注意,此方法有一些不便,因为我们需要使用 Symbol["your-symbol-name"] 将解析延迟到运行时。

一个非常简单的方法是仅通过符号的长名称来引用它们。在上面,我们可以只使用 Test`gTest1`g ,然后就不需要重型机械了。然而,这有点不太灵活,因为您必须将符号的上下文“硬编码”到代码中。

The reason for what you observed is that the statement Off[t::shdw] disables a shadowing message for the symbol t that is currently on the $ContextPath, but not for another t, created during the loading of another package. You should disable shadowing message for that second t, if you don't want to see it. Here is an example:

In[1]:= Off[Test1`a::shdw]
In[2]:= 
BeginPackage["Test`"]
a
EndPackage[]

Out[2]= Test`
Out[3]= a

In[5]:= BeginPackage["Test1`"]
a
EndPackage[]

Out[5]= Test1`
Out[6]= a

Here, no message was generated.

Generally, however, I would not want to disable shadowing messages, since shadowing is a serious problem. Shadowing simply means that there is more than one context currently on the symbol search path ($ContextPath), containing symbol(s) with the same (short) name. Basically, if symbol is shadowed, and you refer to it by its short name (that is, symbol without its containing package), you have no guarantee which of the several symbols with the same short name will actually be used. So, the correct way to deal with this is to avoid shadowing altogether, which is always possible, if not always convenient.

The simplest way to avoid shadowing is to load the package you need into the private section of your package, which starts after the line Begin["`Private`"]. You do that by calling Needs[your-package], as always. In this way, the context of the loaded package does not stay on the $ContextPath together with your package's context. The worst case is when you need to load two packages with conflicting symbols. One way out is to construct a wrapper package for one of them, which would load that one privately and rename the conflicting symbols. This may be inconvenient though, since you'd have to rename all functions in a package, even those that don't conflict. Here is an example of a more flexible variant:

First package:

BeginPackage["Test`"];
g[x_?NumericQ] := x^2;
EndPackage[];

Second package:

BeginPackage["Test1`"];
g[x_?NumericQ] := x^3;
EndPackage[]

Main package:

BeginPackage["Main`"];
f::usage = "A test function of a single  argument";
Begin["`Private`"];

Block[{$ContextPath = $ContextPath},
  Needs["Test`"];
  (* Define first delegate private function *)
  g1 = Symbol["g"]];


Block[{$ContextPath = $ContextPath},
  Needs["Test1`"];
  (* Define second delegate private function *)
  g2 = Symbol["g"];
];

f[x_] := g1[x]*g2[x]
End[]
EndPackage[]

Now, provided that the system knows where to find your packages:

In[2]:= Needs["Main`"]

In[3]:= f[x]
Out[3]= Test`g[x] Test1`g[x]

In[4]:= f[2]
Out[4]= 32

And we used two conflicting symbols for the same public function. Using Block above served to localize the code where the first or second definition of g is used. Note that there is some inconvenience with this method in that we need to use Symbol["your-symbol-name"], to delay the parsing until run-time.

A much simple method is to just refer to symbols by their long names. In the above, we could just use Test`g and Test1`g and then there is no need for the heavy machinery. This is somewhat less flexible however, since you have to "hard-code" the symbol's context into the code.

拥有 2024-12-08 01:14:10

您可以重载 Message 将其关闭:

Unprotect@Message;
Message[MessageName[s_, "shdw"],___] := Null;
Protect@Message;

此代码还会发出更有用且更正确的消息,并使用 Assert:

Unprotect@Message;
Message[MessageName[s_, "shdw"], 
   rest : PatternSequence[snHeld_, pathsHeld_, newpath_]] := 
  With[{paths = ReleaseHold@pathsHeld},
   {memberpaths = Select[$ContextPath, MemberQ[paths, #] &], 
    sn = ReleaseHold@snHeld},
   Print@StringTemplate[
      "Note: Symbol `` added in context ``, so that it now appears in \
multiple contexts: ``. On the context path, it is currently found in: \
``. Definitions in the first context of the context path, ``, will \
shadow any other definitions."][sn, newpath, paths, memberpaths, 
     First@memberpaths];
   (*symbol name*)
   Assert[SymbolName@s === sn];

   (*demonstrate that First@
   memberpaths is the context used for short names*)
   Assert[ToExpression@StringTemplate[
       "Unevaluated@`` === Unevaluated@````"
       ][sn, First@memberpaths, sn
      ]
    ];

   (*and not any other context*)
   Assert@AllTrue[TrueQ][ToExpression@StringTemplate[
          "Unevaluated@`` =!= Unevaluated@````"
          ][sn, #, sn
         ] & /@ DeleteCases[paths, First@memberpaths]
     ];
   ];
Protect@Message;

Try 验证其断言:

Global`Image 

注意:符号图像添加到上下文 Global` 中,以便它现在出现在多个上下文中:{Global`、System`}。在上下文路径上,当前可以在:{System`, Global`} 中找到它。上下文路径的第一个上下文 System` 中的定义将隐藏任何其他定义。

cf https://mathematica.stackexchange.com/questions/43381/result-about-context-is-inconcient-with-the-description-of-power-programming/119887#119887

You can overload Message to turn it off:

Unprotect@Message;
Message[MessageName[s_, "shdw"],___] := Null;
Protect@Message;

This code also emits a more helpful and correct message, and it verifies its assertions with Assert:

Unprotect@Message;
Message[MessageName[s_, "shdw"], 
   rest : PatternSequence[snHeld_, pathsHeld_, newpath_]] := 
  With[{paths = ReleaseHold@pathsHeld},
   {memberpaths = Select[$ContextPath, MemberQ[paths, #] &], 
    sn = ReleaseHold@snHeld},
   Print@StringTemplate[
      "Note: Symbol `` added in context ``, so that it now appears in \
multiple contexts: ``. On the context path, it is currently found in: \
``. Definitions in the first context of the context path, ``, will \
shadow any other definitions."][sn, newpath, paths, memberpaths, 
     First@memberpaths];
   (*symbol name*)
   Assert[SymbolName@s === sn];

   (*demonstrate that First@
   memberpaths is the context used for short names*)
   Assert[ToExpression@StringTemplate[
       "Unevaluated@`` === Unevaluated@````"
       ][sn, First@memberpaths, sn
      ]
    ];

   (*and not any other context*)
   Assert@AllTrue[TrueQ][ToExpression@StringTemplate[
          "Unevaluated@`` =!= Unevaluated@````"
          ][sn, #, sn
         ] & /@ DeleteCases[paths, First@memberpaths]
     ];
   ];
Protect@Message;

Try:

Global`Image 

Note: Symbol Image added in context Global`, so that it now appears in multiple contexts: {Global`, System`}. On the context path, it is currently found in: {System`, Global`}. Definitions in the first context of the context path, System`, will shadow any other definitions.

c.f. https://mathematica.stackexchange.com/questions/43381/result-about-context-is-inconsistent-with-the-description-of-power-programming/119887#119887

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文