2

「Think Like a Computer Scientist」の問題 17.6 の一部として、Kangaroo というクラスを作成しました。

class Kangaroo(object):

    def __init__(self, pouch_contents = []):
        self.pouch_contents = pouch_contents

    def __str__(self):
        '''
        >>> kanga = Kangaroo()
        >>> kanga.put_in_pouch('olfactory')
        >>> kanga.put_in_pouch(7)
        >>> kanga.put_in_pouch(8)
        >>> kanga.put_in_pouch(9)
        >>> print kanga
        "In kanga's pouch there is: ['olfactory', 7, 8, 9]"
        '''

        return "In %s's pouch there is: %s" % (object.__str__(self), self.pouch_contents)

    def put_in_pouch(self, other):
        '''
        >>> kanga = Kangaroo()
        >>> kanga.put_in_pouch('olfactory')
        >>> kanga.put_in_pouch(7)
        >>> kanga.put_in_pouch(8)
        >>> kanga.put_in_pouch(9)
        >>> kanga.pouch_contents
        ['olfactory', 7, 8, 9]
        '''

        self.pouch_contents.append(other)

私を夢中にさせているのは、書かれているようにユニットテストに合格する文字列メソッドを書きたいということ__str__です。代わりに私が今得ているのは:

In <__main__.Kangaroo object at 0x4dd870>'s pouch there is: ['olfactory', 7, 8, 9]

基本的に、関数の出力がこれらの5文字、つまり関数(カンガ)->「カンガ」になるように、カンガ=カンガルーで実行できる関数があるかどうか疑問に思っています。

何か案は?

編集: 最初の回答を読んで、元の質問をもっと簡潔に尋ねる方法があることに気付きました。__init__次のコードが書かれたとおりに有効になるように書き換える方法はありますか?

>>> somename = Kangaroo()
>>> somename.name
'somename'
4

5 に答える 5

6

あなたの要求を大局的に見るために、このコードによって作成されたオブジェクトに付けたい名前を説明してください:

marsupials = []
marsupials.append(Kangaroo()) 

effbot によるこの古典的なエッセイは、優れた説明を提供します。

編集で修正された質問に答えるには: いいえ。

コメントで明確になり、この命名演習の全体的な目的は、変更可能なデフォルト引数に関連付けられたデバッグ目的でオブジェクトを区別することであると述べました。

Python の CPython 実装では、少なくとも任意の時点で、既存のすべてのオブジェクトに一意の ID があり、id(obj). デバッグ目的にはこれで十分な場合があります。オブジェクトが削除された場合、その ID (メモリアドレス) は、その後作成されたオブジェクトで再利用できることに注意してください。

于 2010-08-22T22:20:31.503 に答える
2

これを投稿するつもりはありませんでしたが、デバッグのためだけにこれが必要な場合は、ここに行きます:

import sys

class Kangaroo(object):
    def __str__(self):
        flocals = sys._getframe(1).f_locals
        for ident in flocals:
            if flocals[ident] is self:
                name = ident
                break
        else:   
            name = 'roo'
        return "in {0}'s pouch, there is {1}".format(name, self.pouch_contents)

kang = Kangaroo()
print kang

これは CPython (AFAIK) に依存しており、プロダクション コードには適していません。インスタンスが何らかのコンテナにある場合は機能せず、いつでも何らかの理由で失敗する可能性があります。ただし、それはあなたのためにトリックを行う必要があります。

が呼び出されるf_locals名前空間を表すスタック フレームからディクショナリを取得することによって機能します。print kangのキーはf_localsフレーム内の変数の名前であるため、ループして各エントリが であるかどうかをテストしますself。もしそうなら、私たちはbreak。が実行されない場合breakは、エントリが見つからず、loopselse句が要求どおりに値 'roo' を割り当てます。

ある種のコンテナから取り出したい場合は、これを拡張して、 内のすべてのコンテナを調べる必要がありますf_locals。辞書のようなコンテナーの場合はキーを返すか、タプルやリストのような場合はインデックスを返すことができます。

于 2010-08-23T00:32:53.477 に答える
2
class Kangaroo(object):

    def __init__(self, pouch_contents=None, name='roo'):
        if pouch_contents is None:
            self.pouch_contents = []  # this isn't shared with all other instances
        else:
            self.pouch_contents = pouch_contents
        self.name = name
    ...

kanga = Kangaroo(name='kanga')

引数の前後にスペースを入れないのが良いスタイルであることに注意してください=

于 2010-08-22T23:03:19.700 に答える
0

これに取り組み始めたとき、aaronasterlingのハックな答えは見たことがありませんでしたが、いずれにせよ、私自身のハックな答えは次のとおりです。

class Kangaroo(object):

    def __init__(self, pouch_contents = ()):
        self.pouch_contents = list(pouch_contents)

    def __str__(self):
        if not hasattr(self, 'name'):
            for k, v in globals().iteritems():
                if id(v) == id(self):
                    self.name = k
                    break
                else:
                    self.name = 'roo'                    
        return "In %s's pouch there is: %s" % (self.name, self.pouch_contents)

kanga = Kangaroo()
print kanga

これをおかしいと思って壊すことはできますが (書かれているとおりに動作しますが、doctest の一部として失敗します)、動作します。私は、私の学習経験の現時点では、実際に何ができるかよりも、何ができるかに関心があるので、私ができるはずだと考えたことを実行するための少なくとも 2 つの異なる方法があることを知ってうれしく思います。たとえそれが悪い方法であっても。

于 2010-08-23T07:18:31.777 に答える
0

提案された「ハック」があっても、Pythonでは基本的に不可能です。たとえば、次のコードは何を出力しますか?

>>> kanga1 = kanga2 = kanga3 = Kangaroo()
>>> kanga2.name 
???
>>> kanga3.name
???

また

>>> l = [Kangaroo()]
>>> l[0].name
???

「名前付き」オブジェクトが必要な場合は、オブジェクトに名前を指定するだけです

def __init__(self, name):
    self.name = name

より明示的 (これは Python で気に入っています) であり、すべての場合で一貫しています。確かにあなたは次のようなことができます

>>> foo = Kangaroo("bar")
>>> foo.name
'bar'

ただし、foo は、インスタンスが持つ可能性のある多くのラベルの 1 つにすぎません。名前は明示的で永続的です。必要に応じて、一意の名前を強制することもできます (変数は、さまざまなオブジェクトに対して必要なだけ再利用できます)。

于 2010-08-23T07:37:23.613 に答える