2017-09-06 4 views
-1

は、ここで私が思い付く方法です:文字列のリストをループする方法、いくつかの文字列操作を操作して返す方法はありますか?

a = 'bats bear' 
b = 'cats pear' 

def sub_strings(a, b): 
    for s in [a, b]: 
     s = re.sub('\\b.ear\\b', '', s) 
    return a, b 

a, b = sub_strings(a, b) 

しかし、それがすべてでは動作しません。また、機能はまだ元の文字列('bats bear', 'cats pear')を出力します。このアプローチで何が問題になっていますか?

答えて

1

あなたが抱えている問題は、Pythonでは文字列(つまり、strタイプのオブジェクト)が不変オブジェクトであることです。文字列オブジェクトを変更することはできないため、文字列に対して実行する任意の関数は、元の文字列を決して変更しません。それは常には同じまま:

>>> s = 'abc' 
>>> s.replace('abc', 'def') # perform some method on s 
>>> print(s) # has s been changed? 
abC# NOPE 

あなたは、文字列の操作バージョンを取得したい場合は、あなたがどこかに操作したバージョンを保存してを返すことがあります。提供された他の答えは、これを行う方法を明確に示しています。

実際の問題については、ジェネレータを使用することをおすすめします。ジェネレータは、通常の関数とは大きく異なる動作をする関数です。これらの違いの1つは、ジェネレータ関数が単一の関数呼び出しのみで複数の結果(1つずつ)を生成できることです。

ジェネレータを作成するには、returnという単語を使用する代わりに、yieldを使用します。 *strings構文は関数が複数の引数を受け入れることを可能にすることを

a = 'bats bear' 
b = 'cats pear' 

def sub_string_gen(*strings): 
    for s in strings: 
     yield re.sub('\\b.ear\\b', '', s) 

a, b = sub_strings(a, b) # generator is "unpacked" here 

注:ここでは一例です。これらの引数は関数内で、stringsという名前のリストの下にあります。

上記のコードが動作する理由は、最後の行が自動的に実行されたジェネレータをアンパックすることです。つまり、各結果は一度に1つずつ生成され、対応する提供された名前に一度に1つずつ解凍されます。

は、あなたがこれを行うにしようとしないこと、しかし、注意してください:

a = sub_strings(a) # BAD! 

これは、あなたが期待するように動作しません。 a = sub_strings(a)がないので動作しません発電機;代わりにジェネレータを作成し、aに割り当てます。発電機は開梱されていない。用語解説:sub_stringsジェネレータ関数です。 sub_strings(a,b,c)は、ジェネレータを使用して、ジェネレータ機能を作成します。

が単一の名前に発電機を解凍するには、代わりに次の操作を行います。

a, = sub_strings(a) # Note the comma 

余分なコンマではなくシングルトンのシンボルのタプルにaになります。これにより、ジェネレータを孤立シンボル「a」に「解凍」することを通訳者に知らせることができます。

私はこの構文がとても好きです。なぜなら、必ずしも見た目が簡単ではないエラーを防ぐからです。たとえば、あなたがsub_stringsではなく、十分な変数にあまりにも多くの引数を指定した場合、それはあなたにエラーを与えるだろうし、あなたは問題がある知っている:あなたの発電機を使用する

>>> a, b = sub_strings(a, b, c) # extra c argument 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack (expected 2) 

もう一つの方法は、単に結果を詰め込むことですリストに、反復可能なオブジェクト(発電機は反復可能です)受け入れタプル、または何か他のもの:

>>> results = list(sub_strings(a, b, c, d, e, f)) 

は、同じことを別の非常に素晴らしい代替構文もあります。ここで私達は星を再び見る(それは "吹奏"と呼ばれる人もいる)。あなたも発電機を作るための関数を定義する必要はありません。最後に

>>> results = [*sub_strings(a, b, c, d, e, f)] 

:スプラットは前にそれが自動的に解凍したとほぼ同じ、一度ジェネレータつの値を「アンパック」。代わりにgenerator expressionと呼ばれるものを使用することもできます。

>>> a, b = (re.sub('\\b.ear\\b', '', s) for s in (a, b)) 

あなたは私たちが上に私たちの発電機を使用する場所のいずれかで、このような表現を使用することができます。

>>> results = list((re.sub('\\b.ear\\b', '', s) for s in (a, b))) 
>>> results = [*(re.sub('\\b.ear\\b', '', s) for s in (a, b))] 

はジェネレータ式と呼ばれる部分がジェネレータ関数の呼び出しを置き換えることを確認しますこれは、以前のバージョンのコードではジェネレータを生成します。ずっとあり

>>> results = [re.sub('\\b.ear\\b', '', s) for s in (a, b)] 

、はるかには、Pythonのジェネレータについて学ぶために:あなたの目標はlistある場合

しかし、さらに短い構文は単にリストの内包と呼ばれているものを使用することです。開始するにはにアクセスしてください。

1

この

a = 'bats bear' 
b = 'cats pear' 

def sub_strings(a, b): 
    result = [] 
    for s in [a, b]: 
     result.append(re.sub('\\b.ear\\b', '', s) ) 
    return result[0], result[1] 

a, b = sub_strings(a, b) 
4
s = re.sub('\\b.ear\\b', '', s) 

あなたはそれがないと思う何をしません試してみてください。ただの再バインドsという名前の変数がre.sub()によって返された変更された文字列に返されます。変数aまたはbは変更されません。ループ内のsの値を出力することで確認できます。

代わりにあなたはジェネレータを返すことができます。

def sub_strings(a, b): 
    return (re.sub(r'\b.ear\b', '', s) for s in (a, b)) 

リストの内包も動作します:

def sub_strings(a, b): 
    return [re.sub(r'\b.ear\b', '', s) for s in (a, b)] 

いずれかの方法で必要に応じて、結果は変数abに展開されます。

あなたはそれがパラメータの任意の数を受け入れるように機能を一般化を検討する必要があります

def sub_strings(*args): 
    return (re.sub(r'\b.ear\b', '', s) for s in args) 

今、あなたは任意の数の引数でそれを呼び出すことができます。

>>> print(list(sub_strings('bats bear', 'cats pear', 'rats hear'))) 
['bats ', 'cats ', 'rats '] 
>>> print(list(sub_strings('bats bear', 'cats pear', 'rats hear', 'gnats rear'))) 
['bats ', 'cats ', 'rats ', 'gnats '] 
関連する問題