型についてのあれこれ(3) - 文字列とコレクション

初回公開:
最終更新:2017/07/09

【 目次 】

シーケンス型 (sequence)

シーケンス型は順番を持った値の集まりと考えられる。

シーケンス型の型階層は以下のようになっている。(多分、こんなふうなイメージ)

シーケンス型 (sequence)
    変更不能なシーケンス (immutable sequence)
        文字列型 (string)
        Unicode 文字列型
        タプル型 (tuple)
    変更可能なシーケンス型 (mutable sequence)
        リスト型 (list)
        Byte Arrays

シーケンス型の操作については

文字列型 (string)

文字列は順番を持った文字の集まりと見ることもできる。

文字列はpython2とpyhon3で異なる部分があるので、まずはpython2からみていく。

str型 - (8ビットの)文字列型

文字列の各要素は文字 (character) です。文字型 (character type) は存在しません。単一の文字は、要素が一つだけの文字列として表現されます。各文字は(少なくとも)8-bit の 1 byte を表現します。組み込み関数 chr() および ord()を使うと、文字と非負の整数で表されたバイト値の間で変換を行えます。0-127 の値を持つバイト値は、通常 同じ ASCII 値をもつ文字を表現しています...

pythonにはc言語のcharような文字型は存在しない。
文字列型は1文字8ビットのシーケンス型(順番を持った値の集まり)という事になる。
文字型は1文字8ビットであるため、当然,日本語は表現できない。
組み込み関数strを使って生成することもできる。

  • 3.1.2. 文字列

    文字列 (string) はシングルクオート ' で囲むか、ダブルクオート " で囲んで表します。...
    文字列を囲うクォート記号は通常はシングルクォート(')ですが、文字列がシングルクォートを含みダブルクォート(")を含まない場合は、ダブルクォートで囲います。

シングルクォートとダブルクォートの使い分けは?

他の言語では、シングルクォートの場合は変数展開しないがダブルクォートの場合は変数展開をおこなうなどの違いがあるが、pythonでははシングルクォートとダブルクォートで違いは無い。

  • お気楽 Python プログラミング入門

    文字列には「エスケープシーケンス」を含めることができます。...
    演算子 + は文字列を連結した新しい文字列を作り、演算子 * は文字列を指定した回数だけ繰り返した新しい文字列を作ります。...
    エスケープシーケンスを無効にしたい場合は、文字列の前に r または R を付けます。これを raw string といいます。...
    複数の行にわたって文字列を定義したい場合は継続行を使います。継続行は最後にバックスラッシュ (円記号) を付けます。

Unicode型 - Unicode文字列型

Unicode オブジェクトの各要素は Unicode コード単位です。 Unicode コード単位とは、単一の Unicode オブジェクトで、Unicode 序数を表現する 16-bit または 32-bit の値を保持できるものです (この序数の最大値は sys.maxunicode で与えられており
組み込み関数 unichr()および ord() は、コード単位と非負の整数で表された Unicode 標準 3.0 で定義された Unicode 序数との間で変換を行います。他の文字エンコード形式との相互変換は、 Unicode メソッド encode() および組み込み関数 unicode()で行うことができます。

Unicode文字列は以下のようにuを付けて通常の文字列と区別する。

str = u"Unicode文字列です"

組み込み関数Unicodeを使って生成することもできる。

row文字列

型では無いがエスケープシーケンスを無効にするための文字列を表現方法としてraw文字列というのもある。
pythonでもC言語と同様エスケープシーケンスを使って制御文字を文字列中に埋め込むことができる。

例えば文字列の最後に改行を入れる場合は

str = u"Unicode文字列です\n"

エスケープシーケンスは便利なのだが、正規表現やWindowのデレクトリ表現では\の文字を多用するため不便である。
このため文字列の前にrを付けてエスケープシーケンスを無視するrow文字列というものがある。

row文字列の例

str = r"C:\Program Files\Common Files"

ユニコード文字列の場合は更にuを付けて

str = ur"C:\日本語のデレクトリ名"

raw 文字列の制約など

三重クォート

三重のクォートを使うとヒアドキュメントを実現できる。
三重のクォートはシングル クォートとダブルクォートのどちらで囲んでも良い。
\文字を重ねていれる必要が無い。

三重のクォートの「raw string」なんてものある。

Python3の文字列型

「文字型は1文字8ビットであるため、当然,日本語は表現できない」といったこれまでの話はPython2での話しであって、Python3では文字列型はUnicode文字列型に統一されていて、Python3のstr型(文字列型)はUnicode文字列型を指す。


文字列の操作については

配列...のようなもの - タプル(tuple)とリスト(list)とbytearray

pythonには一般のプログラミング言語のように配列は存在しないが、タプル型 (tuple),リスト型 (list),Byte Arraysを使えば配列と同じような操作が実現できる。
タプルとリストはどのような型も要素として保持できるが、bytearrayはその名のとおりbyte(0 <= x < 256 の整数)列の要素しか保持できない。
タプルとリストの違いはタプルは要素を変更できない(immutable)のに対して、リストは変更可能 (mutable)である事。
bytearrayも変更可能である。

タプル

タプルは値をカッコでくくって指定する。

tpl=(a,b,c)

組み込み関数tupleを使って生成することもできる。

タプルの()は省略できる。

>>> tpl = 1, 2, 3
>>> a, b, c = tpl
>>> print tpl, a, b, c
(1, 2, 3) 1 2 3

一つの要素を持つタプルは、値の後ろにコンマが必要なので注意。

>>> tpl = (5)   # タプルでは無く単一の値
>>> tpl
5
>>> tpl = (5,)   # タプル
>>> tpl
(5,)

リスト

リストは値を大カッコでくくって指定する。

lst=[a,b,c]

組み込み関数listを使って生成することもできる。
リストやタプルを入れ子にして多次元配列を表すことができる。
多次元配列の例については型についてのあれこれ(8) - コレクションとfor文を参照

タプルは要素を変更できないがリストは変更可能

変更可能の意味は?
参照型の意味がわかっていないと何が変更できて何が変更できないのか混乱してしまう。

以下のコードは7行目でエラーになってしまう。

#coding: UTF-8

# タプルは要素をカッコでくくる。
var = (2,5.5,7 + 8j)

print var
var[0] = 10   # <- ここでエラー:タプルは要素を変更できない。
print var[0]

しかし、変数varを以下のようにタプルからリストに変更すると、エラーは発生しない。

#coding: UTF-8

# リストは要素を大カッコでくくる。
var = [2, 5.5, 7 + 8j]

print var
var[0] = 10   # <- OK
print var[0]

では、以下のコードはどうだろう。

#coding: UTF-8

var1 = 1
var2 = 2
var3 = 3

# 変数tpl_varにタプルを代入
tpl_var = (var1,var2,var3)
print tpl_var

# 変数list_varにリストを代入
list_var = [var1,var2,var3]
print list_var

# var1を変更
var1 = "var1の値を変更"

# しかしタプルもリストも値は変わらない
print tpl_var
print list_var

あたりまえの事であるがvar1の値を変更しても、タプルもリストも値は変わらない。

ならば、クラスのインスタンスを要素に持つリストとタプルを生成して、クラスのインスタンスの内容を変更したらどうなるだろう。

#coding: UTF-8

# pyhton3のコード
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __repr__(self, **kwargs):
        return self.name+"は"+str(self.age)+"才です。"
        return "{name}は{age}才です。".format({"name": self.name, "age": self.age})

var1 = Person("愚鈍人",999)
var2 = Person("妻",17)
var3 = Person("子",10)

# 変数tpl_varにタプルを代入
tpl_var = (var1,var2,var3)
print(tpl_var)

# 変数list_varにリストを代入
list_var = [var1,var2,var3]
print(list_var)

# var1(のインスタンス変数ageの値)を変更
var1.age = 0

# しかしタプルもリストも値は変化
print(tpl_var)
print(list_var)

これまでのコードは、python2のコードを示してきたが、上記のコードはpython3のコードである。
なぜpython3のコードにしたのかというとpython2では__repr__関数の戻り値に日本語が返せないためだけの理由で、本来の目的とは関係ない。
参考までに述べると__repr__関数 は、JavaのtoStringメソッドに相当するクラスの値を文字列に変換するメソッドである。

実行結果

(愚鈍人は999才です。, 妻は17才です。, 子は10才です。)
[愚鈍人は999才です。, 妻は17才です。, 子は10才です。]
(愚鈍人は0才です。, 妻は17才です。, 子は10才です。)
[愚鈍人は0才です。, 妻は17才です。, 子は10才です。]


実行結果をみると、タプルもリストも値が変化しているのがわかる。
奇妙なようにみえるが、参照型の意味を理解していれば、当然の結果である。
タプルは要素の参照先を変更できないが、参照先のオブジェクトの状態は変更できるという事。

タプルとリストのコンストラクタ(見かけ上はキャストのようにも見えるが)を使ってリストをタプルに,タプルをリストに変換できる。
タプルは要素を変更できないが、以下のようにタプルをいったんリストに変換した後、リストの要素を変更し直せば同等の事が可能。
あまりパフォーマンスの良い方法とは言えないが。

tpl=(2,3,4)
lst=list(tpl)
lst[1]=99
tpl=tuple(lst)

実行結果

(2, 99, 4)

タプルもリストも「+」演算子を使って要素を連結できる。

連結してできた新しいタプルをもとの変数に代入してやればタプルに要素を追加したように見える。

tpl=tpl+("A","B")
print tpl

実行結果

(2, 99, 4, 'A', 'B')

リストの操作については

その他のシーケンス型

bytearray

組み込み関数bytearrayを使って生成することができる。

python3ではバイナリシーケンス型としてbytes型とともに分類されている。

4.8. バイナリシーケンス型 — bytes, bytearray, memoryview

buffer

どのようなものかよくわからない。
とりあえず、関係ありそうな情報を。

python3では「Buffer プロトコル」という名前になったのかな?

xrange

python2では組込み関数xrange([start], stop[, step])range([start], stop[, step])というのがあってどちらも、for文などで、等差数列を含むリストを生成するために使われる。

# xrangeの例
for i in xrange(10) :
    print i

# xrangeの例
for i in range(10) :
    print i

上記の例ではxrangeを使ってもrangeを使っても同じ結果になるが、
xrange関数がxrangeオブジェクトを返すのに対してrange関数はリストを返す。

>>> range(0, 30, 5)
[0, 5, 10, 15, 20, 25]
>>> xrange(0, 30, 5)
xrange(0, 30, 5)
>>> type(range(0, 30, 5))
<type 'list'>
>>> type(xrange(0, 30, 5))
<type 'xrange'>

xrangeを使ったほうがメモリーの使用量が少ないので良いとされている。

と、またしてもここまではpython2での話し。
python3ではxrange型が廃止されていて、range型が新たに追加されているのでこちらを使う。

arrayモジュール

組込み型ではないが、arrayモジュールを利用して配列のようなものを実現する事もできる。

8.6. array — 効率のよい数値アレイ — Python 2.7ja1 documentation

集合型

順序のない,重複しない要素を扱う集合型というのがある。

  • Sets
  • Frozen sets

リストや辞書などとくらべてあまり使わないので、参考URLのみを以下に記しておく。

追記

集合型に関する記事を追加しました。

マップ型 (mapping)

5.8. マップ型 - 5. 組み込み型 — Python 2.7ja1 documentation

マップ型 (mapping) オブジェクトは hashable (ハッシュ可能) な値を任意のオブジェクトに割り付けます。マップ型は変更可能なオブジェクトです。現時点では、ひとつだけの標準マップ型として辞書型 (dictionary) があります

辞書型 (dictionary)

いわゆるハッシュマップとか連想配列と他の言語でよばれるているものである。

使い方は

辞書の定義
タプルではカッコ()で括り、リストは大カッコ[]で、そして辞書は中カッコ{}でくくり「キー:値」をカンマで区切って指定する事になる。

tel = {'jack': 4098, 'sape': 4139}

dict() コンストラクタによる辞書の生成。

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}

辞書の値の設定,取得は

>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098

値の取得には他にもgetメソッドを使う事もできる。

>>> tel.get('jack')
4098

[キー名]を使って値を取得する場合にキーが存在しない場合はKeyErrorの例外が送出されるが、getメソッドの場合はエラーが発生しない。
また、getメソッドの第2引数を指定するとキーが存在しない場合に第2引数で指定した値が返される。

>>> tel['xxx']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'xxx'
>>> tel.get('xxx')
>>> tel.get('xxx','yyy')
'yyy'

【追記】

辞書型 (dictionary)のキー値や値は文字型の場合が多いが、もちろん他の言語の連想配列のように文字型以外の型でもかまわない。

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

persons = {1: Person(u"愚鈍人",999), 2: Person(u"愚鈍人の妻",17)}

print persons[1].name,persons[2].name

実行結果

愚鈍人 愚鈍人の妻

コンテナとコレクション

  • コンテナ (データ型) - Wikipedia

    コンピュータプログラミングにおいて、コンテナとはオブジェクトの集まりを表現するデータ構造、抽象データ型またはクラスの総称である。 コレクションとも言う。コンテナには複数の種類があり、それそれ独自の方法でオブジェクトを組織的に格納する。

「pythonにおける文字列を除くシーケンス型,マップ型,集合型」を総称して複数のデータの集まりという事でコンテナとかコレクションと呼ぶ。

コンテナをエミュレートする - データモデル — Python 2.7ja1 documentation

コンテナは通常、(リストやタプルのような) シーケンスや、(辞書のような) マップ型を指しますが、他のコンテナも同じように表現することができます。
...
変更可能なシーケンスでは、Python の標準リストオブジェクトのように、メソッド append(), count(), index(), extend(), insert(), pop(), remove(), reverse(),および sort() を提供しなければなりません。

JavaやC#でのコレクションは

collections

collectionsモジュールに、dict, list, set, および tuple に代わる、特殊なコンテナデータ型を実装している。

ページのトップへ戻る