piruty.hatenablog.com

今を一所懸命生きる。

【php】グローバルスコープを使うときは明示的に指定する

最近になってPHPのスコープについて「グローバルなスコープと思っていても明示的に呼び出さないといけない」ということを初めて知った。 どういうことかというと、PHPではスクリプト全体で共有されているように見えても、ちゃんとglobalをつけて宣言しないといけないということ。

例えば次のようなコード。

<?php
$a = 1;

function call_global() {
    global $a;
    $a = 2;
    echo "In call_global a: ".$a."\n";
}

function not_call_global() {
    $a = 3;
    echo "In not_call_global a: ".$a."\n";
}

echo $a."\n";
call_global();
echo $a."\n";
not_call_global();
echo $a."\n";

スクリプトの先頭とcall_globalnot_call_globalでそれぞれ同じ名前の変数が使用されている。 直感的には、最初の宣言が関数の外にあるので、このスクリプト内ではグローバルな変数として使いまわされそうな気がする。

これの実行結果はこちら。

$ php global.php
1
In call_global a: 2
2
In call_global a: 3
2

call_globalの呼び出しによってaの値が書き換わっている。 ところが、not_call_globalが呼ばれてもaには影響がない。 globalと宣言されることによってグローバル変数を参照するようになるが、そうでなければローカル変数として定義されるということです。

このぐらいの簡単なコードならまだ大丈夫。 ところが、大きなプロジェクトになるとglobalの宣言がいたるところにあったり、同じ変数名がローカルだったりグローバルだったりするようになる。 そうならないように、きちんとリファクタしたりきれいなコードを書くように心がけましょう、ということです。


【python】jupyter notebook上でanimationを実行する

jupyterでpython3のコードを書きながらアニメーションを実装しようとしたところ、なかなかうまく行かなかった。 調べてみたところ、jupyter上でアニメーションさせるときはplotを表示させるのではなく実装したアニメーションを直接呼び出す必要があった。

from matplotlib import pyplot as plt
from matplotlib import animation

def update_radius(i, circle):
    circle.radius = i*0.5
    return circle,

fig = plt.gcf()
ax = plt.axes(xlim=(-10,10), ylim=(-10,10))
ax.set_aspect('equal')
circle = plt.Circle((0,0), 0.05)
ax.add_patch(circle)
anim = animation.FuncAnimation(fig, update_radius, fargs=(circle, ), frames=30, interval=50)
anim

これをjupyter上で実行すると、徐々に円が大きくなっていくアニメーションが繰り返し表示される。 本やサイトによっては最後のところをplt.show()としていたり%matplotlib nbaggを記述したりしているが、今回は最後にアニメーションのインスタンスを呼び出すだけで表示できた。

【html/css】tabindexを設定しdivタグにフォーカスを当てる

久々にHTMLを書いたら、いろいろなことを忘れていて非常に難儀した。 divタグにtabキーでフォーカスを当てられるようにしつつ、フォーカスの当たったdivタグをボーダーで囲むということをやったので今度は忘れないようにまとめておく。

まず、divタグにtabキーの操作でフォーカスが当てられるように「tabindex」を設定しておく必要がある。 さらにクラスを指定し、CSSでボーダーを表示できるようにする。 この時、「:focus」とすることでフォーカスが当たった場合に適用されるスタイルを定義することができる。

これらをまとめて、簡単なhtmlを書いてみた。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>フォーカスが当たったときにボーダーが表示される</title>
        <style>
            div.focus1:focus {border: medium solid red;}
            div.focus2:focus {border: medium solid blue;}
            div.focus3:focus {border: medium solid yellow;}
        </style>
    </head>
    <body>
        <div class="focus1" tabindex="1">focus1</div>
        <div class="focus2" tabindex="2">focus2</div>
        <div class="focus3" tabindex="3">focus3</div>
    </body>
</html>

今回は3つのdivタグを用意し、それぞれに個別のクラスを設定した。 ブラウザ上で確認すると、はじめは文字が表示されているだけだが、tabキーを押すと順番にフォーカスが当たり設定された色の枠で囲まれる。

chromeのコンソールでページ上の要素にフォーカスを当てる

