# クラス変数と
インスタンス変数ってなに?
インスタンス 変数 | そのインスタンスだけで 使う属性 |
クラス 変数 | すべてのインスタンスで 共有して使う属性 |
class GirlFriend:
# クラス変数
# インスタンスオブジェクト間で
# 共有される変数
max_intimacy = 100
min_intimacy = 0
# インスタンス変数
# インスタンスオブジェクト間で
# 共有しない変数
def __init__(self, name):
self.name = name
self.intimacy = 0
これはどう言うことでしょうか? 実際に操作をしながらクラス変数とインスタンス変数の違いを、 もう少し追いかけてみたいと思います。
違い | クラス変数 | インスタンス変数 | |
---|---|---|---|
1 | 使い分け | 全ての インスタンスで 共有する値 | そのインスタンス だけで使う値 |
2 | 定義場所 | クラス定義文の 直下で 代入された変数 | 関数定義文の直下で 代入された self の属性 |
3 | クラス オブジェクト から参照 | できる | できない |
4 | インスタンス オブジェクト から参照 | できる | できる |
5 | 変更すると | 全ての インスタンスの属性 が変更される。 | その インスタンスの属性 だけが変更される。 |
# 1. 2つの属性の違い
オブジェクトが持っている値を 属性 と言います。
>>> user.name
サーバルちゃん
>>>
6.3.1. 属性参照 - Python 言語リファレンス (opens new window)
属性参照は、プライマリの後ろにピリオドと名前を連ねたものです: 全く重要な知識ではありません。 以下の表記は EBNF (opens new window) と呼ばれるものです。 Python の文法は、この EBNF で定義されています。
attributeref ::= primary "." identifier
属性 には2種類あります。 クラス変数 と インスタンス変数 です。 属性なのに変数ってちょっとややこしいですよね。
9.3.5. クラスとインスタンス変数 - Python チュートリアル (opens new window)
一般的に、インスタンス変数はそれぞれのインスタンスについて固有のデータのためのもので、クラス変数はそのクラスのすべてのインスタンスによって共有される属性やメソッドのためのものです:
# 違い 1. 使い分け
インスタンス 変数 | そのインスタンスだけで 使う属性 |
クラス 変数 | すべてのインスタンスで 共有して使う属性 |
# 違い 2. 定義する場所
クラス変数とインスタンス変数は、どこで定義するの?
例えば、恋愛ゲームについて考えましょう。 彼女 GirlFriend には名前 name, 彼氏への親密度 intimacy があり最小値 0, 最大値 100 とします。
ο 正しい書き方
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
# インスタンスオブジェクト間で共有される変数
max_intimacy = 100
min_intimacy = 0
# インスタンスオブジェクト間で共有しない変数
def __init__(self, name):
self.name = name
self.intimacy = 0
× 間違った書き方
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
intimacy = 0
name = ''
# 2.1. クラス変数
クラス定義文の直下で 変数 に代入する。 各インスタンスオブジェクトで共有 する 変数は、 クラス変数として定義します。
class GirlFriend:
# クラス変数
max_intimacy = 100
min_intimacy = 0
# 2.2. インスタンス変数
関数定義文の直下で self の属性 に代入する。 各インスタンスで共有 しない 変数は、 インスタンス変数として定義します。
class GirlFriend:
def __init__(self, name):
# インスタンス変数
self.name = name
self.intimacy = 0
# 違い 3. 参照
クラスブジェクトから参照できるか、できないか
引き続き GirlFriend クラスについて考えます。
# 3.1. クラスオブジェクトからクラス変数を参照できるか?
答え: できる
クラスオブジェクトは、 クラス定義 (opens new window) の内部で属性に代入されたインスタンスオブジェクトを、外部から参照できる仕様になっています。
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
# 参照できる
GirlFriend.max_intimacy
GirlFriend.min_intimacy
>>> # 参照できる
>>> GirlFriend.max_intimacy
100
>>> GirlFriend.min_intimacy
0
>>>
# 3.2. クラスオブジェクトからインスタンス変数を参照できるか?
答え: できない
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
# 参照できない
GirlFriend.name
GirlFriend.intimacy
>>> # 参照できない
... GirlFriend.name
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: type object 'GirlFriend' has no attribute 'name'
>>> GirlFriend.intimacy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'GirlFriend' has no attribute 'intimacy'
>>>
# 何でインスタンス変数には頭に self が必要なの?
答え: 関数の中で使われた "値" は、 "オブジェクトの属性" に代入してもらわないと外から見えないから。
class GirlFriend:
# self は不要
max_intimacy = 100
min_intimacy = 0
# self が必要
def __init__(self, name):
self.name = name
self.intimacy = 0
関数定義文とクラス定義文は、異なるものです。 関数定義文とクラス定義文は、 パッと見の構造が似ているので混同しがちですが、全く動作が違います。
#
# クラス定義文
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
# クラス定義文の中で書かれた値 100, 0 は
# 外から見える。
GirlFriend.max_intimacy == 100
GirlFriend.min_intimacy == 0
#
# 関数定義文
#
def __init__(self):
self.name = '岩倉玲音'
intimacy = 0
class GirlFriend:
pass
# 関数定義文の中で書かれた値 '岩倉玲音', 0 は
# 属性に代入しないと
# 外から見えない。
girl_friend = GirlFriend()
__init__(girl_friend, '岩倉玲音')
girl_friend.name == '岩倉玲音'
girl_friend.intimacy == 0 # AttributeError
# 違い 4. 参照
インスタンスブジェクトから参照できるか、できないか
インスタンスオブジェクトとは、変数に代入されたものを指しています。
# 4.1 インスタンスオブジェクトからクラス変数を参照できるか?
答え: できる
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend = GirlFriend('サーバルちゃん')
# 参照できる
girl_friend.max_intimacy
girl_friend.min_intimacy
>>> # 参照できる
>>> girl_friend.max_intimacy
100
>>> girl_friend.min_intimacy
0
>>>
# 4.2. インスタンスオブジェクトからインスタンス変数を参照できるか?
答え: できる
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend = GirlFriend('サーバルちゃん')
# 参照できる
girl_friend.name
girl_friend.intimacy
>>> # 参照できる
>>> girl_friend.name
'サーバルちゃん'
>>> girl_friend.intimacy
0
>>>
# 違い 5. 変更
クラス変数とインスタンス変数を変更してみる。
# 5.1. クラス変数を変更する。
クラス変数を変更すると、そのクラスからインスタンス化された、 すべてのインスタンスオブジェクトのクラス変数が変更されます。
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend1 = GirlFriend('サーバルちゃん')
girl_friend2 = GirlFriend('岩倉玲音')
girl_friend1.max_intimacy
girl_friend2.max_intimacy
# クラス変数を変更する。
GirlFriend.max_intimacy = 50
girl_friend1.max_intimacy
girl_friend2.max_intimacy
>>> girl_friend1 = GirlFriend('サーバルちゃん')
>>> girl_friend2 = GirlFriend('岩倉玲音')
>>> girl_friend1.max_intimacy
100
>>> girl_friend2.max_intimacy
100
>>>
>>>
>>> # クラス変数を変更する。
>>> girl_friend1.max_intimacy
50
>>> girl_friend2.max_intimacy
50
>>>
# 5.2. インスタンス変数を変更する。
インスタンス変数を変更すると、 そのインスタンスのインスタンス変数だけが変更されます。
#
# 対話モード >>> に
# コピペで実行できます。
#
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend1 = GirlFriend('サーバルちゃん')
girl_friend2 = GirlFriend('岩倉玲音')
girl_friend1.intimacy
girl_friend2.intimacy
# インスタンス変数を変更する
girl_friend1.intimacy = 70
girl_friend2.intimacy = 20
girl_friend1.intimacy
girl_friend2.intimacy
>>> girl_friend1 = GirlFriend('サーバルちゃん')
>>> girl_friend2 = GirlFriend('岩倉玲音')
>>> girl_friend1.intimacy
0
>>> girl_friend2.intimacy
0
>>>
>>>
>>> # インスタンス変数を変更する
... girl_friend1.intimacy = 70
>>> girl_friend2.intimacy = 20
>>> girl_friend1.intimacy
70
>>> girl_friend2.intimacy
20
>>>
# ◯ まとめ
インスタンス 変数 | そのインスタンスだけで 使う属性 |
クラス 変数 | すべてのインスタンスで 共有して使う属性 |
違い | クラス変数 | インスタンス変数 | |
---|---|---|---|
1 | 使い分け | 全ての インスタンスで 共有する値 | そのインスタンス だけで使う値 |
2 | 定義場所 | クラス定義文の 直下で 代入された変数 | 関数定義文の直下で 代入された self の属性 |
3 | クラス オブジェクト から参照 | できる | できない |
4 | インスタンス オブジェクト から参照 | できる | できる |
5 | 変更すると | 全ての インスタンスの属性 が変更される。 | その インスタンスの属性 だけが変更される。 |
WARNING
ここからは重箱の隅をつついていきます。 あまり重要ではない話です。
# 2. クラス変数の参照の仕方
実は、クラス変数の参照の仕方は、4通りあります。 どの書き方をしてもいいとも思います。 ただ、もし書き方を迷った場合は、 ご参考にしていただけると嬉しいです。
# 2.1. self から参照する。
新しく設定された親密度 new_intimacy
が
決められた最大値 max_intimacy
, 最小値 min_intimacy
外なら
例外を投げ返す場合について考えて見ます。
class GirlFriend:
min_intimacy = 0
max_intimacy = 100
def set_intimacy(self, new_intimacy):
if not (
self.min_intimacy
<= new_intimacy
<= self.max_intimacy
):
raise Exception
self.intimacy = new_intimacy
girl_friend = GirlFriend()
girl_friend.set_intimacy(50)
girl_friend.set_intimacy(101)
>>> girl_friend.set_intimacy(50)
>>> girl_friend.set_intimacy(101)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in set_intimacy
Exception
>>>
個人的にはには、このそのまま self で参照する方法がいいかなと思います。 なぜなら Python が提供してくれる便利な機能だからです。 もし推奨されない書き方なら、 わざわざこのような機能をつけたりしないと思うからです。
# 2.2. type 関数から参照する。
この方法も悪い方法ではないかなと思います。
class GirlFriend:
min_intimacy = 0
max_intimacy = 100
def set_intimacy(self, new_intimacy):
if not (
type(self).min_intimacy
<= new_intimacy
<= type(self).max_intimacy
):
raise Exception
self.intimacy = new_intimacy
girl_friend = GirlFriend()
girl_friend.set_intimacy(50)
girl_friend.set_intimacy(101)
>>> girl_friend.set_intimacy(50)
>>> girl_friend.set_intimacy(101)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in set_intimacy
Exception
>>>
何故なら、クラス変数であることを明示的に示すことができるからです。
明示的であることは、暗黙的であることより、良い。
Explicit is better than implicit.
PEP 20 - The Zen of Python (opens new window)
type 関数を使うことでクラスを取得することができます。
type([0, 1, 2]) is list # True になります。
class type(object) (opens new window)
引数が1つだけの場合、object の型を返します。 返り値は型オブジェクトで、一般に object.__class__ によって返されるのと同じオブジェクトです。
# 2.3. 特殊属性 __class__ から参照する。
この方法は type 関数を使うより悪い書き方かなと思います。
class GirlFriend:
min_intimacy = 0
max_intimacy = 100
def set_intimacy(self, new_intimacy):
if not (
self.__class__.min_intimacy
<= new_intimacy
<= self.__class__.max_intimacy
):
raise Exception
self.intimacy = new_intimacy
girl_friend = GirlFriend()
girl_friend.set_intimacy(50)
girl_friend.set_intimacy(101)
特殊属性 __class__ からクラスを取得することができます。
instance.__class__ (opens new window)
クラスインスタンスが属しているクラスです。
実は、さきほどご紹介した type 関数は __class__ を返しているだけです。
class type(object) (opens new window)
引数が1つだけの場合、object の型を返します。 返り値は型オブジェクトで、 一般に object.__class__ によって返されるのと同じオブジェクトです。
Python では他にも単純に属性を返すだけの関数がたくさんあります。 そのような関数が提供されている場合は、その関数を使うのが望ましいと 個人的には感じます。
その辺りの温度感については、以下の記事でご紹介させていただきました。
# 2.4. クラス名をそのまま参照する。
個人的な意見ですが、このやり方はあまり良くないような気がします。
class GirlFriend:
min_intimacy = 0
max_intimacy = 100
def set_intimacy(self, new_intimacy):
if not (
GirlFriend.min_intimacy
<= new_intimacy
<= GirlFriend.max_intimacy
):
raise Exception
self.intimacy = new_intimacy
girl_friend = GirlFriend()
girl_friend.set_intimacy(50)
girl_friend.set_intimacy(101)
>>> girl_friend.set_intimacy(50)
>>> girl_friend.set_intimacy(101)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in set_intimacy
Exception
>>>
まず、第一にクラス変数を直接参照できなくなっています。 Python では意図的にこのようなスコープの設計がされています。
#
# 偽物の Python
# 動きません
#
class GirlFriend:
min_intimacy = 0
max_intimacy = 100
def set_intimacy(self, new_intimacy):
if not (
min_intimacy # <--- このようには書けない
<= new_intimacy
<= max_intimacy # <--- このようには書けない
):
raise Exception
self.intimacy = new_intimacy
PEP 227 - Statically Nested Scopes (opens new window)
Python の名前解決のルールは、静的スコープ言語に典型的なものです。
The name resolution rules are typical for statically scoped languages,ただし以下の3つの例外を除きます。
with three primary exceptions:
- クラススコープにある名前は参照できない。
- Names in class scope are not accessible.
また第二にグローバル変数 GirlFriend
を参照してしまっているからです。
一般にスコープは使わずにローカルスコープを使う方が良いとされています。
それでも明示的に GirlFriend
と書いた方がわかりやすい気もするのですが、
うーんどうでしょう。
# 3. クラス変数の仕組み
ここで伝えたいことは...
辞書をつなぎ合わせただけで
表現されています。
インスタンスオブジェクトの属性
→ クラスオブジェクトの属性
→ クラスオブジェクトの親クラスオブジェクトの属性
→ クラスオブジェクトの親クラスオブジェクトの親クラスオブジェクトの...
といった順番に属性にアクセスしています。
属性アクセスのデフォルトの振る舞いは、オブジェクトの辞書の属性の取得、設定、削除です。 例えば a.x は、まず a.__dict__['x']、それから type(a).__dict__['x']、さらに type(a) の メタクラス (opens new window) を除く基底クラスへと続くというように探索が連鎖します。
デスクリプタ HowTo ガイド - Python HOWTO (opens new window)
# ◯ 問題
それっぽく書かれても「何言ってんだ?」って感じです。 もう少しクラス変数の動作に習熟してみたいと思います。
# 1. 復習
実行結果 1, 2 には何が表示されるでしょうか?
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend1 = GirlFriend('サーバルちゃん')
girl_friend2 = GirlFriend('岩倉玲音')
# 1. クラスオブジェクトの属性を
girl_friend1.max_intimacy
girl_friend2.max_intimacy
# 2. 変更すると
GirlFriend.max_intimacy = 50
# 3. そこから生成された全ての
# インスタンスオブジェクトの属性も変更される。
girl_friend1.max_intimacy # 実行結果 1
girl_friend2.max_intimacy # 実行結果 2
>>> # 答え(実行結果を抜粋したもの)
>>> girl_friend1.max_intimacy # 実行結果 1
50
>>> girl_friend2.max_intimacy # 実行結果 2
50
>>>
いよいよ、ここからは、 もう少し突っ込んだ動作原理を見ていきたいと思います。
実は、この記事は以下の記事からの続きになります。 細かいことは置いておいて、 「インスタンスオブジェクト」と「クラスオブジェクト」 というものが存在しているということだけで押さえておくと、 この先が把握しやすいかなと思います。
# 2. 本題
実行結果 3, 4, 5, 6 には何が表示されるでしょうか?
class GirlFriend:
max_intimacy = 100
min_intimacy = 0
def __init__(self, name):
self.name = name
self.intimacy = 0
girl_friend1 = GirlFriend('サーバルちゃん')
girl_friend2 = GirlFriend('岩倉玲音')
# step1. girl_friend1 の属性 max_intimacy に
# インスタンスオブジェクトは代入されてるかな?
# -> されてない...
# step2. GirlFriend の属性 max_intimacy に
# インスタンスオブジェクトは代入されてるかな?
# -> 100 があった!
girl_friend1.max_intimacy
#
# インスタンスオブジェクトの属性を変えても...
#
girl_friend1.max_intimacy = 1000
# そのインスタンスオブジェクトは変わるが
girl_friend1.max_intimacy # 実行結果 3
# クラスオブジェクトの属性にも
GirlFriend.max_intimacy # 実行結果 4
# 他のインスタンスオブジェクトにも影響はない
girl_friend2.max_intimacy # 実行結果 5
#
# インスタンスオブジェクトの属性を消せば...
#
del girl_friend1.max_intimacy
# またクラスオブジェクトの属性が参照される。
girl_friend1.max_intimacy # 実行結果 6
>>> # 答え(実行結果を抜粋したもの)
... girl_friend1.max_intimacy # 実行結果 3
1000
>>>
>>> GirlFriend.max_intimacy # 実行結果 4
100
>>>
>>> girl_friend2.max_intimacy # 実行結果 5
100
>>>
>>> girl_friend1.max_intimacy # 実行結果 6
100
>>>
# ◯ 公式マニュアルの説明
公式マニュアルに属性参照の動作に関わる記述があります。 しかし、マニュアルの文章がいまいちよくわかりません。 理解につなげるために、関数呼び出し、日本語の表記を除いて、 最終的に obj.attr のような属性参照だけに書き換えていきます。 厳密に書いてるわけではないので、ざっくり眺めてもらえると嬉しいです。
属性アクセスのデフォルトの振る舞いは、 オブジェクトの辞書の属性の取得、設定、削除です。 例えば a.x は、まず a.__dict__['x']、 それから type(a).__dict__['x']、 さらに type(a) の メタクラス (opens new window) を除く基底クラスへと続くというように探索が連鎖します。
デスクリプタ HowTo ガイド - Python HOWTO (opens new window)
# Step1: マニュアルの文章を、ちょっと書き換えてみます。
→ a.__dict__['x']
→ type(a).__dict__['x']
→ type(a) のメタクラスを除く基底クラスの __dict__['x']
→ type(a) のメタクラスを除く基底クラスの メタクラスを除く基底クラス..
...
# Step2: class.__bases__
「type(a) のメタクラスを除く基底クラス」→ type(a).__bases__[0]
→ a.__dict__['x']
→ type(a).__dict__['x']
→ type(a).__bases__[0].__dict__['x']
→ type(a).__bases__[0].__bases__[0].__dict__['x']
...
「type(a) のメタクラスを除く基底クラス」とは、 オブジェクト a を生成したクラスの親クラスのことを指しています。 だいたいの場合 type(a).__bases__[0] と同じです。 __bases__ がタプルになっているのは、多重継承している場合があるからです。
クラスオブジェクトの基底クラスのタプルです。
class.__bases__ - Python 標準ライブラリ (opens new window)
# Step3: type 関数, instance.__class__
type(a) → a.__class__
→ a.__dict__['x']
→ a.__class__.__dict__['x']
→ a.__class__.__bases__[0].__dict__['x']
→ a.__class__.__bases__[0].__bases__[0].__dict__['x']
...
tyep(a) は、だいたいの場合 __class__ と同じです。
返り値は型オブジェクトで、一般に object.__class__ によって返されるのと同じオブジェクトです。
type 関数 - Python 標準ライブラリ (opens new window)
クラスインスタンスが属しているクラスです。
__class__ 属性 - Python 標準ライブラリ (opens new window)
# Step4: 図にすると...
辞書をつなぎ合わせただけで
表現されています。
# ◯ 誰がつなぎ合わせているの?
答え: 属性です。
辞書をつなぎ合わせただけで表現されています。 どうやってつなぎ合わせているのでしょうか?
インスタンスオブジェクトの __class__ 属性には、クラスオブジェクトが代入しているだけです。 クラスオブジェクトの __bases__ 属性には、親クラスオブジェクトが代入しているだけです。
→ a.__dict__['x']
→ a.__class__.__dict__['x']
→ a.__class__.__bases__[0].__dict__['x']
→ a.__class__.__bases__[0].__bases__[0].__dict__['x']
...
オブジェクトの (書き込み可能な) 属性を保存するために使われる辞書またはその他のマッピングオブジェクトです。
__dict__ 属性 - Python 標準ライブラリ (opens new window)
このような構造をしているので __class__ 属性に別のクラスオブジェクトを代入すると、 クラスキャストのような動作をします。
また Python では、属性だけではなく変数も辞書の中に保存されています。
# 変数
# var = 0
locals().update({'var': 0})
print(var) # 0
# 属性
# obj.attr = 1
class Cls:
pass
obj = Cls()
obj.__dict__.update({'obj_attr': 1})
print(obj.obj_attr) # 1
locals() - Python 標準ライブラリ (opens new window)
現在のローカルシンボルテーブルを表す辞書を更新して返します。 関数ブロックで locals() を呼び出したときは自由変数が返されますが、 クラスブロックでは返されません。 モジュールレベルでは、 locals() と globals() は同じ辞書であることに注意してください。
注釈 この辞書の内容は変更してはいけません; 変更しても、インタプリタが使うローカル変数や自由変数の値には影響しません。
これは難しい言葉で言い換えると「名前空間そのものが辞書で表現されている」と言えます。
名前空間 (namespace) とは、名前からオブジェクトへの対応付け (mapping) です。 ほとんどの名前空間は、現状では Python の辞書として実装されています。
9.2. Python のスコープと名前空間 - Python チュートリアル (opens new window)
名前空間は、こちらの記事で見てきました。
# 4. 継承より合成
せっかく継承がどのように実装されているか見てきたのですが、 「継承より合成」という言葉があります。 継承するのではなく、欲しい機能を属性に代入し(合成)、 処理を呼び出したいときは属性からメソッドを呼び出した方が(移譲)、良いという経験則です。
class SequenceA(list):
# 継承
pass
class SequenceB:
def __init__(self):
# 合成
self._list = []
def append(self, element):
# 委譲
self._list.append(element)
合成と委譲は、継承に比べて、ひどく面倒ではないでしょうか? しかし継承は、それなりに嫌われているようです。 以下に Java の記事を引用します。 extends とは Python の継承のことです。 どうやら継承はとても嫌われているようです。
Java の extends は悪だ; チャールズ・マンソンほどでないかもしれないが、 可能ならいつでも避けなければならないほど悪いものだ。
The extends keyword is evil; maybe not at the Charles Manson level, ut bad enough that it should be shunned whenever possible.
Why extends is evil - JAVAWORLD (opens new window)
その辺りの温度感、どう言ったときなら継承を使ってもいいのか、といったことについては、 名前空間という枠の中で、最後に、ご紹介させていただきたいと思っております。 なぜ名前空間に執着しているかというと、オブジェクト指向は、名前空間と関係があると感じたからです。
# 5. おわりに
以下のような流れでクラス変数とインスタンス変数の違いを追って来ました。
ありがとうございました。 ここでは「クラス変数」と「インスタンス変数」の違いを見てきました。 次は「関数」と「メソッド」の違いを、追っていきたいと思います。