Python変数宣言


85

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

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

class writer:
    path = ""

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

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

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

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

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

12
そして、2番目の質問に関して:Pythonでは、変数にはタイプがありません:値にはタイプがあります。したがって、どの変数でもカスタムオブジェクトを保持できます。
jpaugh 2012年

4
名前/識別子を変数として考えるのをやめると役に立ちます。それらはオブジェクトへの参照です
John La Rooy 2012年

2
@gnibblerまたはそれらの名前
...–

1
@detly、名前は悪い選択だと思います。通常、物事には1つの名前しかありませんが、オブジェクトには複数の参照がある場合があります
John La Rooy 2012年

2
@JohnClementsですが、Pythonは数学のようには機能しません。Pythonを理解したい場合は、__name__属性を持つオブジェクトに「名前」があることを知っておく必要があります。すべてのオブジェクトに__name__属性があるわけではありませんが、それらへの参照を持つことはできます。「参照」を「名前」と呼び始めると、初心者は不利益を被ることになります。
John La Rooy 2017

回答:


202

さて、まず最初に。

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では、クラスもオブジェクトです。

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

ただし、これらの属性はまだ実際にはオブジェクトの一部ではありません。基本的に、オブジェクトは、分割できないものにたどり着くまで、より多くの名前(属性名)のバンドルにすぎません。したがって、意図的に設定した場合は、クラスの異なるインスタンス間、または異なるクラスのオブジェクト間で値を共有できます。

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

x = Example()

xこれで、のインスタンスである、という名前の別のオブジェクトができましたExampledataそしてmethod実際にオブジェクトの一部ではありませんが、我々はまだ経由でそれらを見ることができますxので、Pythonは背後でないことをいくつかの魔法の。method特に、ルックアップすると、代わりに「バインドされたメソッド」xが取得されます(これを呼び出すと、selfパラメーターとして自動的に渡されますExample.method。直接ルックアップした場合は発生しません)。

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

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

ただし、に割り当てると x.data、Pythonはオブジェクトに属性を作成します。それはなりませんクラスの属性を交換してください。

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

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

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

最後の注意点:変更(変更)と割り当ては別のものです!

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

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

あなたは変更されません、元の「ハイテク」の文字列を。それはPythonでは不可能です。代わりに、あなたが作成し、新しい文字列を'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は単に+=リストの扱いが異なるため、名前を付けるための新しいリストは作成しませんでした。

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


12
これが、それらを「識別子」と呼ぶ理由です。:-)
MartijnPieters

最後に、文字列の例の@Karl_Knechtelで、「b」という名前を付けないと、「hi」はどうなりますか?これはメモリリークですか?
heretoinfinity 2016

2
@heretoinfinity:いいえ; Pythonはガベージコレクションを使用して到達不能なオブジェクトを解放します
John Clements

変数宣言は、このビデオで詳しく説明されています:youtube.com/watch?v = ao2N37E-D9s
IshaqKhan19年

回答のために、このビデオをチェックアウトyoutube.com/...
タオN

23

これは6年遅れるかもしれませんが、Python 3.5以降では、次のような変数型を宣言します。

variable_name: type_name

またはこれ:

variable_name # type: shinyType

したがって、あなたの場合(CustomObjectクラスが定義されている場合)、次のことができます。

customObj: CustomObject

詳細については、これまたはそれを参照してください。


22

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は、(a)__init__メソッドのオブジェクト属性を初期化し、(b)必要に応じてクラスの動作を文書化することです。これまでに書いたすべてのことについて、本格的なSphinxレベルのドキュメントの問題に取り組む必要はありませんが、少なくとも、あなたや他の誰かがそれを拾う必要があるかもしれない詳細についてのコメントがいくつかあります。


12

スコーピングの目的で、私は以下を使用します:

custom_object = None

1

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

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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.