python クロージャ
忘れた頃にまたやってくるクロージャ。
def charge(price): def calc(num): return price * num return calc child = charge(1000) adult = charge(1500) price1 = child(2) price2 = adult(2) print(price1) print(price2)
クロージャでは関数の中に関数を定義する。
上記の例では、charge() の中に、calc() が定義されている。
charge() が呼び出されると、その戻り値として、calc() が返却される。
calc() は関数なので、戻り値は関数オブジェクトになる。
calc() は price * num の結果を返す関数。
charge() が呼び出された時点で、price が引数で与えられている。
そのため、戻り値は price に値が入った calc() 関数になる。
例えば、charge(1000) なら、1000 * num を返却する calc() 関数が戻り値になる。
それが、child に代入されている。
charge(1500) なら、1500 * num を返却する calc() 関数が戻り値になる。
それが、adult に代入されている。
child(2) を呼び出すと、それは calc(2) (※ただし price は 1000) を呼び出すのと同じである。
1000 * num を返すので、2000 が返ることになる。
adult(2) を呼び出すと、それは calc(2) (※ただし price は 1500) を呼び出すのと同じである。
1500 * num を返すので、3000 が返ることになる。
なぜ、sudo rm でワイルドカード指定できないのか
sudo rm でワイルドカード指定したのに動かない。
$ sudo rm /var/log/elasticsearch/elasticsearch.*.log rm: cannot remove `/var/log/elasticsearch/elasticsearch*log': No such file or directory
ワイルドカード拡張は、rmではなくシェルによって行われる。
また、シェルにはsudo権限はなく、rmのみにある。
したがって、シェルには/var/log/elasticsearch/を読み取る権限がないため
展開は行われず、rmはファイル(ワイルドカードではない)/var/log/elasticsearch/*(存在しない)を削除しようとする。
これを回避するには、rmを実行するsudo権限を持つシェルが必要となる。
sudo sh -c 'rm /var/log/elasticsearch/elasticsearch*.log'
JUnit DataPoint によるテストパラメータ定義
例えば、文字列を引数に取るメソッドをテストするにあたり、色んな文字列でテストしたい場合。
テストする文字列ごとにテストケースを作成するのは大変。
DataPoint を使うことで、それらのパラメータを配列で管理することができ、文字列一つずつを一つのテストケース内で自動的に適用しながらテストすることが可能となる。
※そのメソッドの期待値が引数に依存せずに同一であれば評価しやすいが、もし異なる場合、それぞれの引数に対する期待値を別途定義が必要
@RunWith(Theories.class) public class DataPointSampleTest2 { @DataPoints // for multi test data public static String[] DATA_PARAM = { "JAPAN", "JAPANESE" }; private static int index = 0; @Theory public void test(String param) { System.out.println("test param=" + param); assertThat(param, is(DATA_PARAM[index++])); } }
このテストでは、引数param として、”JAPAN” と "JAPANESE" が順番にテストされる。
コンソールでの標準出力。
test param=JAPAN test param=JAPANESE
Python CUIで迷路生成(3)
スタートとゴールの場所を指定するところまで。
set_start_goal
ランダムに座標を指定し、そこが通路ならスタート”S”、またはゴール”G” をそこに設置する。
import sys import random class Maze(): PATH = 0 WALL = 1 START = 2 GOAL = 3 def __init__(self, height, width): self.maze = [] self.width = width self.height = height if (self.width % 2) == 0: self.width += 1 if (self.height % 2) == 0: self.height += 1 def set_outer_wall(self): for y in range(0, self.height): row = [] for x in range(0, self.width): if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1): cell = self.WALL else: cell = self.PATH row.append(cell) self.maze.append(row) def set_inner_wall(self): for x in range(2, self.width-1, 2): for y in range(2, self.height-1, 2): self.maze[y][x] = self.WALL while True: wall_x = x wall_y = y if y == 2: direction = random.randrange(0, 4) else: direction = random.randrange(0, 3) if direction == 0: wall_x += 1 elif direction == 1: wall_y += 1 elif direction == 2: wall_x -= 1 else: wall_y -= 1 if self.maze[wall_y][wall_x] != self.WALL: self.maze[wall_y][wall_x] = self.WALL break def set_start_goal(self): # set start while True: s_x = random.randrange(1, self.width-1) s_y = random.randrange(1, self.height-1) if self.maze[s_y][s_x] == self.PATH: self.maze[s_y][s_x] = self.START break # set goal while True: g_x = random.randrange(1, self.width-1) g_y = random.randrange(1, self.height-1) if self.maze[g_y][g_x] == self.PATH: self.maze[g_y][g_x] = self.GOAL break def print_maze(self): for row in self.maze: for cell in row: if cell == self.PATH: print(' ', end='') elif cell == self.WALL: print('#', end='') elif cell == self.START: print('S', end='') elif cell == self.GOAL: print('G', end='') print() args = sys.argv maze = Maze(int(args[1]), int(args[2])) maze.set_outer_wall() maze.set_inner_wall() maze.set_start_goal() maze.print_maze()
出力例
$ python create_maze.py 10 20 ##################### # # # # # # ### ##### # ### ### # # # # ##### # # ##### ### # # # # # S# # ##### ####### ##### # # # # # # ##### ### # # ### # # G# # # # # #####################
JUnit Enclosed によるテストケースのグループ化
既に存在しているテストクラスに新しいテストケースを追加するとき、どの位置に入れようか迷うときがあります。
出来れば、後で見たときに分かりやすい位置に入れたいですが、そもそも整理されていなければそれも難しいです。そこで Enclosedを使うことで、テストケースのグループ化が可能です。
@RunWith(Enclosed.class) public class RunWithTest { public static class TestForNumber { @Test public void additionTest() { int actual = 1 + 2; assertThat(actual, is(3)); } @Test public void subtractionTest() { int actual = 1 - 2; assertThat(actual, is(-1)); } } public static class TestForCharacter { @Test public void additionTest() { String actual = "a" + "b"; assertThat(actual, is("ab")); } @Test public void replaceTest() { String actual = "a".replace("a", "b"); assertThat(actual, is("b")); } } }
どのような観点でグループ化するか迷いところですが、いくつかヒントはありそうです。
- 共通のデータで分ける
- 共通の状態で分ける
- コンストラクタのテストを分ける など
テスト結果も以下のようにグループ化されて表示されます。
Python CUIで迷路生成(2)
内壁を生成するところまで。
棒倒し法により生成するが、その手順は
1. 迷路全体を構成する2次元配列を、幅高さ5以上の奇数で生成する
2. 迷路の外周を壁とし、それ以外を通路とする
3. 外周の内側に基準となる壁(棒)を1セルおき(x, y ともに偶数の座標)に配置する
4. 内側の壁(棒)を走査し、ランダムな方向に倒して壁とする
※ただし以下に当てはまる方向以外に倒す
- 1行目の内側の壁以外では上方向に倒してはいけない
- すでに棒が倒され壁になっている場合、その方向には倒してはいけない
import sys import random class Maze(): PATH = 0 WALL = 1 def __init__(self, height, width): self.maze = [] self.width = width self.height = height if (self.width % 2) == 0: self.width += 1 if (self.height % 2) == 0: self.height += 1 def set_outer_wall(self): for y in range(0, self.height): row = [] for x in range(0, self.width): if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1): cell = self.WALL else: cell = self.PATH row.append(cell) self.maze.append(row) return self.maze def set_inner_wall(self): for x in range(2, self.width-1, 2): for y in range(2, self.height-1, 2): self.maze[y][x] = self.WALL while True: wall_x = x wall_y = y if y == 2: direction = random.randrange(0, 4) else: direction = random.randrange(0, 3) if direction == 0: wall_x += 1 elif direction == 1: wall_y += 1 elif direction == 2: wall_x -= 1 else: wall_y -= 1 if self.maze[wall_y][wall_x] != self.WALL: self.maze[wall_y][wall_x] = self.WALL break return self.maze def print_maze(self): for row in self.maze: for cell in row: if cell == self.PATH: print(' ', end='') elif cell == self.WALL: print('#', end='') print() args = sys.argv maze = Maze(int(args[1]), int(args[2])) maze.set_outer_wall() maze.set_inner_wall() maze.print_maze()
出力例
$ python create_maze.py 10 20 ##################### # # # # # # # # # # # # ### # # # # # # # # # # ##### ### # ##### # # # # # # # # ##### ######### # # # # # # # ### # ### ##### ### # # # # # # # #####################
Java 例外(Exception) テスト
例外(Exception)のテストの書き方でよく知られているもので、Ruleアノテーションを用いた ExpectedException を使う方法があります。
例外のメッセージまで評価してくれるのがいいですね。
public class RuleTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void testThrowException() { expectedException.expect(RuntimeException.class); expectedException.expectMessage("Rule test"); throw new RuntimeException("Rule test"); } }