ホームページ > バックエンド開発 > Python チュートリアル > Python の基本クラス変数とインスタンス変数

Python の基本クラス変数とインスタンス変数

巴扎黑
リリース: 2017-06-26 09:12:11
オリジナル
1511 人が閲覧しました

Pythonの基礎 - クラス変数とインスタンス変数

前に書いてます

特に断りのない限り、以下はPython3に基づいています

概要:

Python の基本クラス変数とインスタンス変数

1 Pythonチュートリアルで。クラス変数とインスタンス変数は次のように説明されます:

一般的に言えば、インスタンス変数は各インスタンスに固有のデータ用であり、クラス変数はクラスのすべてのインスタンスによって共有される属性とメソッド用です:

一般的に言えば、インスタンス変数は次のようになります。クラス変数は各インスタンスに固有のデータであり、クラス変数はクラスのすべてのインスタンスで共有されるプロパティとメソッドです。

実際、私はそれらをクラス属性とインスタンス属性と呼びたいのですが、

変数

という言葉はプログラミング言語の慣例的な名前になっています。通常の例は次のとおりです。

class Dog:

    kind = 'canine'         # class variable shared by all instancesdef __init__(self, name):self.name = name    # instance variable unique to each instance
ログイン後にコピー

クラス Dog では、クラス属性 kind はすべてのインスタンスによって共有されます。 Dog の各インスタンスに固有のものです。

2. クラス オブジェクトとインスタンス オブジェクトDog中,类属性kind为所有实例所共享;实例属性name为每个Dog的实例独有。

2. 类对象和实例对象

2.1 类对象

Python中一切皆对象;类定义完成后,会在当前作用域中定义一个以类名为名字,指向类对象的名字。如

class Dog:pass
ログイン後にコピー

会在当前作用域定义名字Dog,指向类对象Dog

类对象支持的操作
总的来说,类对象仅支持两个操作:

  1. 实例化;使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例。

  2. 属性引用;使用class_name.attr_name的方式引用类属性。

2.2 实例对象

实例对象是类对象实例化的产物,实例对象仅支持一个操作:

  1. 属性引用;与类对象属性引用的方式相同,使用instance_name.attr_name的方式。

按照严格的面向对象思想,所有属性都应该是实例的,类属性不应该存在。那么在Python中,由于类属性绑定就不应该存在,类定义中就只剩下函数定义了。

在Python tutorial关于类定义也这么说:

In practice, the statements inside a class definition will usually be function definitions, but other statements are allowed, and sometimes useful.

实践中,类定义中的语句通常是函数定义,但是其他语句也是允许的,有时也是有用的。

这里说的其他语句,就是指类属性的绑定语句。

3. 属性绑定

在定义类时,通常我们说的定义属性,其实是分为两个方面的:

  1. 类属性绑定

  2. 实例属性绑定

绑定这个词更加确切;不管是类对象还是实例对象,属性都是依托对象而存在的。

我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用

objname.attr = attr_value
ログイン後にコピー

的方式,为对象objname绑定属性attr

这分两种情况:

  1. 若属性attr已经存在,绑定操作会将属性名指向新的对象;

  2. 若不存在,则为该对象添加新的属性,后面就可以引用新增属性。

3.1 类属性绑定

Python作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性的绑定发生在两个地方:

  1. 类定义时;

  2. 运行时任意阶段。

下面这个例子说明了类属性绑定发生的时期:

class Dog:

    kind = 'canine'Dog.country = 'China'print(Dog.kind, ' - ', Dog.country) # output: canine  -  Chinadel Dog.kindprint(Dog.kind, ' - ', Dog.country) # AttributeError: type object 'Dog' has no attribute 'kind'
ログイン後にコピー

在类定义中,类属性的绑定并没有使用objname.attr = attr_value的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式。
因为是动态语言,所以可以在运行时增加属性,删除属性。

3.2 实例属性绑定

与类属性绑定相同,实例属性绑定也发生在两个地方:

  1. 类定义时;

  2. 运行时任意阶段。

示例:

class Dog:def __init__(self, name, age):self.name = nameself.age = age

dog = Dog('Lily', 3)
dog.fur_color = 'red'print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color))# Output: Lily is 3 years old, it has red fur
ログイン後にコピー

Python类实例有两个特殊之处:

  1. __init__在实例化时执行

  2. Python实例调用方法时,会将实例对象作为第一个参数传递

因此,__init__方法中的self就是实例对象本身,这里是dog

2.1 クラス オブジェクト

Python 内のすべてのものはオブジェクトです。クラス定義が完了すると、クラス名が定義されます。現在のスコープは名前であり、クラス オブジェクトの名前を指します。たとえば、
self.name = nameself.age = age
ログイン後にコピー
🎜🎜は、現在のスコープで名前Dogを定義し、クラスオブジェクトDogを指します。 🎜🎜🎜クラス オブジェクトによってサポートされる操作🎜:
一般に、クラス オブジェクトは 2 つの操作のみをサポートします。 🎜
  1. 🎜Instantiation use Instance_name = class_name; () がインスタンス化され、インスタンス化操作によってクラスのインスタンスが作成されます。 🎜
  2. 🎜属性参照。クラス属性を参照するには、class_name.attr_name を使用します。 🎜
