2

まず第一に、私はJavaとPHPのバックグラウンドから来て、現在Pythonを学んでいます。したがって、これはばかげた質問のように思えるかもしれませんが、少し混乱しています。

php の例として:

class MyClass
{
   private $myMember;

   public function __construct($myMember = null)
   {
       $this->myMember = $myMember;
   }

   public function setMyMember($myMember)
   {
       $this->myMember = $myMember;
   }

   public function getMyMember()
   {
       return $this->myMember;
   }

}

これは完全に教科書 101 OOP です。1 つのプライベート メンバーとゲッターとセッターを持つクラス。

ただし、いくつかの python を学習すると、これはそれほど簡単ではないようです。

まず、コンストラクターは実際のコンストラクターではありません (ただし、 at such?? を使用できます)

次に、クラス レベルの減速は静的として扱われますか?? だから、Pythonのself.myMemberは、実際にはクラスレベルのmyMemberと同じではないインスタンスに別の変数を設定しますか?

最後に、私の混乱が正しければ、上記の同じ例を Python でどのようにコーディングしますか?

4

4 に答える 4

4

通常、Python ではゲッターとセッターを使用しません。値を変換する必要がある場合、設定または取得中に副作用が必要な場合、または取得または設定を防止する必要がない場合は、代わりに属性を使用します。

class MyClass(object):
    def __init__(self, member):
        self.member = member

インスタンス属性はクラス属性とは別のものです。属性を on に設定するselfと、インスタンスを操作していることを意味します。クラスの属性 ( MyClass.member) はクラス属性であり、インスタンス間で共有されます。これは、属性を検索するときにクラスをフォールバックとして使用することによって実現されます。最初にインスタンスがクエリされ、次にインスタンスのクラスがクエリされ、次にクラスの基本クラスがクエリされます。設定は、インスタンスに表示されなくなっself.memberたことを意味します。MyClass.member

__init__メソッドは実際、技術的にはコンストラクターではありません。が呼び出されたselfときにすでに存在します。__init__代わりに初期化子であり、最初の値を設定します。実際のコンストラクタ (インスタンス ファクトリ) が必要な場合は、代わりに__new__静的メソッドを探す必要があります。PHP では__construct、コンストラクターではなく、イニシャライザーでもあることに注意してください。

セッターとゲッターを作成する必要がある場合は、デコレータ関数property使用します。

class MyClass(object):
    def __init__(self, member):
        self._member = member

    @property
    def member(self):
        return 'Hello {}!'.format(self._member)

    @member.setter
    def member(self, value):
        # Remove "Hello " and "!" from the start and end of any value being set.
        if value.startswith('Hello '):
            value = value.split(None, 1)[1]
        self._member = value.rstrip('!')

デモ:

>>> m = MyClass('World')
>>> m.member
'Hello World!'
>>> m.member = 'Hello Planet Earth!'
>>> m.member
'Hello Planet Earth!'
>>> m._member
'Planet Earth'
于 2013-05-25T15:17:55.650 に答える
3

これは次のようになります。

class MyClass(object):

    def __init__(self, myMember=None):
        self._myMember = myMember

    @property
    def myMember(self):
        return self._myMember

    @myMember.setter
    def myMember(self, value):
        self._myMember = value

デモ:

c = MyClass()
c.myMember = 10
print c.myMember

そして、あなたは持っています:

# 10
于 2013-05-25T15:17:44.460 に答える
1

Java/PHP から来た場合、Python がオブジェクト指向をどのように行うかについて知っておく必要があるいくつかのポイントを次に示します。


Python では、クラスも完全に普通のオブジェクトです。つまり、クラス自体がメンバー変数を持つことができます (通常は属性と呼びます)。クラス ブロックで割り当てた名前はすべて、そのインスタンスの属性ではなく、クラス自体の属性になります (defメソッドを作成する関数ブロックを含みます。メソッドはすべて Python にあります)。

通常は 1 つのクラスと多数のインスタンスがあるため、クラス属性は Java クラスの静的変数と同様の目的を果たすことができますが、まったく同じ概念ではありません。

クラス ブロックで名前を割り当てても、クラスの実際のインスタンスに属性が作成されることはありません。オブジェクト (任意のオブジェクト、クラス、または通常のインスタンス) に属性を作成する唯一の方法は、それが存在するときに属性を割り当てることです。したがって、クラスのインスタンスが持つすべての変数の標準的な宣言は__init__、Python のメソッドに存在し、属性を に割り当てる必要がありますself

