LoginSignup
2
0

More than 1 year has passed since last update.

依存性のある複数引数を一時変数無しで設定する

Last updated at Posted at 2022-09-23

※以下のプログラムはPython 2.7/3.9およびRuby 2.7でそのまま貼り付けて動作することを確認しています。

背景

ライブラリの挙動により、このようなことをしたいことがあると思います。

process(config=json.load(open(fname)),data=get_data(config))
process(config: JSON.parse(File.read(fname)), data: get_data(config))

しかし、前側のパラメータに与えられる情報を後ろのパラメータで使うことはできません。

解決策

※以下、サンプルなのでconfig/dataという名前になっていますが、実際にはこの辺りはちゃんとした名前をつけてください

一時変数

こういう場合、通常はkwargs変数を用意して処理するのだと思います。

Python

def process(**kwargs):  # actually defined in another module
    print(kwargs)

def get_data(config):
    return 1

kwargs = {
    'config': {},  # json.load(open('aaa.json'))
}
kwargs['data'] = get_data(kwargs['config'])
process(**kwargs)
# {'config': {}, 'data': 1}

Ruby

class C  # actually defined in another module
    def self.process(**kwargs)
        print(kwargs)
    end
end

def get_data(config)
    return 1
end

kwargs = {
    :config => {},  # JSON.parse File.read('aaa.json')
}
kwargs[:data] = get_data(kwargs[:config])
C.process(**kwargs)
# {:config=>{}, :data=>1}

似非関数型プログラミング

しかし、このkwargsという変数をどうしても入れたくない場合もあると思います。このような場合、PythonのlocalsやRubyのlocal_variablesを用いて関数型にすることができてしまいます!!!

Python

def process(**kwargs):  # actually defined in another module
    print(kwargs)

def get_data(config):
    return 1

def build_args(fname):
    config = {}  # json.load(open(fname))
    data = get_data(config)
    del fname
    return locals()

process(**build_args('aaa.json'))
# {'config': {}, 'data': 1}

Ruby

  • delに相当するものがRubyにはないので、Hashの要素を削除する必要があります。一時変数…と思いきや、Rubyには_1があるので安心です。
class C  # actually defined in another module
    def self.process(**kwargs)
        print(kwargs)
    end
end

def get_data(config)
    return 1
end

def build_args(fname)
    config = {}  # JSON.parse File.read(fname)
    data = get_data(config)
    return local_variables.zip(local_variables.map(&binding.method(:local_variable_get))).to_h.tap{_1.delete(:fname)}
end

C.process(**build_args('aaa.json'))
# {:config=>{}, :data=>1}

最後に

通常、data = get_data(conf)に相当する操作は、data=None(やnil)を渡した上で、ライブラリ側でdata is None(なりnilなり)のときに実行することだと思います。この記事で紹介した方法はライブラリ側を変更できない場合のみにしてください(というか必要ないならやらないでください)。

蛇足

このPythonサンプルをRubyに移植したのが私がRubyで初めてkwargsをまともに使ったプログラムになってしまいました^^;

2
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0