Python における値って何?




オブジェクトの集まりで表現されるもの




f:id:domodomodomo:20161101224658p:plain




公式マニュアル

実は公式マニュアルでは「値」という言葉が頻繁に使われています。しかし、実際にその「値」がなんであるのかを説明している箇所はありません。この値という概念は何者でしょうか?

list.remove(x)
リスト中で、 x を持つ最初の要素を削除します。
該当する項目がなければエラーとなります。

従って immutable であること (immutability) は、厳密に言えば "が変更できないこと" と同義ではなく、もう少し複雑です。
So, immutability is not strictly the same as having an unchangeable value, it is more subtle.
3.1. Objects, values and types

オブジェクトのPython ではやや抽象的な概念です: 例えば、オブジェクトの値にアクセスする正統な方法はありません。 また、その全てのデータ属性から構成されるなどの特定の方法で、オブジェクトの値を構築する必要性もありません。

比較演算子は、オブジェクトの値とは何かについての特定の概念を実装しています。 この比較の実装によって、間接的にオブジェクトの値を定義している考えることもできます。
6.10.1. 値の比較

すべてのオブジェクトは、同一性 (identity)、型、をもっています。 3. データモデル — Python 3.6.5 ドキュメント


具体例


例 1. int, float クラス

11.0 というオブジェクトは 1 という値を持っています。

>>> 1 == 1.0
True
>>>

すべてのオブジェクトは、同一性 (identity)、型、をもっています。 3. データモデル — Python 3.6.5 ドキュメント

比較演算子は、オブジェクトの値とは何かについての特定の概念を実装しています。 この比較の実装によって、間接的にオブジェクトの値を定義している考えることもできます。
6.10.1. 値の比較


例えば、1 の値と 1.0 の値は、等しいです。

>>> 1 == 1.0
True
>>>


でも、11.0 は、型が異なりますし、

>>> type(1) == type(1.0)
False
>>> 


それに、11.0 は、属性も異なります。

>>> set(dir(1)) == set(dir(1.0))
False
>>> 


11.0 も、 オブジェクトの集まりです。

>>> # 1 オブジェクト
>>> a = 1
>>>
>>> # a の属性を表示
>>> for e in dir(a): e
... 
'__abs__'
'... 略 ...'
'__xor__'
'bit_length'
'conjugate'
'denominator'
'from_bytes'
'imag'
'numerator'
'real'
'to_bytes'
>>>
>>> # 1 オブジェクト
>>> a = 1
>>>
>>> # 実部
>>> a.real
1
>>> # 虚部
>>> a.imag
0
>>>
>>> # 1.0 オブジェクト
>>> b = 1.0
>>>
>>> for e in dir(b): e
... 
'__abs__'
'... 略 ...'
'__trunc__'
'as_integer_ratio'
'conjugate'
'fromhex'
'hex'
'imag'
'is_integer'
'real'
>>>
>>> # 1.0 オブジェクト
>>> b = 1.0
>>>
>>> # 実部
>>> b.real
1.0
>>> # 虚部
>>> b.imag
0.0
>>>


属性に保持しているオブジェクトは異なりますが、 それぞれのオブジェクトが集まって 1 という値を表現しています。 11.0 というオブジェクトは 1 という値を持っています。

値 (情報工学) - Wikipedia
値は、何らかの式を評価した結果である。式はデータ型を持ち、評価結果は内部的にはビット列になる。データ型が異なれば、同じビット列が異なる値(意味)を持つこともある。例えばあるビット列は整数、浮動小数点数または文字列として解釈されることがある。(ワイの注釈: Python の 1 と 1.0 の例では、ビット列が異なりますが、型が異なれば、同じ値として解釈されることもある例を示しました。)


例 2. Person クラス

また、オブジェクトは属性に値を持っていると考えることもできます。 例えば「人」をクラスにすることを考えます。「人」には属性として「名前」、「年齢」、「性別」があります。

変数 person に束縛されたオブジェクトは、"Gaius Iulius Caesar", 30, False という 3 つの値を持っていると言えます。

class Person(object):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

person = Person("Gaius Iulius Caesar", 30, False)


「オブジェクトそのものが1つの値を持っている。」とも「オブジェクトが属性に複数の値を持っている。」とも捉えることもできます。

他のオブジェクトに対する参照をもつオブジェクトもあります; これらは コンテナ (container) と呼ばれます。コンテナオブジェクトの例として、タプル、リスト、および辞書が挙げられます。オブジェクトへの参照自体がコンテナの値の一部です。ほとんどの場合、コンテナの値というと、コンテナに入っているオブジェクトの値のことを指し、それらオブジェクトのアイデンティティではありません;
3.1. オブジェクト、値、および型


例 3. Computer クラス

他にも自分で定義したクラスについて考えてみます。 例えば Computer はCPU, メモリ, SSD と言った部品の集まり、値で構成されています。

メモリはメモリという値として、CPU は CPU という値として、SSDSSD という値として認識することができます。

class Computer(object):
    def __init__(self, cpu,
                 primary_memory, auxiliary_memory):
        self.cpu = cpu
        self.primary_memory = primary_memory
        self.auxiliary_memory = auxiliary_memory


class Cpu(object):
    def __init__(self, clock, core):
        self.clock = clock
        self.core = core


