Mathematicaで内部処理を隠蔽する
Mathematicaのシンボルにはいくつかの属性を設定でき、ReadProtected
属性を付与することで定義を隠蔽することができるが、
DownValues
やUpValues
を使うことで定義を表示することができる他、Trace
やTracePrint
を使うことで内部処理を追跡することが可能である。
そこで、ReadProtected
属性に加えてLocked
属性を付与することで内部処理を隠蔽することができる。
通常
何も属性を付与しない場合、Information(?、??)
やDefinition
、DownValues
、UpValues
を使うことで定義を確認できる。
In[1]:= f[x_] := Sin[x] + 1;
In[2]:= Definition[f] // OutputForm
Out[2]//OutputForm= f[x_] := Sin[x] + 1
In[3]:= DownValues[f]
Out[3]= {HoldPattern[f[x_]] :> Sin[x] + 1}
もちろん、Trace
で処理を追うことも可能である。
In[4]:= Trace[f[2]] // OutputForm
Out[4]//OutputForm= {f[2], Sin[2] + 1, 1 + Sin[2]}
ReadProtected
のみ
属性ReadProtected
を付与すると、??
やDefinition
では定義が表示されなくなる。
In[5]:= g[x_] := Sin[x] + 1;
SetAttributes[g, {ReadProtected}];
In[7]:= Definition[g] // OutputForm
Out[7]//OutputForm= Attributes[g] = {ReadProtected}
ただし、依然としてDownValues
では定義を表示可能で、Trace
で処理を追跡することも可能である。
In[8]:= DownValues[g]
Out[8]= {HoldPattern[g[x_]] :> Sin[x] + 1}
In[9]:= Trace[g[2]] // OutputForm
Out[9]//OutputForm= {g[2], Sin[2] + 1, 1 + Sin[2]}
Locked
のみ
属性Locked
をだけを付与しても、これ以上のシンボルの変更ができなくなるだけで、定義を参照することは通常と変わらない。
In[10]:= h[x_] := Sin[x] + 1;
SetAttributes[h, {Locked}];
In[12]:= Definition[h] // OutputForm
Out[12]//OutputForm= Attributes[h] = {Locked}
h[x_] := Sin[x] + 1
In[13]:= DownValues[h]
Out[13]= {HoldPattern[h[x_]] :> Sin[x] + x}
In[14]:= Trace[h[2]] // OutputForm
Out[14]//OutputForm= {h[2], Sin[2] + 1, 1 + Sin[2]}
ReadProtected
+ Locked
ReadProtected
とLocked
の両方を付与した場合に、DownValues
やTrace
を使っても定義を隠蔽することが可能になる。
In[15]:= i[x_] := Sin[x] + 1;
SetAttributes[i, {ReadProtected, Locked}];
Definition
を使っても属性以外は表示されない。
In[17]:= Definition[i] // OutputForm
Out[17]//OutputForm= Attributes[i] = {Locked, ReadProtected}
DownValues
では「シンボルの読出しはできません」とメッセージが表示されて失敗する。
In[18]:= DownValues[i]
In[18]:= General::readp: シンボルiの読出しはできません. >>
Out[18]= $Failed
Trace
を使っても、内部処理部分は表示されず、一気に表示される(TracePrint
も同様)。
In[19]:= Trace[i[2]] // OutputForm
Out[19]//OutputForm= {i[2], 1 + Sin[2]}
回避方法
定義を行う前に大域変数$Pre
や$PreRead
を設定することで、定義される瞬間にどのような式が評価されようとしているのかを見ることができてしまう。
In[20]:= $Pre = Function[a, Print[Hold[a]]; a, {HoldAll}]
In[21]:= j[x_] := Cos[x] + 1
Hold[j[x_]:=Cos[x]+1]
回避方法の回避方法
定義をファイルから読み込む場合は$Pre
や$PreRead
を設定していた場合でも隠すことができる。
もちろんテキストエディタでファイルの中身を読まれては行けないので、Encode
で符号化しておく。
In[22]:= Export[FileNameJoin[{$TemporaryDirectory, "test.m"}], "k[x_]:=Sin[x]+x+1;SetAttributes[k,{ReadProtected,Locked}];", "Text"];
In[23]:= Encode[FileNameJoin[{$TemporaryDirectory, "test.m"}], FileNameJoin[{$TemporaryDirectory, "test.m.enc"}]];
In[24]:= {$Pre, $PreRead} = {#, #} &@ Function[a, Print[Hold[a]]; a, {HoldAll}];
In[25]:= Get[FileNameJoin[{$TemporaryDirectory, "test.m.enc"}]]
Hold[RowBox[{Get,[,RowBox[{FileNameJoin,[,RowBox[{{,RowBox[{$TemporaryDirectory,,,"test.m.enc"}],}}],]}],]}]]
Hold[Get[FileNameJoin[{$TemporaryDirectory,test.m.enc}]]]
結論
- シンボルに属性
ReadProtected
とLocked
の両方を設定することで、大体の場合の内部処理を隠蔽することが可能。 - 定義をファイルから読み込むことで
$Pre
や$PreRead
を使って定義される瞬間も隠蔽可能。