2011-10-23 16 views
6

私はプログラムにコマンドラインパラメータで指定された秒数だけ、テキストファイルのすべてのタイムスタンプ( 'HH:MM:SS'の形式)を増やそうとしています。ここでpython:re.subの置換関数は余分な引数を受け付けません - どのようにグローバル変数を避けるのですか?

は私の努力の簡易版は、これまでのところです:

import re 
from datetime import datetime, timedelta 

time_diff = timedelta(seconds=10) 

def replace_time(matchobj): 
    if matchobj.group(1) not in [None, '']: 
     return (datetime.strptime(matchobj.group(1), "%H:%M:%S") + time_diff).strftime("%H:%M:%S") 

print re.sub('(\d\d:\d\d:\d\d)', replace_time, "01:27:55") 

これは正常に動作します:これを実行した結果は、私が欲しいものだけである01:28:05です。

しかし、グローバル変数を可能な限り少なくするべきだと聞いてきました。そこで、グローバル変数を使用する代わりにtime_diffを引数としてreplace_timeに渡す簡単な方法があるかどうか疑問に思っていました。

私は明白なことを試してみましたが、それは失敗しました:

def replace_time(matchobj, time_diff): 
    if matchobj.group(1) not in [None, '']: 
     return (datetime.strptime(matchobj.group(1), "%H:%M:%S") + time_diff).strftime("%H:%M:%S") 

time_diff = timedelta(seconds=10) 
print re.sub('(\d\d:\d\d:\d\d)', replace_time(matchobj, time_diff), "01:27:55") 

をこのエラーに:NameError: name 'matchobj' is not definedので、私はmatchobj直接渡すことはできません。

私はstandard re pagestandard re howtoを見ましたが、そこに必要な情報が見つかりませんでした。ここでグローバル変数を使用しないようにするにはどうすればよいですか?どういうわけかreplace_time関数に余分な引数を渡すことはできますか?前もって感謝します。

答えて

11

次のような閉鎖の関数をラップすることができます:

def increment_by(time_diff): 
    def replace_time(matchobj): 
     if matchobj.group(1) not in [None, '']: 
      return (datetime.strptime(matchobj.group(1), "%H:%M:%S") + time_diff).strftime("%H:%M:%S") 
    return replace_time 

time_diff = timedelta(seconds=10) 
print re.sub('(\d\d:\d\d:\d\d)', increment_by(time_diff), "01:27:55") 

それとも、このようSTDLIBからpartialを使用することができます。

from functools import partial 

def replace_time(time_diff, matchobj): 
    if matchobj.group(1) not in [None, '']: 
     return (datetime.strptime(matchobj.group(1), "%H:%M:%S") + time_diff).strftime("%H:%M:%S") 

time_diff = timedelta(seconds=10) 
print re.sub('(\d\d:\d\d:\d\d)', partial(replace_time, time_diff), "01:27:55") 
+0

素晴らしい!私はちょうど両方のアプローチを試して、彼らは正常に動作しますが、私はまだどちらかがその魔法を理解していません。今私は3つの選択肢から選択する必要があります:(a)閉鎖を使用する、(b)部分を使う、または(c)David Heffernanの示唆しているように、グローバルを使い続ける。各オプションのトレードオフは何ですか?どのように決定する必要がありますか? – noumenon

+0

実際には、オプション(a)と(b)は同じです。なぜなら、 'partial'は私の' increment_by'がやっていることとほとんど同じです。もっと一般的です。実際、私はあなたのためにアイデアをよりよく理解するためにそれを書いてきました。 (b)と(c)については、ほとんどの場合、(b)を好むでしょう。まず、グローバルな状態は常に厄介なバグの原因です。第2に、Pythonのグローバル変数では、ルックアップがより高価です。 – dmedvinsky

+0

あなたとDavid Heffernanのアドバイスに基づいて、グローバルな選択肢を避けることに決めました。私は(b)ルートを私に最も合っていると思っており、理解しやすく使いやすく、私の問題をやや優雅に解決しています。ありがとう。 – noumenon

1

あなたの現在のアプローチに間違いはありません。 time_diffは一度だけ書き込まれ、その後のすべてのアクセスは読み取りになります。これはモジュールの幅広い定数に影響します。

複数のスレッドがオブジェクトにアクセスしており、少なくとも1つのスレッドが書き込みを行っているときに、共有グローバル状態に関する問題が発生します。それはここで起こっていないし、あなたは心配する必要はありません。

+0

感謝。私はしばしば、Pythonだけでなくプログラミングの一般的なプラクティスとして、疫病のようなグローバル変数を避けるためのアドバイスを見てきました。だからこそ、私はグローバルなvarの使い方の代替案を探したかったのです。だから私はマルチスレッドをしていない場合はグローバル変数を持つことは大丈夫ですか? また、この特定のケースでは、後でモジュールを自分のコードから取り出して他のプログラムにインポートすると、グローバル変数は問題ないか、問題を引き起こす可能性がありますか? グローバル化するのがいいときのガイドラインを理解しようとしています。 – noumenon

+0

これをモジュールとして公開しようとするなら、それを関数にまとめて、おそらくクロージャのアプローチを使用します。 –

関連する問題