2.2 インスタンス オブジェクト
🎜 インスタンス オブジェクトは、クラス オブジェクトのインスタンス化の産物です: 🎜
  1. 🎜属性参照; クラス オブジェクトの属性参照と同じように、instance_name.attr_name を使用します。 🎜
🎜 厳密なオブジェクト指向の考え方によれば、すべての属性はインスタンスである必要があり、クラス属性は存在すべきではありません。次に、Python では、クラス属性バインディングが存在しないはずなので、クラス定義には関数定義のみが残ります。 🎜🎜Python チュートリアルではクラス定義について次のように述べています:🎜🎜🎜実際には、クラス定義内のステートメントは通常関数定義になりますが、他のステートメントも許可されており、場合によっては便利です。🎜🎜🎜実際には、クラス定義内のステートメントは関数定義になります。クラス定義は通常は関数定義ですが、他のステートメントも許可され、場合によっては便利なステートメントが関数定義になりますが、他のステートメントも許可され、場合によっては便利です。 🎜🎜ここで言及されている他のステートメントは、クラス属性のバインディング ステートメントを指します。 🎜🎜3. 属性バインディング🎜🎜クラスを定義するとき、私たちが通常属性の定義と呼ぶものは、実際には 2 つの側面に分けられます: 🎜
  1. 🎜クラス属性バインディング 定義 🎜
  2. 🎜インスタンス属性バインディング🎜
🎜クラス オブジェクトであってもインスタンス オブジェクトであっても、属性はオブジェクトに基づいて存在します。 🎜🎜私たちが話している属性バインディングでは、バインディング操作を実行するために、まず変数オブジェクトが必要です。メソッド 🎜🎜
dog.fur_color = 'red'
ログイン後にコピー
ログイン後にコピー
🎜🎜 を使用して、属性 attr</ をオブジェクト <code>objname コードにバインドします。 >。 🎜🎜2 つの状況があります: 🎜
  1. 🎜 属性 attr が既に存在する場合、バインディング操作は属性名が新しいオブジェクトを指すようになります。 ; 🎜
  2. 🎜 存在しない場合は、新しい属性をオブジェクトに追加すると、後でその新しい属性を参照できます。 🎜
3.1 クラス属性のバインド
🎜Python動的言語として、クラス オブジェクトとインスタンス オブジェクトの両方が実行時に任意の属性をバインドできます。したがって、クラス属性のバインディングは 2 つの場所で行われます: 🎜
  1. 🎜クラスの定義時 🎜
  2. 🎜 実行時の任意の段階。 🎜
🎜次の例は、クラス属性のバインディングが発生する期間を示しています: 🎜🎜
class Dog:

    kind = &#39;canine&#39;Dog.country = &#39;China&#39;print(Dog.kind, &#39; - &#39;, Dog.country) # output: canine  -  China
ログイン後にコピー
ログイン後にコピー
🎜🎜クラス定義では、クラス属性のバインディングに objname.attr = attr_value</ / code> メソッド、これは特殊なケースであり、実際には後でクラス名を使用して属性をバインドするメソッドと同等です。 <br/>動的言語であるため、実行時に属性を追加および削除できます。 🎜<h5>3.2 インスタンス属性バインディング</h5>🎜 クラス属性バインディングと同様に、インスタンス属性バインディングも 2 つの場所で発生します。 🎜<ol class=" list-paddingleft-2"><li>🎜 クラス 定義されている場合。 </li><li>🎜実行時の任意のステージ。 🎜</li></ol>🎜例: 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="sourceCode python">class Dog: kind = &amp;#39;canine&amp;#39;def tell_kind():print(Dog.kind) Dog.tell_kind() # Output: canine</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>🎜🎜<code>Python クラス インスタンスには 2 つの特別な機能があります: 🎜
  1. 🎜< code>__init__ はインスタンス化中に実行されます🎜
  2. 🎜Python インスタンスがメソッドを呼び出すと、インスタンス オブジェクトが最初のパラメータとして渡されます🎜
🎜 したがって、__init__ メソッドの self はインスタンス オブジェクト自体であり、ここでは dog というステートメント 🎜🎜
class Dog:

    kind = &#39;canine&#39;country = &#39;China&#39;def __init__(self, name, age, country):self.name = nameself.age = ageself.country = country

