105

Pythonを学習していて、いくつかの基本的な疑問があります。

1.変数宣言(パスはこちら)を次のように見ました

class writer:
    path = ""

場合によっては、明示的な宣言はありませんが、を介して初期化し__init__ます。

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

の目的は理解して__init__いますが、他の関数で変数を宣言することをお勧めします。

2.カスタム型を保持する変数を作成するにはどうすればよいですか?

class writer:
    path = "" # string value
    customObj = ??
4

6 に答える 6

225

さて、まず最初に。

Python には「変数の宣言」や「変数の初期化」というものはありません。

単に「割り当て」と呼ぶものがありますが、おそらく「ネーミング」と呼ぶべきでしょう。

割り当てとは、「左側のこの名前は、以前に何を参照していたかに関係なく、右側を評価した結果を参照するようになった」ことを意味します。

foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication

そのため、Python の名前 (おそらく「変数」よりも適切な用語) には関連する型がありません。値はそうです。タイプに関係なく、同じ名前を何にでも再適用できますが、そのタイプに依存する振る舞いは依然として存在します。名前は、単に値 (オブジェクト) を参照する方法です。これは 2 番目の質問に答えます:カスタム型を保持する変数を作成しません。特定の型を保持する変数を作成しません。変数をまったく「作成」しません。オブジェクトに名前を付けます。

2 番目のポイント: Python は、クラスに関して非常に単純な規則に従います。これは、Java、C++、C# などの言語よりも実際にははるかに一貫性があります。ブロック内で宣言されたものはすべてclass、クラスの一部です。したがって、ここに記述された関数 ( def) はメソッド、つまりクラス オブジェクトの一部 (インスタンスごとに保存されない) であり、Java、C++、および C# と同様です。ただし、ここにある他の名前クラスの一部です。繰り返しますが、名前は単なる名前であり、関連付けられた型はありません。Python では関数もオブジェクトです。したがって:

class Example:
    data = 42
    def method(self): pass

Python では、クラスもオブジェクトです。

