At this point we have seen how to reproduce static data
simply by shipping the files over as the data is required by the program.
We have seen how to record and replay user interaction.
However, all of these are actually instances of the same class of input
that is interaction between the program and its environment.
The question is whether it would be possible to record
and replay this interaction as a whole.
A program interactions with its environment
by means of function calls.
We use function calls to access data.
We use function calls to access user interaction
or generally anything that comes form the environment.
So, what we could do is to record and replay function calls.
This way we would have a single mechanism to capture
all sorts of interaction between the program and its environment.
Our plan would be to record every function call with parameters in a log
then later be able to replay them.
Let's first do the recording.
We've already seen our tracing functions where we can access
the individual execution frames of a run.
We know that each frame contains the function name
as well as all local variables.
When a method gets called this list of local variables
is actually the list of arguments for the function.
If, for instance, I have set up the traceit function,
which gets called for every line as always.
It also gets called when a function is called.
In this case the event variable up here has a value of call.
If this happens then we print out the name of the current function,
and we print out the local variables,
which should be the arguments.
Let's try out whether this works.
What we see here is we have a call to remove html markup function
and s as precisely the value as here in our code.
We would now like to turn the function name as well as the argument list
into something that can be translated back into code.
We want it to look precisely like this.
If we turn this into a string that looks exactly like a function call,
then we can pass this to the Python eval function,
which takes a string and interprets it as code.
This is something we will use later for replaying.
Here you can see how the string is interpreted, and the result is printed.
Here's the function that takes care of the printing of the local variables
that is the arguments.
Since we don't know the position of the individual parameters in the function,
what we use is we print out named arguments instead.
That is, we print out name equals value.
This will be separated by commas.
Now again we will remove html markup with this parameter.
If everything goes well,
the traceit function to print out this very call with the right argument.
This is precisely what happens.
You see, we print out remove html markup with the parameter s
being the string foo exactly as over here
except that we do have a named parameter
and not a positional parameter.
The same mechanism works for tracing or recalls
as long as these are Python functions.
So if we call square root of 2, for instance
This would also get traced and reported in our output.
As you see here, here is the count of square root and x has a value of 2.
Now let's assume that we have a variable,
which actually has stored all these calls.
We could do so by recording it right away while the code is executing,
or we could also say store this in a file and read this back from a file.
Your job now is to write a piece of code that evaluates all these calls.
First this one, and then the other one,
and which prints out the appropriate results for each of these calls
in the form function argument equals return value.
Over to you.
この時点でプログラムにとって必要なデータとして
単にファイルを移出することで
静的データを再現するという方法を確認できました
ユーザインタラクションの記録と
リプレイ方法を確認しました
しかしこれらはすべて同等クラスの入力の事例です
プログラムとその環境間のインタラクションです
まとめてこのインタラクションを記録し
リプレイできるのかどうかが問題です
プログラムは関数呼び出しによって
その環境と対話しています
データにアクセスするために関数を呼び出します
ユーザインタラクションまたは環境由来のものすべてに
アクセスするために関数を呼び出します
つまり できるのは関数呼び出しを記録し
リプレイすることです
1つのメカニズムを持つことで
プログラムと環境間のあらゆるインタラクションを
取り込むことができます
ログにあるすべての関数呼び出しを
パラメータで記録します
その後それをリプレイします
まずは記録から始めましょう
実行の1つ1つのフレームにアクセスできる時の
トレース関数をすでに確認しています
各フレームにはすべてのローカル変数だけでなく
関数名も含まれています
メソッドが呼び出された
ローカル変数のリストが
実際は関数に渡す引数のリストになります
たとえばtraceit関数を設定したら
常にすべての行で呼び出されます
関数が呼び出された時も呼び出されます
この場合ここにある引数eventは
呼び出しの値を有しています
もしこれが起きたら現在の関数名を出力し
ローカル変数を出力します
これが引数になります
これが機能するか試してみましょう
ここで確認するのはコードのここと同じ値で
引数sのremove_html_markup関数を呼び出すことです
引数リストだけでなく関数名も
コードに変換し直せる何かに
変換したいと思います
的確にこのような感じにしてください
これをまさに関数呼び出しのような文字列に
変換した場合
これをPythonのeval関数に渡すことができます
これは文字列を取得し それをコードと理解します
これはあとでリプレイに使えそうです
文字列が変換され
結果が出力されているのがわかりますね
これが引数であるローカル変数の
出力を処理する関数です
関数内のそれぞれのパラメータのポジションが
分からないので
代わりに名前付き引数を出力したものを使います
つまりname=valueを出力します
これはコンマで区切られます
ここで再びこのパラメータで
HTMLタグを削除します
すべてがうまくいったらtraceit関数です
正しい引数でこの呼び出しを出力します
これがまさに起きることです
引数sでremove_html_markup関数を出力しました
ここにあるように文字列<b>foo</b>になります
ただしポジションのパラメータではなく
名前付きパラメータがあることは除きます
Python関数がある限り
同様のメカニズム
トレースや再帰呼び出しにも応用できます
たとえばsquare_root(2)を呼び出した場合
トレースされ出力されます
ここで確認できるようにxの平方根の値は2です
変数があり そしてすべての呼び出しを
保存していたと仮定しましょう
コードが実行されている間にすぐに記録すれば
これができます
またはファイル内のこれを保存し
ファイルにこれを読み戻すことができます
それではすべての呼び出しを評価するコードを
書いてください
まずこの呼び出し 次にこちらの呼び出し
呼び出し1つずつの適切な結果を出力します
出力は"関数(引数)=戻り値"の形式です
さあどうぞ