dog = Dog(&#39;Lily&#39;, 3, &#39;Britain&#39;)print(dog.name, dog.age, dog.kind, dog.country)# output: Lily 3 canine Britain
ログイン後にコピー
ログイン後にコピー
🎜 が使用されます。

以及后面的语句

dog.fur_color = &#39;red&#39;
ログイン後にコピー
ログイン後にコピー

为实例dog增加三个属性name, age, fur_color

4. 属性引用

属性的引用与直接访问名字不同,不涉及到作用域。

4.1 类属性引用

类属性的引用,肯定是需要类对象的,属性分为两种:

  1. 数据属性

  2. 函数属性

数据属性引用很简单,示例:

class Dog:

    kind = &#39;canine&#39;Dog.country = &#39;China&#39;print(Dog.kind, &#39; - &#39;, Dog.country) # output: canine  -  China
ログイン後にコピー
ログイン後にコピー

通常很少有引用类函数属性的需求,示例:

class Dog:

    kind = &#39;canine&#39;def tell_kind():print(Dog.kind)
        
Dog.tell_kind() # Output: canine
ログイン後にコピー
ログイン後にコピー

函数tell_kind在引用kind需要使用Dog.kind而不是直接使用kind,涉及到作用域,这一点在我的另一篇文章中有介绍:Python进阶 - 命名空间与作用域

4.2 实例属性引用

使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:

  1. 总是先到实例对象中查找属性,再到类属性中查找属性;

  2. 属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。

4.2.1 数据属性引用

示例1:

class Dog:

    kind = &#39;canine&#39;country = &#39;China&#39;def __init__(self, name, age, country):self.name = nameself.age = ageself.country = country

dog = Dog(&#39;Lily&#39;, 3, &#39;Britain&#39;)print(dog.name, dog.age, dog.kind, dog.country)# output: Lily 3 canine Britain
ログイン後にコピー
ログイン後にコピー

类对象Dog与实例对象dog均有属性country,按照规则,dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性。

示例2:

class Dog:

    kind = &#39;canine&#39;country = &#39;China&#39;def __init__(self, name, age, country):self.name = nameself.age = ageself.country = country

dog = Dog(&#39;Lily&#39;, 3, &#39;Britain&#39;)print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 canine Britainprint(dog.__dict__) # {&#39;name&#39;: &#39;Lily&#39;, &#39;age&#39;: 3, &#39;country&#39;: &#39;Britain&#39;}dog.kind = &#39;feline&#39;print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 feline Britainprint(dog.__dict__) 
print(Dog.kind) # canine 没有改变类属性的指向# {&#39;name&#39;: &#39;Lily&#39;, &#39;age&#39;: 3, &#39;country&#39;: &#39;Britain&#39;, &#39;kind&#39;: &#39;feline&#39;}
ログイン後にコピー

使用属性绑定语句dog.kind = &#39;feline&#39;,按照规则,为实例对象dog增加了属性kind,后面使用dog.kind引用到实例对象的属性。

这里不要以为会改变类属性Dog.kind的指向,实则是为实例对象新增属性,可以使用查看__dict__的方式证明这一点。

示例3,可变类属性引用:

class Dog:
    
    tricks = []def __init__(self, name):self.name = namedef add_trick(self, trick):self.tricks.append(trick)

d = Dog(&#39;Fido&#39;)
e = Dog(&#39;Buddy&#39;)
d.add_trick(&#39;roll over&#39;)
e.add_trick(&#39;play dead&#39;)print(d.tricks) # [&#39;roll over&#39;, &#39;play dead&#39;]
ログイン後にコピー

语句self.tricks.append(trick)并不是属性绑定语句,因此还是在类属性上修改可变对象。

4.2.2 方法属性引用

与数据成员不同,类函数属性在实例对象中会变成方法属性。

先看一个示例:

class MethodTest:def inner_test(self):print(&#39;in class&#39;)def outer_test():print(&#39;out of class&#39;)

mt = MethodTest()
mt.outer_test = outer_testprint(type(MethodTest.inner_test))  # <class &#39;function&#39;>print(type(mt.inner_test))          #<class &#39;method&#39;>print(type(mt.outer_test))          #<class &#39;function&#39;>
ログイン後にコピー

可以看到,类函数属性在实例对象中变成了方法属性,但是并不是实例对象中所有的函数都是方法。

Python tutorial中这样介绍方法对象:

When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.

引用非数据属性的实例属性时,会搜索它对应的类。如果名字是一个有效的函数对象,Python会将实例对象连同函数对象打包到一个抽象的对象中并且依据这个对象创建方法对象:这就是被调用的方法对象。当使用参数列表调用方法对象时,会使用实例对象以及原有参数列表构建新的参数列表,并且使用新的参数列表调用函数对象。

那么,实例对象只有在引用方法属性时,才会将自身作为第一个参数传递;调用实例对象的普通函数,则不会。
所以可以使用如下方式直接调用方法与函数:

mt.inner_test()
mt.outer_test()
ログイン後にコピー

除了方法与函数的区别,其引用与数据属性都是一样的

5. 最佳实践

虽然Python作为动态语言,支持在运行时绑定属性,但是从面向对象的角度来看,还是在定义类的时候将属性确定下来。

以上がPython の基本クラス変数とインスタンス変数の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート