nullable chain
存在しないかするか分からないオブジェクトや属性を参照しようするとき、存在しないものを取得しようとしてエラーになるのが面倒。
例えば、以下のようにissueから始めてlogin_nameを取り出したい時とか。
print issue.author.login_name
ただし、この時
- issueが存在しない(None)こともある
- issueが存在することもある。
そして、存在した場合はlogin_nameが欲しい。
こういう時以下のようなコード書くの面倒
if issue is None: return None else: return issue.author.login_name
時々issueがあってもauthorが存在しないような場合もある。
そうなると以下のようになってしまう。
if issue is None: return None author = issue.author if author is None return None else: return author.login_name
ちょー、面倒くさい。
かと言って、これを避けるためにループを書くのはどうかと思う。
関数にくくりだしても使い辛い。
def selfish_access(obj, *ks): for k in ks: if hasattr(obj, k): obj = obj.k else: return obj return obj # selfish_access({}, "x") selfish_access(issue, "author","login_name")
こんなのどうだろう?(NullableChain)
名前は適切かどうか分からないけれど
class NullableChain(object): def __init__(self, obj): self.obj = obj def __getattr__(self, k): obj = self.obj if hasattr(obj, k): return NullableChain(getattr(obj, k)) else: return NullableChain(None) print NullableChain({}).x # => None
NullableChainに渡すと、このクラスで包んだオブジェクトを返す。
このクラスのインスタンスは、好きなだけchainして値を取り出すことができる。
最終的な値を取り出したい場合は、objを最後につければ良い。
使い方
普通にアクセスした場合(エラー)
空のfooクラスを定義。
これにfoo.bar,foo.bar.bazという感じで値を取り出そうとしてもうまくいかない。
普通は、エラーが出てしまう。これがイライラする。
class foo(object): pass print foo.bar.baz # Traceback (most recent call last): # File "/home/podhmo/sandbox/python/nullable_chain.py", line 52, in <module> # print foo.bar.baz # AttributeError: type object 'foo' has no attribute 'bar'
Nullable Chain
期待としては、foo.bar.bazがとれるかも???と思えるような状況でエラーが起きないこと。
class foo(object): pass print NullableChain(foo).obj print NullableChain(foo).bar.obj print NullableChain(foo).bar.baz.obj # <class '__main__.foo'> # None # None
結果を見てみるとうまく行っているっぽい。エラーにならずにNoneが返ってきている。
多段のものも適切に取り出せる。
class foo(object): """単にfoo.bar.bazとして使いたいだけ""" class bar(object): class baz(object) : pass print NullableChain(foo).obj print NullableChain(foo).bar.obj print NullableChain(foo).bar.baz.obj # <class '__main__.foo'> # <class '__main__.bar'> # <class '__main__.baz'>
意外と便利な気がする。