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__
を使用する必要がありますか?どうして?
>>> 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'
組み込み型を継承することは、あまり価値がありません。いくつかの問題に対処する必要があり、実際にはあまりメリットがありません。
ほとんどの場合、コンポジションを使用する方が適切です。 str
を継承する代わりに、str
オブジェクトを属性として保持します。
class EnhancedString(object):
def __init__(self, *args, **kwargs):
self.s = str(*args, **kwargs)
基になるstr
self.s
で作業するメソッドを手動で、または__getattr__
を使用して自動で延期できます。
とはいえ、独自の文字列型が必要な場合は、一時停止する必要があります。文字列をメインデータとして格納するクラスは多数ありますが、一般的には、文字列の一般的な表現にstr
またはunicode
(後者はテキストを表す場合)を使用する必要があります。 (1つの一般的な例外は、UIツールキットの文字列型を使用する必要がある場合です。)文字列に機能を追加する場合は、ではなく文字列を操作する関数を使用できるかどうかを試してください。 文字列として機能する新しいオブジェクト。これにより、コードがシンプルになり、他のすべてのプログラムとの互換性が高まります。
クラスをインスタンス化すると、渡した引数がクラスの___new__
_(コンストラクタ)に渡され、次にクラスの___init__
_(初期化子)メソッドに渡されます。したがって、インスタンス化中に提供される可能性のある引数の数に制限があるクラスから継承する場合、その___new__
_も___init__
_も、期待するよりも多くの引数を取得しないことを保証する必要があります。それがあなたが抱えている問題です。 C("a", "B")
を使用してクラスをインスタンス化します。インタプリタは、C
で___new__
_メソッドを探します。 C
にはないので、pythonはその基本クラスstr
をのぞきます。そして1つあるので、その1つが使用され、両方に提供されますただし、_str.__new__
_は、(最初の引数としてのクラスオブジェクトのほかに)1つの引数のみを取得することを期待しています。そのため、TypeError
が発生します。そのため、子クラスでそれを拡張する必要があります。 ___init__
_で行います。ただし、クラスインスタンスを返す必要があり、それがstaticメソッドであることを覚えておいてください(_@staticmethod
_デコレータで定義されているかどうかに関係なく)。 super
関数を使用するとカウントされます。
使用する __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__
関数は基本的に、不変タイプからの継承を可能にするために存在します。
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アプリケーションの名前を変更するため。