これで、 であるすべてのもののクラスを表すという名前のオブジェクトが作成されました。このオブジェクトには、2 つのユーザー指定の属性があります(C++ では「メンバー」、C# では「フィールドまたはプロパティまたはメソッド」、Java では「フィールドまたはメソッド」)。それらの 1 つに名前が付けられ、整数値が格納されます。もう 1 つは という名前で、関数オブジェクトを格納します。(Python が自動的に追加する属性が他にもいくつかあります。)ExampleExampledata42method

ただし、これらの属性は実際にはオブジェクトの一部ではありません。基本的に、オブジェクトは複数の名前 (属性名) の集まりにすぎません。これ以上分割できないものに到達するまでは。したがって、意図的に設定すれば、クラスの異なるインスタンス間、または異なるクラスのオブジェクト間で値を共有できます。

インスタンスを作成しましょう:

x = Example()

xこれで、 のインスタンスであるという名前の別のオブジェクトができましたExampledataとは実際にはオブジェクトの一部ではありませんが、Python が舞台裏で行ういくつかの魔法により、methodこれらを参照することはできます。特にxを検索すると、代わりに「バインドされたメソッド」が得られます (呼び出すと、パラメータとして自動的に渡されますが、直接検索すると発生しません)。methodxselfExample.method

を使おうとするとどうなりますx.dataか?

それを調べると、最初にオブジェクトで検索されます。オブジェクトに見つからない場合、Python はクラスを調べます。

ただし、 に割り当てると x.data、Python はオブジェクトに属性を作成します。クラスの属性は置き換えられません。

これにより、オブジェクトの初期化を行うことができます。__init__Python は、新しいインスタンスが作成されたときに、そのクラスのメソッドを自動的に呼び出します (存在する場合)。このメソッドでは、単純に属性に割り当てて、各オブジェクトのその属性の初期値を設定できます。

class Example:
    name = "Ignored"
    def __init__(self, name):
        self.name = name
    # rest as before

nameを作成するときに を指定する必要がありExample、各インスタンスには独自の がありnameます。インスタンスの属性が最初に見つかるため、Python はインスタンスのExample.nameを検索するたびにclass 属性を無視します。.name

最後の警告:変更 (突然変異) と代入は別物です!

Python では、文字列は不変です。それらは変更できません。あなたがするとき:

a = 'hi '
b = a
a += 'mom'

元の「hi」文字列は変更しません。それはPythonでは不可能です。代わりに、新しいstring'hi mom'を作成し、 が の名前ではなくなり、代わりに のa名前'hi 'になり始め'hi mom'ます。bにも名前を付けました。名前を再'hi '適用した後も、まだ存在し、変更されていないため、 のa名前bのままです。'hi ''hi '

ただし、リストは変更できます。

a = [1, 2, 3]
b = a
a += [4]

これbも [1, 2, 3, 4]bです。同じ名前の名前を付けてから、そのa名前を変更したからです。aPython は単純にリストの扱いが+=異なるため、 to nameの新しいリストを作成しませんでした。

クラス属性としてリストがあり、インスタンスを使用してリストを変更した場合、変更は他のすべてのインスタンスで「見られる」ため、これはオブジェクトにとって重要です。これは、(a) データが実際にはクラス オブジェクトの一部であり、インスタンス オブジェクトではないためです。(b) リストを変更していて単純な代入を行っていないため、クラス属性を隠す新しいインスタンス属性を作成していません。

于 2012-06-13T04:43:20.467 に答える
24

Python で新しい変数を宣言する必要はありません。関数またはモジュール内の変数について話している場合、宣言は必要ありません。必要な場所の名前に値を割り当てるだけです: mymagic = "Magic". Python の変数は、任意の型の値を保持でき、それを制限することはできません。

あなたの質問は、クラス、オブジェクト、インスタンス変数について具体的に尋ねています。インスタンス変数を作成する慣用的な方法は、メソッド内にあり、それ以外の場所には__init__ありません。新しいインスタンス変数を他のメソッドや無関係なコードで作成することもできますが、それは単に悪い考えです。コードの推論や保守が難しくなります。

たとえば、次のようになります。

class Thing(object):

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

簡単。このクラスのインスタンスには次のmagic属性があります。

thingo = Thing("More magic")
# thingo.magic is now "More magic"

クラス自体の名前空間で変数を作成すると、まったく異なる動作になります。これは機能が異なるため、特定の理由がある場合にのみ実行してください。例えば:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

今試してみてください:

thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1

または:

class Thing(object):

    magic = ["More", "magic"]

    def __init__(self):
        pass

thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]

これは、クラス自体の名前空間が、そこから作成されたオブジェクトの名前空間と異なるためです。もう少し研究するためにあなたに任せます。

持ち帰りのメッセージは、慣用的な Python は、__init__(a) メソッド内のオブジェクト属性を初期化し、(b) 必要に応じてクラスの動作を文書化することです。これまでに書いたすべてのことについて、本格的な Sphinx レベルのドキュメントを作成する必要はありませんが、少なくとも、あなたや他の誰かがそれを取得するために必要な詳細についてのコメントがいくつかあります。

于 2012-06-13T03:38:41.130 に答える
2

変数にはスコープがあるため、関数に固有の変数を持つことが適切です。それらの定義について常に明示する必要はありません。通常はそのまま使用できます。リストの追加など、変数の型に固有のことをしたい場合にのみ、それらを使用する前にそれらを定義する必要があります。これの典型例。

list = []
for i in stuff:
  list.append(i)

ところで、これは実際にはリストをセットアップする良い方法ではありません。次のように言うほうがよいでしょう:

list = [i for i in stuff] # list comprehension

...しかし、私は脱線します。

あなたの他の質問。カスタム オブジェクトは、クラス自体である必要があります。

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()
于 2012-06-13T03:12:16.607 に答える