2017-07-29 20 views
9

私はpython3でsprintfを実行したいが、%sが動作するための手動変換を行うことなく、生のバイトオブジェクトを使用したい。だから、バイトオブジェクトを「テンプレート」として取り出し、任意の数のオブジェクトを任意の数のオブジェクトとし、レンダリングされたバイトオブジェクトを返します。これは、python 2のsprintf%演算子が常に働いていた方法です。Python 3のバイトオブジェクトに対してsprintf形式の書式を設定するにはどうすればよいですか?

b'test %s %s %s' % (5, b'blah','strblah') # python3 ==> error 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
TypeError: %b requires bytes, or an object that implements __bytes__, not 'int' 

def to_bytes(arg): 
    if hasattr(arg,'encode'): return arg.encode() 
    if hasattr(arg,'decode'): return arg 
    return repr(arg).encode() 

def render_bytes_template(btemplate : bytes, *args): 
    return btemplate % tuple(map(to_bytes,args)) 

render_bytes_template(b'this is how we have to write raw strings with unknown-typed arguments? %s %s %s',5,b'blah','strblah') 

# output: b'this is how we have to render raw string templates with unknown-typed arguments? 5 blah strblah' 

しかし、パイソン2に、それはちょうどに建てられています:

'example that just works %s %s %s' % (5,b'blah',u'strblah') 
# output: 'example that just works 5 blah strblah' 

は、Python 3でこれを行うが、まだのpython 2の同じ性能を達成するための方法はありますか?私に何かが足りないと教えてください。ここでのフォールバックは、cythonで実装することです(または、これに役立つPython 3のライブラリがありますか?)しかし、文字列オブジェクトの暗黙的なエンコード以外の標準ライブラリから削除された理由はまだ分かりません。 format_any()のようなバイトメソッドを追加できませんか?ところで

、それはこの警官アウトのように単純ではありません。

def render_bytes_template(btemplate : bytes, *args): 
    return (btemplate.decode() % args).encode() 

は、私は不要なエンコード/デコードを行うにはしたくないが、バイトの引数はrepr'dの代わりにされているだけでなく、注射された生。

+1

Python 3はバグからあなたを守り、Python 2では水の下に隠れてしまったことに注意してください。たとえば、 'unicode:%s'%(u'Ünîcódæ '、) 'を実行してください。 –

答えて

1

このような機能はありますか?

class B(bytes): 
    def __init__(self, template): 
     self._template = template 

    @staticmethod 
    def to_bytes(arg): 
     if hasattr(arg,'encode'): return arg.encode() 
     if hasattr(arg,'decode'): return arg 
     return repr(arg).encode() 

    def __mod__(self, other): 
     if hasattr(other, '__iter__') and not isinstance(other, str): 
      ret = self._template % tuple(map(self.to_bytes, other)) 
     else: 
      ret = self._template % self.to_bytes(other) 
     return ret 

    def __imod__(self, other): 
     return self.__mod__(other) 

a = B(b'this %s good') 
b = B(b'this %s %s good string') 
print(a % 'is') 
print(b % ('is', 'a')) 

a = B(b'this %s good') 
a %= 'is' 
b = B(b'this %s %s good string') 
b %= ('is', 'a') 
print(a) 
print(b) 

この出力:

b'this is good' 
b'this is a good string' 
b'this is good' 
b'this is a good string' 
+1

正直なところ、私の質問が、デザインがパフォーマンスの面で邪魔になっているか、正直な質問であるかどうかはわかりません。あなたの貢献に感謝します。 1週間に誰も答えなければ、私はあなたに報酬を与えるでしょう。 – parity3

+0

私は公正な質問だと思いますが、パフォーマンスコストは.formatやf-stringsと比較しても分かりません。 – mattjegan

+1

.formatとf-stringsはdecode()を必要とするため、悪化する可能性があります。私はユニコードで作業することは一般的にバイトで作業するスピードの約半分であることを他の記事でオンラインで読んできました。だから恐ろしいことではありませんが、たくさんの作業負荷のために、あなたがやりたいことが他のバイトからバイトを構成しているときには痛いです。はい、答えは大きなオーバーホールである構成の前にすべての入力を絞ることです。 6人または他のヘルパーを使用しても、パフォーマンスの低下は解決されません。 print()コマンドは、バイトとユニコードの両方を受け入れることに注意してください(それほどではありません)。 – parity3

2
あなただけのあなたには、いくつかの bytesオブジェクトを開始するとき、あなたが %%=演算子をオーバーロードした新しい Bバイトのようなオブジェクトでラップすることを確認する必要があります

私はpython3でsprintfをやりたいのですが、%sを手動で変換する必要はありません。

これを機能させるには、すべての書式設定引数もすでにbytesである必要があります。

これはPy2から変更されました。これは、Unicode文字を含むUnicode文字列が導入されるとすぐにPy2実装がエラーを起こしやすいため、Unicode文字列もバイト文字列でフォーマットできます。 Pythonの2の

例えば:

In [1]: '%s' % (u'é',) 
Out[1]: u'\xe9' 

技術的には、開発者が意図したものが正しいですが、ありません。また、使用されているエンコーディングも考慮しません。 Pythonの3大藤で

:書式設定バイト文字列の場合

In [2]: '%s' % ('é',) 
Out[2]: 'é' 

、使用バイト文字列の引数(のみPy3.5 +)整数のよう

b'%s %s' % (b'blah', 'strblah'.encode('utf-8')) 

他のタイプは、バイト文字列に変換する必要があります同じように。

+0

質問に私の意見を再度執行してくれてありがとう。しかし、いくつかの不一致があります。 first off print()は、バイトオブジェクト、intオブジェクト、およびユニコードをとることができます。したがって、明示的ではないと主張することができます。さらに、正規のユニコード文字列は、%sがreprを持つもので動作することを可能にします。これも明示的ではありません。彼らはここで半分しか行きませんでした。それは混乱を加え、機能を減らすだけで何もしませんが、それは私の意見です。明らかに物事は変わりません。私は、python2のパフォーマンスを低下させないようにする、あるいは単にリモート呼び出しpython2を試みる回避策を開始する予定です。 – parity3

+0

明白なことを述べるために、 'print'は印刷用です。エンコードされたユニコード文字列とユニコード文字列自体を出力すると、出力が異なります。それは明白です。技術的には、どちらの場合でも、オブジェクトの '__repr__'または' __str__'が印刷目的で使用されます。 '通常のUnicode文字列'は他のUnicode文字列と一緒に動作します。これはPy3ではデフォルトです。したがって、repr文字列はUnicodeなので、 '__str__'と明示的にバイト文字列として設定されていないものもあります。これはPythonコア開発チームの決定であり、それに慣れなければなりません。 – danny

関連する問題