class Memory(object):
    def __init__(self, volume, clock, type_):
        self.volume = volume
        self.clock = clock
        self.type_ = type_


class Ssd(object):
    def __init__(self, volume):
        self.volume = volume


imac = Computer(
    Cpu('3.4GHz', 7),
    Memory('8GB', '2400MHz', 'DDR4'),
    Ssd('1TB'))



◯ オブジェクトと値の関係

オブジェクトは複数の属性を持っていて、その各属性の中に値が1つはいっています。オブジェクトと値の関係は、このように再帰的に定義されていると考えることができます。

object -*-> attribute -1-> value(object)

◯ オブジェクトと値の違い

オブジェクトと値は、おそらく概念的に違います。オブジェクトは、属性を持っています。値は、属性参照せずに取り扱う概念だと思います。

例えば 1 について、考えて見てください。1, 1.0 は、四則演算子や比較演算子を通して、表面的には属性参照することなく扱えるものです。

最初、なぜこのような値という言葉をわざわざ使っているのか理解できませんでした。正直言っていまもわかっていませんが、確かに 1, "Hello, world!" と言ったリテラルを表現するときには、値と言った言葉があった方がわかりやすいのかなと思ってりもしました。


オブジェクトが値を保存する場所

1つのオブジェクトには、いくつもの値がくっついています。あるオブジェクトに値をくっつけるには、次の2通りの方法があります。

  1. 属性 attribute に代入されたインスタンスオブジェクト または
  2. シーケンス sequence の要素 element

1. 属性 attribute に代入されたインスタンスオブジェクト

前述の通り。

2. シーケンス sequence の要素 element

例えばリストのように s[0] という記述でインスタンスオブジェクトを参照できるオブジェクトをシーケンスと読んでいます。 

s[0] は s の i 番目の要素です。s の属性とは違いそうですが、なんとなくこれが、値と絡んでいそうな気がします


s[i]s の 0 から数えて i 番目の要素
4.6.1. 共通のシーケンス演算
>>> # Hello, world! オブジェクト
>>> s = 'Hello, world! '
>>> 
>>> # Hello, world! オブジェクトの値
>>> s[0]
'W'
>>>


要素は属性とは違うやろ。って声が聞こえてきそうですが。シーケンスの要素を使って == を実装したりもできるので、値を構成しうるものとして考えていいのかなと。ちなみに str には callable でない属性、メソッドでない属性が __doc__ しかありません。

>>> for e in dir(s):
...   if not callable(getattr(s, e)):
...     e
... 
'__doc__'
>>>

リテラルはどこにあるんだろう?

答え: immutable なオブジェクトがリテラルだと思われます

再帰的に定義されてるなら、 1 とか 'a' のような実際のデータ、リテラルは、どこに保存されてるのかな?と思いました。

何故なら、属性と値の関係は再帰的に定義されてるなら、どんなに属性を参照し続けても実際のデータ, リテラルが保存されているところに行き着くことができないからです。自己参照してるところを終端として捉えて、リテラルを保存している場所として取り扱っているのかなと思ったりもします。

例えば int の 1 は自分自身 1 が属性に代入されています。

>>> a = 1
>>> 
>>> a.real
1
>>> a.real.real
1
>>>
>>> id(a.real)
4300950496
>>> id(a.real.real)
4300950496
>>> 


str の 'W' には自分自身 'W' が 0 番目の要素に代入されています。

>>> s = 'Welcome to ようこそジャパリパーク! 今日もドッタンバッタン大騒ぎ うー!がぉー! 高らかに笑い笑えば フレンズ喧嘩して すっちゃかめっちゃかしても仲良し けものは居ても のけものは居ない本当の愛はここにあるほら 君も手をつないで大冒険 '
>>> 
>>> s[0]
'W'
>>> s[0][0]
'W'
>>> 
>>> id(s[0])
4473881520
>>> id(s[0][0])
4473881520
>>>


そして、なぜ immutable なオブジェクトが実際のデータを表現していると思ったのかと言うと、immutable なオブジェクトには __dict__ 属性がないからです。

mutable なオブジェクトは Python は x.a と参照された時、内部で x.__dict__['a'] に変換して値を参照しています。

>>> class X:
...   def __init__(self):
...     self.a = 1
... 
>>> 
>>> 
>>> x = X()
>>> x.a
1
>>> x.__dict__['a']
1
>>> 


しかし、immutable なオブジェクトには __dict__ 属性が存在しません。おそらく __dict__ を使わずに属性を固定して(immutable にして)、リテラルを表現しているものと思われます。

>>> a = 100
>>> a.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__dict__'
>>>
>>> b = range(10)
>>> b.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'range' object has no attribute '__dict__'
>>>

◯ str クラスのオブジェクトの構造

Python のテキストデータは str オブジェクト、
すなわち 文字列 として扱われます。
文字列は Unicode コードポイント
イミュータブルなシーケンスです。
4.7. テキストシーケンス型 — str

文字集合では、個々の文字に対して、
文字集合内での符号位置が決められている。
これをコードポイントという。
文字コード考え方から理解する Unicode と UTF-8 の違い


まとめ




値はオブジェクトの集まりで表現されるもの




なんとなく値とは何かについて伝わったでしょうか。マニュアルの解説記事から、値とは何かについて理解を深めて見てください。