ハマってしまったので、どなたかの参考になれば幸いです。
やろうとしていること: 動的に3つのことなるpath
を表示する関数を定義する
def func
の中が実際に関数が呼ばれたときに評価されるため、t
の値がfor
を処理した最後の値になってしまっている。
>>> path_freq = [{"path": "/pickup/6162449", "freq": 1, "name": "a"}, {"path": "/pickup/6162466", "freq": 1, "name": "b"}, {"path": "/pickup/6162461", "freq":1, "name": "c"}]
>>> task_list = {}
>>> for t in path_freq:
... def func():
... print(t)
... task_list.update({func: t['path']})
...
>>> task_list
{<function func at 0x101184848>: '/pickup/6162461', <function func at 0x101184938>: '/pickup/6162466', <function func at 0x1011848c0>: '/pickup/6162449'}
>>> for k,v in task_list.items():
... k()
...
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
Rubyで似たようなことを試す
[2] pry(main)> path_freq = [{"path" => "/pickup/6162449", "freq" => 1, "name" => "a"}, {"path" => "/pickup/6162466", "freq" => 1, "name" => "b"}, {"path" => "/pickup/6162461", "freq" => 1, "name" => "c"}]
=> [{"path"=>"/pickup/6162449", "freq"=>1, "name"=>"a"},
{"path"=>"/pickup/6162466", "freq"=>1, "name"=>"b"},
{"path"=>"/pickup/6162461", "freq"=>1, "name"=>"c"}]
[3] pry(main)> path_freq.each do |t|
[3] pry(main)* define_method :hoge do
[3] pry(main)* puts t
[3] pry(main)* end
[3] pry(main)* task_list.merge!({hoge => t})
[3] pry(main)* end
{"path"=>"/pickup/6162449", "freq"=>1, "name"=>"a"}
{"path"=>"/pickup/6162466", "freq"=>1, "name"=>"b"}
{"path"=>"/pickup/6162461", "freq"=>1, "name"=>"c"}
=> [{"path"=>"/pickup/6162449", "freq"=>1, "name"=>"a"},
{"path"=>"/pickup/6162466", "freq"=>1, "name"=>"b"},
{"path"=>"/pickup/6162461", "freq"=>1, "name"=>"c"}]
[4] pry(main)> task_list
=> {nil=>{"path"=>"/pickup/6162461", "freq"=>1, "name"=>"c"}}
[5] pry(main)> hoge
{"path"=>"/pickup/6162461", "freq"=>1, "name"=>"c"}
=> nil
PythonとRubyは言語仕様が似てると思ってたけど、一概にそうとも言えないとこの辺りで思いしる。
PythonではメソッドはObjectとして扱われるけど、Rubyでは違う。Rubyの場合は、define_methodでhoge
メソッドを定義した段階で、この例ではmain Object
のメソッドとして定義されてしまう。hoge
メソッドをObjectとして配列に入れたりできない。ちなみに、task_listのkeyにnil
が入っているのは、Rubyではputsの戻り値がnil
だから。
ならば、別の方法でメソッドを定義してみる。
Pythonでsetaddrでclassにメソッドを追加してみるも、同じ挙動。
>>> class Test():
... pass
>>> path_freq = [{"path": "/pickup/6162449", "freq": 1, "name": "a"}, {"path": "/pickup/6162466", "freq": 1, "name": "b"}, {"path": "/pickup/6162461", "freq":
1, "name": "c"}]
>>> task_list = []
>>> for t in path_freq:
... def func():
... print(t)
... setattr(Test, t['name'], func)
... task_list.append(func)
...
>>> for f in task_list:
... f()
...
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
>>> for t in path_freq:
... def func(self):
... print(t)
... setattr(Test, t['name'], func)
...
>>> Test().a()
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
>>> Test().b()
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
>>> Test().c()
{'path': '/pickup/6162461', 'freq': 1, 'name': 'c'}
関数のSignatureは遅延評価されないのではと、引数のデフォルト値でListの値を渡すようにしてみた。
>>> path_freq = [{"path": "/pickup/6162449", "freq": 1, "name": "a"}, {"path": "/pickup/6162466", "freq": 1, "name": "b"}, {"path": "/pickup/6162461", "freq":1, "name": "c"}]
>>> task_list = {}
>>> for t in path_freq:
... def func(path=t['path']):
... print(path)
... task_list.update({func: t['path']})
...
>>> for k,v in task_list.items():
... k()
...
/pickup/6162461
/pickup/6162466
/pickup/6162449