2010-12-02 13 views
4

私は最近、@ sequenceableデコレータを作成しました。このデコレータは、1つの引数をとり、自動的にどのシーケンスにも適用できるようにする関数に適用できます。使用の際に私のデコレータはどれくらいうそですか?

def sequenceable(func): 
    def newfunc(arg): 
     if hasattr(arg, '__iter__'): 
      if isinstance(arg, dict): 
       return dict((k, func(v)) for k, v in arg.iteritems()) 
      else: 
       return map(func, arg) 
     else: 
      return func(arg) 
    return newfunc 

:これは、コード(Pythonの2.5)である

@sequenceable 
def unixtime(dt): 
    return int(dt.strftime('%s')) 

>>> unixtime(datetime.now()) 
1291318284 
>>> unixtime([datetime.now(), datetime(2010, 12, 3)]) 
[1291318291, 1291352400] 
>>> unixtime({'start': datetime.now(), 'end': datetime(2010, 12, 3)}) 
{'start': 1291318301, 'end': 1291352400} 

は、私の質問は以下のとおりです。

  • これはひどいアイデア、そしてなぜ?
  • これはおそらく良いアイデアですか、実装されると重大な欠点がありますか?
  • このコードを使用した の潜在的な落とし穴は何ですか?
  • は既に私がやっていることをしている組み込みやライブラリはありますか?
+0

これは 'map'とは異なりますか?そして、理解をリストアップしないでください。既に混雑しているコンセプト空間に第3の技術を追加するのはなぜですか? 'map'とlist comprehensionsをどのように改善するか説明してください。 –

+0

map()より改善されていません。 * map()の短縮形です。 map()にはおそらく1つは必要ないが、iteritems() - > list comprehension - > dict()にはメリットがあるかもしれないことに同意する。 –

答えて

8

このは、という恐ろしいアイデアです。これは本質的に緩いタイピングです。ダックタイピングはこれまでのところ ものを取るべきです、IMO。

def pluralize(f): 
    def on_seq(seq): 
     return [f(x) for x in seq] 
    def on_dict(d): 
     return dict((k, f(v)) for k, v in d.iteritems()) 
    f.on_dict = on_dict 
    f.on_seq = on_seq 
    return f 

あなたの例として、この方法はまだ渡されたとのdoesnされているもの(ダックタイピング精度内に)知って、発信者を必要とし、それをやって

@pluralize 
def unixtime(dt): 
    return int(dt.strftime('%s')) 


unixtime.on_seq([datetime.now(), datetime(2010, 12, 3)]) 
unixtime.on_dict({'start': datetime.now(), 'end': datetime(2010, 12, 3)}) 

を次のようになります。

はこの考えてみましょう実際の関数にtypecheckingオーバーヘッドを追加しないでください。また、任意のdict-likeオブジェクトでも機能しますが、元のソリューションは実際のサブクラスであるdictに依存します。

+0

私は、あなたが@ pluralizeによってdef unixtime()を装飾したことを意味すると思います。私はこの例を試してみました。それはその方法で働き、私が望んでいたものを拡張性の点で達成しました。良いショー! –

+0

これはいい考えです。 @Brent Newey。 – werehuman

+0

訂正していただきありがとうございます:)嬉しいです。 – aaronasterling

1

私は発信者をあまりにも助けようとしているのではありません。 Pythonは、呼び出し元が "リスト"を扱うのは大したことではないと表現しています。発信者がdictの通話またはmap通話を書き留めるのは簡単です。

Pythonの標準ライブラリ関数がこのように私を助けないので、私がしなければならないと思うPythonプログラマです。このイディオムは、実際に私がもう少し混乱させているのは、どのメソッドが「有用な」ものではないのかを覚えておく必要があるからです。

私はPythonベースのビルドツールSConsにはあまりにも柔軟性がありません。その方法はすべて非常に適応しています。いくつかのプリプロセッサ定義を設定したい場合は、文字列、文字列、タプル、dictなどのリストを与えることができます。これは非常に便利ですが、圧倒的です。

env = Environment(CPPDEFINES='xyz')    # -Dxyz 
env = Environment(CPPDEFINES=[('B', 2), 'A'])  # -DB=2 -DA 
env = Environment(CPPDEFINES={'B':2, 'A':None}) # -DA -DB=2 
+0

これも私の最初の反応でした。ブレントの最後の例を参照してください。彼のデコレータは辞書の中で "マップ"し、各キーとそのキーの値に関する関数の結果を関連づけます。 (私は思う...) –

+0

データに作用したり、文字をエスケープしたり、文字列をスクラブしたり、日付を変換したりするユーティリティがたくさんあります。多くのマップ、リスト内包、変換私はこれがこれらの頻繁なタスクを達成するために余分なコードの量を減らすかもしれないと思った。 –

+0

@ダン正しいです。これは、データ構造全体に頻繁にマッピングされる関数の略語として設計されています。 –

2

私の意見では、ロジックを間違った場所に組み込んでいるようです。 unixtimeはなぜシーケンシングについて知っているのですか?場合によっては(パフォーマンスやセマンティクスのために)良いアイデアになるかもしれませんが、ここでは、その文脈で意味をなさない余分な機能をunixtimeに追加しているようです。

より良いだけで(例えば)リストの内包表記を使用することです:

[unixtime(x) for x in [datetime.now(), datetime(2010, 12, 3)]] 

そのように、あなたは適切なPython的には配列と同じものを適用するための構築使用している、とあなたはunixtimeを汚染していませんシーケンスに関するアイディアを持っています。実装がその知識から解放されなければならない場所では、結合ロジック(シーケンスについて)が終了します。

編集: 基本的にコーディングスタイル、再利用性、保守性が低下します。コードをよく分割したいので、unixtime(たとえば)をコーディングするときは、unixtimeに変換することに専念することになります。次に、シーケンスに興味がある場合は、シーケンスに専念する機能を設計します(または組み込み構文を使用します)。これにより、コードの各操作、テスト、デバッグ、再利用について明確に考えることが容易になります。名前についても考えてみましょう。元の関数は適切にunixtimeと呼ばれますが、より適切にはunixtime_sequenceと呼ばれることがあります。これは奇妙なことであり、珍しい機能を示唆しています。

もちろん、そのルールを破ることがあります。パフォーマンスが問題になる場合(ただしその場合のみ)、機能を組み合わせることができます。しかし、一般的には、最初のものを明確な部分に分割することで、明確な思考、明確なコーディング、簡単な再利用が可能になります。

+0

よろしくお願いいたします。なぜこれが悪いのかを知ることに興味があります。これが問題を混乱させるか、または私の顔に爆破するかの例を教えてください。 –

+0

@Brent:もう少し詳細を追加しました。 – Peter

0

ない神託の理由: - 明示的なPythonでの暗黙的な よりも良いと考えている - それは、組み込みのマップやリスト内包

0
@sequence 
def distance(points): 
    return sqrt(reduce(
     lambda a, b: a + b, 
     (a**2 for a in points), 
     0)) 

を使用してのような標準的なイディオムではありませんそして、あなたのデコレータは無駄になってしまいます。あなたのデコレータは特別な場合にのみ適用することができます。もしあなたがそれを使っているなら、Python Zenのルールの1つを破ります。

+0

デコレータは、スカラー値をとる関数でのみ動作するように設計されています。しかし、私は議論を理解しています。 –

関連する問題