web-dev-qa-db-ja.com

strまたはintからの継承

Str(またはintからも)を継承するクラスの作成に問題があるのはなぜですか

class C(str):
   def __init__(self, a, b):
     str.__init__(self,a)
     self.b = b

C("a", "B")

TypeError: str() takes at most 1 argument (2 given)

intの代わりにstrを使用しようとすると、同じことが起こりますが、カスタムクラスで動作します。 __new__ではなく__init__を使用する必要がありますか?どうして?

49
Ruggero Turra
>>> class C(str):
...     def __new__(cls, *args, **kw):
...         return str.__new__(cls, *args, **kw)
... 
>>> c = C("hello world")
>>> type(c)
<class '__main__.C'>

>>> c.__class__.__mro__
(<class '__main__.C'>, <type 'str'>, <type 'basestring'>, <type 'object'>)

__init__は、オブジェクトの構築後に呼び出されます。不変タイプの値を変更するには遅すぎます。ご了承ください __new__はクラスメソッドなので、最初のパラメーターclsを呼び出しました

詳細は こちら を参照してください

>>> class C(str):
...     def __new__(cls, value, meta):
...         obj = str.__new__(cls, value)
...         obj.meta = meta
...         return obj
... 
>>> c = C("hello world", "meta")
>>> c
'hello world'
>>> c.meta
'meta'
67
John La Rooy

組み込み型を継承することは、あまり価値がありません。いくつかの問題に対処する必要があり、実際にはあまりメリットがありません。

ほとんどの場合、コンポジションを使用する方が適切です。 strを継承する代わりに、strオブジェクトを属性として保持します。

class EnhancedString(object):
     def __init__(self, *args, **kwargs):
         self.s = str(*args, **kwargs)

基になるstrself.sで作業するメソッドを手動で、または__getattr__を使用して自動で延期できます。

とはいえ、独自の文字列型が必要な場合は、一時停止する必要があります。文字列をメインデータとして格納するクラスは多数ありますが、一般的には、文字列の一般的な表現にstrまたはunicode(後者はテキストを表す場合)を使用する必要があります。 (1つの一般的な例外は、UIツールキットの文字列型を使用する必要がある場合です。)文字列に機能を追加する場合は、ではなく文字列を操作する関数を使用できるかどうかを試してください。 文字列として機能する新しいオブジェクト。これにより、コードがシンプルになり、他のすべてのプログラムとの互換性が高まります。

12
Mike Graham

クラスをインスタンス化すると、渡した引数がクラスの___new___(コンストラクタ)に渡され、次にクラスの___init___(初期化子)メソッドに渡されます。したがって、インスタンス化中に提供される可能性のある引数の数に制限があるクラスから継承する場合、その___new___も___init___も、期待するよりも多くの引数を取得しないことを保証する必要があります。それがあなたが抱えている問題です。 C("a", "B")を使用してクラスをインスタンス化します。インタプリタは、Cで___new___メソッドを探します。 Cにはないので、pythonはその基本クラスstrをのぞきます。そして1つあるので、その1つが使用され、両方に提供されますただし、_str.__new___は、(最初​​の引数としてのクラスオブジェクトのほかに)1つの引数のみを取得することを期待しています。そのため、TypeErrorが発生します。そのため、子クラスでそれを拡張する必要があります。 ___init___で行います。ただし、クラスインスタンスを返す必要があり、それがstaticメソッドであることを覚えておいてください(_@staticmethod_デコレータで定義されているかどうかに関係なく)。 super関数を使用するとカウントされます。

8
user2683246

使用する __new__不変タイプの場合:

class C(str):
    def __new__(cls, content, b):
        return str.__new__(cls, content)

    def __str__(self):
        return str.__str__(self)

a=C("hello", "world")
print a

printはhelloを返します。

Python文字列は不変の型です。関数 __new__が呼び出され、オブジェクトCの新しいインスタンスが作成されます。 python __new__ 関数は基本的に、不変タイプからの継承を可能にするために存在します。

5
zoli2k

this を注意深く読んだ後、strをサブクラス化する別の試みを次に示します。他の回答からの変更点は、super(TitleText, cls).__new__を使用して正しいクラスにインスタンスを作成することです。これは使用されるたびにstrのように動作するように見えますが、メソッドをオーバーライドすることができました:

class TitleText(str):
    title_text=""
    def __new__(cls,content,title_text):
        o=super(TitleText, cls).__new__(cls,content)
        o.title_text = title_text
        return o

    def title(self):
        return self.title_text

>>> a=TitleText('name','A Nice name')
>>> a
'name'
>>> a[0]
'n'
>>> a[0:2]
'na'
>>> a.title()
'A Nice name'

これにより、スライスと添字を正しく行うことができます。これは何のためですか?管理インデックスページのDjangoアプリケーションの名前を変更するため。

4