5

私はこの主題についてたくさん書かれていることを知っています。しかし、私はそれの多くを吸収することはできません。おそらく、私はコンピュータサイエンスのトレーニングを受けずに、自分自身を教えている完全な初心者だからです。とにかく、もしあなたの頭脳がこの特定の例に耳を傾けるなら、あなたは私のような他の初心者を助けるでしょう。

そこで、次の関数を作成しました。これは、「funky.py」という独自のファイルであるため、(モジュールとして?)呼び出すと問題なく機能します。

端末に次のように入力します。

python classy.py

そしてそれはうまく動作します。

def load_deck():
    suite = ('Spades', 'Hearts')
    rank = ('2', '3')
    full_deck = {}
    i = 0
    for s in suite:
        for r in rank:
            full_deck[i] = "%s of %s" % (r, s)
            i += 1
    return full_deck

print load_deck()

しかし、同じ関数をクラスに入れると、エラーが発生します。

'classy.py'のコードは次のとおりです。

class GAME():
    def load_deck():
        suite = ('Spades', 'Hearts')
        rank = ('2', '3')
        full_deck = {}
        i = 0
        for s in suite:
            for r in rank:
                full_deck[i] = "%s of %s" % (r, s)
                i += 1
        return full_deck
MyGame = GAME()
print MyGame.load_deck()

次のエラーが発生します。

Traceback (most recent call last):
File "classy.py", line 15, in <module>
print MyGame.load_deck()
TypeError: load_deck() takes no arguments (1 given)

そこで、定義行を次のように変更しました。正常に機能します。

def load_deck(self):

'self'の使用を要求するクラスに関数を配置することについてはどうですか。私は「自己」が単なる慣習であることを理解しています。では、なぜ議論が必要なのですか?クラス内から呼び出された場合、関数の動作は異なりますか?

また、これはほとんど重要ですが、なぜ私のクラスはinitを使用しないで機能するのですか?initを使用すると、クラスで何ができますか?

基本的に、私が6歳のように誰かが私にこれを説明する時間があれば、それは助けになるでしょう。助けてくれてありがとう。

4

3 に答える 3

4

クラス定義で関数を定義すると、それをメソッド記述子に変える魔法が呼び出されます。foo.methodにアクセスすると、バインドされたメソッドが自動的に作成され、オブジェクトインスタンスが最初のパラメーターとして渡されます。@staticmethodデコレータを使用すると、これを回避できます。

__init__オプションのセットアップを行うためにクラスが作成されたときに呼び出されるメソッドです。__new__実際にオブジェクトを作成するものです。

下記は用例です

>>> class Foo(object):
    def bar(*args, **kwargs):
        print args, kwargs

>>> foo = Foo()
>>> foo.bar
<bound method Foo.bar of <__main__.Foo object at 0x01C9FEB0>>
>>> Foo.bar
<unbound method Foo.bar>
>>> foo.bar()
(<__main__.Foo object at 0x01C9FEB0>,) {}
>>> Foo.bar()

Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    Foo.bar()
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)
>>> Foo.bar(foo)
(<__main__.Foo object at 0x01C9FEB0>,) {}
于 2012-08-06T23:46:14.790 に答える
1

では、なぜ議論が必要なのですか?

クラスの現在のインスタンスの属性にアクセスします。

2つのメソッドを持つクラスがあるload_deckとしshuffleます。最後に(メソッドload_deckを呼び出して)デッキをシャッフルしますshuffle

Pythonでは、次のようにします。

class Game(object):
    def shuffle(self, deck):
        return random.shuffle(deck)

    def load_deck(self):
        # ...

        return self.shuffle(full_deck)

これをほぼ同等のC++コードと比較してください。

class Game {
    shuffle(deck) {
        return random.shuffle(deck);
    }
    load_deck() {
        // ...

        return shuffle(full_deck)
    }
}

shuffle(full_deck)オンラインでは、最初にというローカル変数を探します-これshuffleは存在しません、次に1つ上のレベルをチェックし、呼び出されたインスタンスメソッドを見つけますshuffle(これが存在しない場合は、正しい名前)

これは問題ありませんが、shuffleローカル変数を参照しているのか、インスタンスメソッドを参照しているのかは明確ではありません。このあいまいさに対処するために、instance-methodsまたはinstance-attributesにも次の方法でアクセスできますthis

...
load_deck() {
    // ...

    return this->shuffle(full_deck)
}

this引数として渡されないことを除いて、Pythonの自己とほとんど同じです。

self引数として有用であることがなぜ有用なのですか?FAQには、いくつかの理由が記載されています。これらは、 「Pythonの禅」の1行にまとめることができます。

Explicit is better than implicit.

これは、 The HistoryofPythonブログの投稿によって裏付けられています。

インスタンス変数への暗黙の参照のアイデアをあきらめることにしました。C ++のような言語では、this-> fooを記述して、インスタンス変数fooを明示的に参照できます(別のローカル変数fooがある場合)。したがって、このような明示的な参照をインスタンス変数を参照する唯一の方法にすることにしました。さらに、現在のオブジェクト( "this")を特別なキーワードにするのではなく、単に "this"(またはそれに相当するもの)をメソッドの最初の名前付き引数にすることにしました。インスタンス変数は、常にその引数の属性として参照されます。

明示的な参照を使用すると、メソッド定義に特別な構文を設定する必要も、変数ルックアップに関する複雑なセマンティクスについて心配する必要もありません。代わりに、最初の引数がインスタンスに対応する関数を定義するだけです。このインスタンスは、慣例により「自己」と呼ばれます。

于 2012-08-07T00:26:55.553 に答える
0

自分自身を使用するつもりがない場合は、おそらくメソッドをstaticmethodとして宣言する必要があります。

class Game:
    @staticmethod
    def load_deck():
        ....

これにより、通常はクラススコープ内の関数がインスタンスを引数として取るメソッドに変換される自動デフォルトパッキングが取り消されます。

使用しない引数を渡すことは、コードを読み取ろうとしている他の人を当惑させます。

ほとんどのクラスにはメンバーがいます。あなたのものはそうではないので、そのメソッドはすべて静的でなければなりません。プロジェクトが発展するにつれて、おそらくプロジェクト内のすべての関数にアクセスできるはずのデータが見つかり、それらを自分自身に入れて、すべての関数に渡します。

このコンテキストでは、アプリケーション自体がプライマリオブジェクトであり、__ init__は、これらの共有値をすべて初期化する関数にすぎません。

これは、オブジェクト指向スタイルへの第一歩であり、小さなデータがオブジェクト自体として使用されます。しかし、これはストレートスクリプトからオブジェクト指向プログラミングに移行する際の通常の段階です。

于 2014-08-31T23:30:01.153 に答える