長いことchromeを使って開発しているが、開発コンソールについてはまだまだ未知の機能が多い。 今日初めて、コンソール上からページ内の要素にフォーカスを当てる機能があることを知った。

開発コンソールを開き、「Elements」タブを選択すると画面内の要素がHTMLで表示される。 この時、タグを右クリックすると「:focus」と出てくるのでこれを選ぶ。 すると、そのタグの横にオレンジ色のマークが付き、指定したタグの画面上の要素にフォーカスが当たった状態になる。 解除するときはもう一度右クリックし同じ項目を選び直せば良い。

他にも「:active, :hover, :visited」があり、これらも同様に扱うことができる。

1PasswordのDropbox同期ではフォルダ選択に注意する

Mac上でのDropboxを使った1Passwordの同期設定について、簡単にできると思っていて初歩的なミスで詰まってしまった。

まず、設定画面を開いて同期タブを選択する。 Mac上で保存されているVaultsが表示されているので同期したいものを選択し、「Sync vault with」の隣のドロップダウンメニューから「Dropbox」を選ぶ。 すると同期先のDropboxフォルダの選択を促されるので、PC上のDropboxフォルダを指定する。 この時、Dropboxフォルダ内に作成された別のフォルダなどを指定したとしてもうまくいかない。(←今回詰まったところ)

あとは同期が行われて、Dropbox上のApps/1Passwordというフォルダの中に同期のためのファイルが生成される。 別のデバイスで同期するときは、1Passwordの同期設定でDropboxを選べば勝手にDropboxフォルダ内を検索して同期ファイルを見つけてくれる。

【python】sympyのsympifyとsimplifyの違いについて

Pythonからはじめる数学入門」を読んでいて、少し混乱してしまったところ。 sympyパッケージがもっている「sympify」と「simplify」の違いについて。 本を読んでいれば書いてあるのだが、いつの間にか混同して使っていた。

この2つの違いは以下の通り。

  • sympify: 文字列を数式に変換する
  • simplify: 数式を簡略化する

例えばこんな使い方ができる。

from sympy import symbols, sympify, simplify

x, y = symbols('x, y')
expr = 'x**2-1'
expr = sympify(expr) # 1
expr_y = expr.subs({x:1-y}) # 2
print(simplify(expr_y)) # 3

上の例では#1でexprに格納された文字列をsympifyを用いて数式に変換している。 この時点でexprは「x2 - 1」になっている。

次に#2でexprにx=1-yを代入し、これをexpr_yと置く。 従って、expr_y = (1-y)2 - 1である。

最後に#3でsimplifyを使い、expr_yを計算・簡単な形に表現し直す。 これを実行すると「y*(y-2)」となり、expr_yが一度展開され計算された後に再度因数分解されていることがわかる。

この2つの関数は名前が似ているが、実行していることは異なる。

【php】PHPで独自ソートを実装する

単純な昇順・降順ではなく、実装上の都合で特定の要素をソート基準として並べ替えたくなることが度々ある。 そんな時、PHPでは関数として並べ替えのルールを定義してソートする関数「usort」が用意されている。

<?php
function mysort($a, $b) {
    return $a["order"] < $b["order"] ? -1 : 1;
}

$arr[] = ["order" => 3];
$arr[] = ["order" => 1];
$arr[] = ["order" => 2];

echo "ソート前: ";
foreach ($arr as $a) {
    echo $a["order"];
}

echo "\n";
echo "ソート後: ";
usort($arr, "mysort");

foreach ($arr as $a) {
    echo $a["order"];
}

これを実行するとこうなる。

$ php usort.php
ソート前: 312
ソート後: 123

まず、ソート条件を関数として定義する。(上記ではmysortという関数。) この関数には戻り値が必要で、戻り値の正負によって並べ替えが行われる。 戻り値が負なら要素同士を入れ替え、正ならそのままになる。

次に、ソート対象になるオブジェクトとソート条件関数を「usort」に引数として渡す。 これで対象のオブジェクトが先程の関数に記述された条件で並び替えられる。 例の中では、配列中の各要素のorderに格納されている値の大小を元にしてソートされる。

実際に実行してみると、ソート前後で要素が並び替えられていることがわかる。