私はPythonを勉強していますが、Pythonの概念と概念をすべて理解していると思いますが、今日私は完全に理解していなかったコードを見つけました:
サークルを定義するはずのクラスがありますが、ボディがありません:
class Circle():
pass
私は属性を定義していないので、どうすればこれを行うことができます:
my_circle = Circle()
my_circle.radius = 12
奇妙な部分は、Pythonは上記のステートメントを受け入れます。なぜPythonがundefined name error
。私は、動的型付けを介して、必要なときにいつでも変数をオブジェクトにバインドするだけで、属性radius
が存在しないことを理解していますCircle
クラスでこれを行うことができますか?
[〜#〜] edit [〜#〜]:答えにたくさんの素晴らしい情報があります! これらすべての素晴らしい回答をありがとう!答えとしてマークするだけで残念です。
主要な原則は、宣言のようなものはないということです。つまり、「このクラスにはメソッドfooがある」または「このクラスのインスタンスには属性バーがある」と宣言することはなく、そこに格納するオブジェクトのタイプに関するステートメントを作成することはできません。メソッド、属性、クラスなどを定義するだけで、追加されます。 JBernardoが指摘しているように、どの__init__
メソッドもまったく同じことを行います。新しい属性の作成を__init__
という名前のメソッドにarbitrarily意的に制限することはあまり意味がありません。そして、実際にはその名前を持たない__init__
として関数を保存すると便利な場合があります(例:デコレータ)。そのような制限はそれを壊します。
今、これは普遍的に真実ではありません。組み込み型では、最適化としてこの機能が省略されています。 __slots__
を介して、ユーザー定義クラスでこれを防ぐこともできます。しかし、これは単なるスペースの最適化であり(すべてのオブジェクトに辞書は必要ありません)、正確性の問題ではありません。
セーフティネットが必要な場合は、あまりにも悪いです。 Pythonは提供しません。また、合理的に追加することはできません。最も重要なことは、言語を採用するPythonプログラマーによって回避されることです(読む:ほぼすべての人がと連携)。テストと規律は、依然として正しいことを確認するのに大いに役立ちます。 __init__
以外の属性を作成するために自由を使用しないでください(= /// =)、回避できる場合、自動テストを実行します。このようなトリックが原因でAttributeError
または論理エラーが発生することは非常にまれであり、発生するもののほとんどはテストでキャッチされます。
ここでの議論の誤解を明確にするために。このコード:
class Foo(object):
def __init__(self, bar):
self.bar = bar
foo = Foo(5)
そしてこのコード:
class Foo(object):
pass
foo = Foo()
foo.bar = 5
完全に同等です。本当に違いはありません。まったく同じことを行います。この違いは、最初のケースではカプセル化されており、bar属性がFoo型オブジェクトの通常の部分であることは明らかです。 2番目のケースでは、これがそうかどうかは明らかではありません。
最初のケースでは、bar属性を持たないFooオブジェクトを作成できません(おそらく可能ですが、簡単ではありません)、2番目のケースでは、Fooオブジェクトは設定しない限りbar属性を持ちません。
したがって、コードはプログラム的に同等ですが、さまざまなケースで使用されます。
Pythonでは、事実上すべてのインスタンス(またはクラス)に任意の名前の属性を保存できます。組み込み型のようにCでクラスを記述するか、特定の名前のみを許可する__slots__
を使用して、これをブロックすることができます。
これが機能する理由は、ほとんどのインスタンスが属性を辞書に保存するためです。はい、通常のPython {}
で定義するような辞書。辞書は__dict__
というインスタンス属性に保存されます。実際、 "クラスつまり、辞書を使用してクラスでできることはすべて実行できます。クラスを使用すると簡単になります。
コンパイル時にすべての属性を定義する必要がある静的言語に慣れています。 Pythonでは、クラス定義は実行済みであり、コンパイルされていません。クラスは他のクラスと同じオブジェクトです。属性を追加するのは、辞書にアイテムを追加するのと同じくらい簡単です。 Pythonは動的言語と見なされる理由です。
いいえ、pythonはそのように柔軟性があり、ユーザー定義のクラスに保存できる属性を強制しません。
ただし、トリックがあります。クラス定義で __slots__
属性 を使用すると、__slots__
シーケンスで定義されていない追加の属性を作成できなくなります。
>>> class Foo(object):
... __slots__ = ()
...
>>> f = Foo()
>>> f.bar = 'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'
>>> class Foo(object):
... __slots__ = ('bar',)
...
>>> f = Foo()
>>> f.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: bar
>>> f.bar = 'spam'
my_circle
のradius
データメンバーを作成します。
my_circle.radius
を要求した場合、例外がスローされます。
>>> print my_circle.radius # AttributeError
興味深いことに、これはクラスを変更しません。その1つのインスタンスだけです。そう:
>>> my_circle = Circle()
>>> my_circle.radius = 5
>>> my_other_circle = Circle()
>>> print my_other_circle.radius # AttributeError
Python-Class Data Attributes
およびInstance Data Attributes
]には2種類の属性があります。
Pythonは、Data Attributes
をその場で作成する柔軟性を提供します。
インスタンスデータ属性はインスタンスに関連しているため、__init__
メソッドで行うことも、インスタンスの作成後に行うこともできます。
class Demo(object):
classAttr = 30
def __init__(self):
self.inInit = 10
demo = Demo()
demo.outInit = 20
Demo.new_class_attr = 45; # You can also create class attribute here.
print demo.classAttr # Can access it
del demo.classAttr # Cannot do this.. Should delete only through class
demo.classAttr = 67 # creates an instance attribute for this instance.
del demo.classAttr # Now OK.
print Demo.classAttr
インスタンスが作成された後、__init__
の内部と外部の2つのインスタンス属性を作成したことがわかります。
ただし、違いは、__init__
の内部で作成されたインスタンス属性がすべてのインスタンスに設定されるのに対して、外部で作成された場合は、インスタンスごとに異なるインスタンス属性を使用できることです。
これは、クラスの各インスタンスが同じインスタンス変数のセットを持つJavaとは異なります。
デルナンが言ったように、__slots__
属性。しかし、メモリスペースとアクセスタイプを節約する方法であるという事実は、動的属性を無効にすることも(また)意味するという事実を破棄しません。
スペルミスによる微妙なバグを防ぐためだけに、動的属性を無効にすることは合理的なことです。 「テストと規律」は問題ありませんが、自動化された検証に依存することは間違いなく間違いではありません。
また、2016年にattrs
ライブラリがバージョン16に達したため(明らかに元の質問と回答の後)、スロットを使用して閉じたクラスを作成することはかつてないほど容易になりました。
>>> import attr
...
... @attr.s(slots=True)
... class Circle:
... radius = attr.ib()
...
... f = Circle(radius=2)
... f.color = 'red'
AttributeError: 'Circle' object has no attribute 'color'