2017-01-02 8 views
1

私は、Python 3.5を使用していますし、これは私が現時点で扱ってるコードです:Pythonどのようにエレガントに異なるデータ構造の使用を処理するには?

def is_odd_number(n): 
    """states if n is an odd number""" 
    return n % 2 == 1 


def collatz_next(n): 
    """returns the successor to n in Collatz sequence""" 
    return 3*n + 1 if is_odd_number(n) else n//2 


def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    return sum(seq) 


def collatz_seq(n): 
    """returns the Collatz sequence to n""" 
    l = [] 
    l.append(n) 
    current = n 
    while current != 1: 
     next_one = collatz_next(current) 
     l.append(next_one) 
     current = next_one 
    return l 


def collatz_seqs(lower_limit=1, upper_limit=10): 
    """returns Collatz sequences from lower_limit to upper_limit""" 
    return {i: collatz_seq(i) for i in range(lower_limit, upper_limit+1)} 

私は、単一のこのCollat​​zシーケンスを扱うときに、そのタイプlistがベストだと思います。だから、collatz_seqがリストを返します。しかし、複数のパラメータnを連続して扱う場合、この特定のシーケンスがどのように発展するかを観察することは興味深いことです。だからこそ私はcollatz_seqsを作成しました。

非常に単純な理由から私はcollatz_seq_sumが好きではありません。パラメータseqのタイプがlistの場合にのみ正しく動作します。私の意見では、collatz_seq_sumは、実際のパラメータが適切であることを確認する責任はありません。この場合は、listは自然数です。私の意見では、collatz_seq_sumへの発信者は、正しいパラメータが提供されていることを確認する必要があります。

collatz_sum_seqは、単一シーケンスと複数シーケンスで動作します。 collatz_seqlistを返し、collatz_seqsdictを返します。したがって、私の質問:seqcollatz_seq_sumが常に正しいデータ型を取得できるようにするうまい方法は何ですか? collatz_seq_sumが正常に動作するためには、collatz_seq_sumのパラメータのデータタイプを気にする必要があります。seq?私の最初のアイデアはcollatz_seqlistの代わりにdictを返し、dictを処理するためにcollatz_seq_sumを変更するように変更することでした。しかし、単一の配列を扱うときにはdictが欲しくないので、私はこのアプローチが嫌いです。

解決策はありますか?事前にどうもありがとうございました。

+0

[mypy](https://github.com/python/mypy)静的型検査ライブラリは、[decorator](https://jeffknupp.com/blog/2013/11/29/improve-your- python-decorators-described /)を使って、あなたが望む多態性を許すような 'overload'を作成します:http://mypy.readthedocs.io/en/latest/function_overloading.html。私に有望に見えます。 –

+0

[functools.singledispatch](https://docs.python.org/3/library/functools.html#functools.singledispatch)は役に立ちますか? – wwii

答えて

0

唯一の方法は、チェックすることです与えられた引数の型:

from collections.abc import Mapping, Iterable 

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, Mapping): 
     ret = {key: sum(values) for key, values in seq.items()} 
    elif isinstance(seq, Iterable): 
     ret = sum(seq) 
    else: 
     msg = "collatz_seq_sum got unexpected type: '{}'".format(type(seq)) 
     raise TypeError(msg) 
    return ret 

これは、入力の種類によって機能が異なるようにしたい場合に使用します。

+0

あなたのご意見ありがとうございます。それは良い議論であり、私はそれを理解しています。私は疑問に思っていた:これは唯一のアプローチですか?何千もの関数ではなく、何百もの関数を利用するスクリプトを使用しているとします。常に同じことが何度も繰り返されているということです。各関数はパラメータの型をチェックし、それに応じて動作します。同じことを何度も何度も繰り返すことは信じられないほど面倒だし、読んだり維持したりするのは難しいと思う。 – 6q9nqBjo

+0

これは、クラス(およびダックタイピング)が対象とするものです。これを行うというPythonの哲学です。 –

0

正しく理解すれば、collatz_seq_sumはcollat​​zシーケンスの辞書と個々のcollat​​zシーケンスの両方で動作します。辞書の場合、関数は個々のcollat​​zシーケンスの合計の辞書を返すようにします。

isinstanceを使用して、入力seqがディクショナリまたはリストであるかどうかを確認し、それぞれのケースごとに異なるコードを実行できます。次のコードは動作します。

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, dict): 
     return {i: sum(seqi) for i, seqi in seq.items()} 
    else: 
     return sum(seq) 

何をしたいあなたは辞書の全てのシーケンスの和であるならば、あなたは代わりに以下を使用することができますしかし、Pythonでの関数のための多型を行うには

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, dict): 
     return sum([sum(seqi) for i, seqi in seq.items()]) 
    else: 
     return sum(seq) 
+0

あなたのご意見ありがとうございます。まあ、正確ではありません。 'collat​​z_seq_sum'がデータ型のチェックに' collat​​z_seq_sum'の仕事をしているとは思っていないので、 'seq'のデータ型では気にしません。合計を計算するのはその仕事です。他には何もない。 – 6q9nqBjo

+0

データ型をチェックせずに、任意のデータ型でcollat​​z_seq_sumを動作させたいとお考えですか? –

+0

はい、これは基本的な考えです。何百もの関数を扱うときに同じチェックをほとんどしたくないからです。 – 6q9nqBjo

0

Python 3.4+ - functools.singledispatchオーバーロードは、引数の型に基づいた関数定義になります。

from functools import singledispatch 

@singledispatch 
def collatz_seq_sum(seq): 
    '''returns the sum of all elements to a given Collatz sequence''' 
    raise NotImplementedError("I can't handle that data type") 

@collatz_seq_sum.register(list) 
def _(seq): 
    return sum(seq) 

@collatz_seq_sum.register(dict) 
def _(seq): 
    return {key: sum(values) for key, values in seq.items()} 

>>> collatz_seq_sum([1,2,3,4,5]) 
15 
>>> collatz_seq_sum({'a': [1,1,1,1], 'b': [2,2,2,2]}) 
{'a': 4, 'b': 8} 

リストや辞書以外のものでcollatz_seq_sumを呼び出すと、NotImplementedErrorが発生します。

+0

入力いただきありがとうございます。これは非常に面白いアプローチです。あなたは "過負荷"という言葉を使いました。あなたのコードはPythonのデコレータ機能のアプリケーションですか? @記号は私にそれを思い出させる。 – 6q9nqBjo

+0

@ 6q9nqBjo、私はそれがドキュメントから過負荷という言葉を取った。それはデコレータです - 私は見て、それがどのように実装されているか見る時間をとらなかった。私の答えには、ドキュメントへのリンクがあります。 – wwii

関連する問題