2017-09-24 3 views
2

浮動小数点のペアを含む複数の名前付きタプルを使用するプログラムのためのきれいな印刷手順を作成しようとしているときに、この問題が発生しました。partialを__str__として使用できません

の結果ので、私は、印刷時に浮動小数点数をフォーマットしたい
from collections import namedtuple 
Position = namedtuple('Position', 'x y') 
Vector = namedtuple('Vector', 'x y') 
Size = namedtuple('Size', 'width height') 

import math 
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi)) 

が長すぎる:

Position(x=3.141592653589793, y=3.141592653589793) Vector(x=3.141592653589793, y=3.141592653589793) Size(width=3.141592653589793, height=3.141592653589793) 

だから私は名前のタプルを印刷する機能を作成しました:

def pretty_float_pair(name, labels, obj): 
    """ 
    If labels = ('a', 'b') and object = (1.2345, 1.2345) returns: 
     'name(a=1.23, b=1.23)' 
    """ 
    return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1]) 

すべての型に対して名前とラベルを修正する必要があり、obj引数だけが異なるので、functools partialを使うことができると考えました。

from functools import partial 
Position.__str__ = partial(pretty_float_pair, 'Position', ('x', 'y')) 
Vector.__str__ = partial(pretty_float_pair, 'Vector', ('x', 'y')) 
Size.__str__ = partial(pretty_float_pair, 'Size', ('width', 'height')) 
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi)) 

しかし、私はそれが動作する関数を作成するためにラムダを使用する場合、これは驚くべきことにTypeError: pretty_float_pair() missing 1 required positional argument: 'obj'.

をスローします。私が望んで

Position.__str__ = lambda x: pretty_float_pair('Position', ('x', 'y'), x) 
Vector.__str__ = lambda x: pretty_float_pair('Vector', ('x', 'y'), x) 
Size.__str__ = lambda x: pretty_float_pair('Size', ('width', 'height'), x) 
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi)) 

プリント:

Position(x=3.14, y=3.14) Vector(x=3.14, y=3.14) Size(width=3.14, height=3.14) 

私は部分的なバージョンが動作しない理由を理解しようとしています。

+0

あなたの機能が適切に字下げされません。修正してください。私の答えを参照のために使うことができます。 –

+0

あなたの質問は閉鎖されましたが、投稿された質問の中から回答を選択する必要があります。 –

答えて

3

functools.partialは非ディスクリプタ呼び出し可能で、アンバインドされたメソッドにほぼ相当します。これは、実際にはクラスです。これは、表示されているエラーと一貫しているselfパラメータが渡されていないことを意味します。

ラムダはdefで定義された通常の関数と同様に動作するため、実際にはディスクリプタです。ラムダの__get__メソッドは、インスタンス内でxとして渡されるバインドされたバージョンを返します。

メソッドのように動作する部分関数を取得するには、代わりにfunctools.partialmethodを使用します。メソッドがバインドされている場合は、objを引数リストの先頭に移動して、selfを受け取る必要があります。ここで

はあなたの例である:

 
from functools import partialmethod 

def pretty_float_pair(obj,name, labels): 
    """ 
    If labels = ('a', 'b') and object = (1.2345, 1.2345), returns: 
     name(a=1.23, b=1.23) 
    """ 
    return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1]) 

Position.__str__ = partialmethod(pretty_float_pair, 'Position', ('x', 'y')) 
Vector.__str__ = partialmethod(pretty_float_pair, 'Vector', ('x', 'y')) 
Size.__str__ = partialmethod(pretty_float_pair, 'Size', ('width', 'height')) 

print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi)) 
1

機能descriptorsあることによって彼らの暗黙のself引数を取得:検索x.f構造をしてfにそれを供給するようにxを覚えメソッドオブジェクトを返します。 functools.partial(...)はディスクリプタを返さないため、特別な扱いを受けません。

+1

これは真実ではないので、ダウンホートするつもりはありませんが、答えが必要な解決策が必要です。今すぐあなたはちょうど最高のときに非常に洞察力のあるコメントを持っています。 –

+0

@MadPhysicist:質問には疑問符はありませんが、私はこれを書いて、 "私は部分バージョンがなぜ機能しないのか理解しようとしています。" –

+0

あなたは絶対に正しいです。 +1。 OPはそのような強い意義を持ち、私はとても疲れています。実際の質問とはまったく違うものを読んでいます。キャッチをありがとう。 –

関連する問題