例えば:

class Foo(object):
    foo = "I am a class attribute"

    def __init__(self):
        self.bar = "I am an instance attribute"

これが新しい Python プログラマーをしばしば混乱させるのは、インスタンスから属性を読み取ろうとする試みが実際fooに機能し、クラス属性を見つけることです (これは、メソッド呼び出しが呼び出すはずの関数を見つける方法です)。そのため、クラス ブロックでインスタンス属性を宣言することは、最初のカジュアルな遊びのように見えます。しかし、実際にはfoo、すべてのインスタンス間で共有される属性は 1 つだけです。これは、可変オブジェクトであり、各インスタンスに独自のコピーがあると予想される場合、非常に悪い可能性があります。


Python にはアクセス制御がないため、プライベート変数のようなものはありません。これは、Python が十分に動的であるため、そのような制限をいつでも回避できるため、少し無意味になります。

代わりに、Python プログラマーは、クライアント コードを記述するプログラマーがどの名前がパブリック API の一部であり、どの名前が実装の詳細であるかを確実に把握できるようにするために、ドキュメントと規則に依存する傾向があります。次に、誰もがルールをほぼ尊重し、コードを処理する必要がないものは、変更に頼るべきではないと信じています。

とにかく、どの言語でも、単純なゲッターとセッターを持つ属性は実際には「パブリック」です。考えられる唯一の懸念は、「いつか」getter/setter の実装を変更して、インターフェイスを変更しないと簡単ではなくなることです。Python は、プロパティを使用してこの問題に対処できます (基本的に、属性の読み取りまたは書き込みのように見えるメソッド呼び出しを行うことができます)。そのため、実際に何かが行われている場合を除き、getter/setter メソッドを使用する理由はまったくありません。

そのため、通常、クライアント コードがオブジェクトを操作するためのインターフェイスにフィールドの読み取りと書き込みが含まれる場合は、通常の属性が読み取りと書き込みに使用できることを単純に文書化します。属性 (またはメソッド) が純粋に内部使用であることを明確にしたい場合は、通常、名前を 1 つのアンダースコアで開始します。これにより、その名前を使用する人は誰でも内部名にアクセスしていることを知ることができます (先頭のアンダースコアを入力する必要があるため)。そのため、誰かが「誤って」プライベート属性を使用することを心配する必要はありません。


コンストラクターに関しては、__init__メソッドを__constructPHP からのものとして扱うだけで、期待どおりに動作します (ただし、Python メソッドは明示的にパラメーターを受け取ることを忘れないでselfください。暗黙的ではありませんthis)。

__init__コンストラクターとは多少異なるこの神話が広まっているため、コンストラクターと呼ぶべきではありません。私が知る限り、犯人はDive Into Pythonであり、奇妙なことに次のように述べています。

これをクラスのコンストラクターと呼ぶのは魅力的ですが、正しくありません。コンストラクターのように見え (慣例により__init__、クラスに対して定義された最初のメソッド)、コンストラクターのように動作し (クラスの新しく作成されたインスタンスで実行される最初のコード部分)、さらにはコンストラクターのように聞こえる ( 「init」は確かにコンストラクターっぽい性質を示唆しています)。が呼び出されるまでにオブジェクトが既に構築されており__init__、クラスの新しいインスタンスへの有効な参照が既に存在するため、不正解です。

しかし、「オブジェクト__init__は呼び出されるまでにすでに構築されており、クラスの新しいインスタンスへの有効な参照がすでにある」というのは、従来のコンストラクターがどのように機能するかを正確に特徴付けているため、作成者がそこで何をしようとしているのかわかりません.

( Python のドキュメントが取っているように見える公式の行は、それMyClass(arg1, arg2)コンストラクター式__init__であるというものです。どちらも__new__、コンストラクター式に与えられた引数を受け取ると説明されており、__init__明示的にコンストラクターと呼ばれています。これらの用語は両方ともめったに使用されません。ドキュメントでは、彼らは__init__ほとんどいつも言っているだけです。)

したがって、これはコンストラクターではないと言う人を無視することを強くお勧めします。コンストラクターとの類推によって理解しようとする方が、コンストラクターとコンストラクターとの間の重要な違いを理解しようとする__init__よりもはるかに優れています。__init____init__


以上をまとめると、PHP クラスの慣用的な翻訳は次のようになります。

class MyClass(object):
    def __init__(self, myMember):
        self.myMember = myMember
于 2013-05-25T16:49:04.200 に答える