今、話題の人工知能(AI)などで人気のPython。初心者に優しいとか言われていますが、全然優しくない! という事を、つらつら、愚痴っていきます

006.Pythonのデータ型1

»

初回:2018/09/12

0.今回のまとめ
 Pythonのデータ型として、str,int,float,bool,list(リスト),tuple(タプル)
dict(辞書型)というのがあります。基本型(str,int,float,bool)だけ見ても、「誰が書いても同じようになる」なんてことは言えません。いや、普通の言語より、色々な書き方ができてしまうと思います。

1.文字型
 Pythonの文字列は、immutable(変更不能)です。

>>> a='foo'
>>> b="bar"
>>> c='''baz'''
>>> d="""hoge"""

色々と複雑な約束事(※1)がありますが、基本でもあるので理解しておきましょう。(※2

 まずは、文字列の連結。
>>> x = a + b + c
>>> x
'foobarbas'
>>>

+記号で連結ではなく、スペースで連結できます。
>>> x = 'foo' "bar" '''baz'''
>>> x
'foobarbaz'
>>>

変数を、スペース連結することは出来ません。
>>> x = a b c
File "<stdin>", line 1
x = a b c
^
「ちょっと、しっかりしてよ」(※3
>>>

自分自身に文字列を加算(連結)することもできます。

>>> x += a
>>> x
'foobarbasfoo'
>>>

自分自身に文字列を乗算(繰り返し連結)することもできます。

>>> y = 'AAA'
>>> y *= 3
>>> y
'AAAAAAAAA'
>>>

2.数値型
int型といっても、Python 3 では、整数型を意味します。(桁数の制限がない)例えば、階乗の計算の場合、結果が爆発的に増えてしまいますが、きちんと計算できます。

def kai( num ):
if( num <= 1 ) : # 正確には、0!=1 が終了条件です。(※4
return 1
else:
return int(num) * kai(num-1)

>>> kai(5)
120
>>> kai(10)
3628800
>>> kai(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
>>> kai(1000)
「調子に乗ってるんじゃないわよ」(※5

3.浮動少数点型
 浮動少数点数(float)は、2進数でデータを管理しているコンピュータにとって、いつでも厄介な問題を提示します。(※6

>>> a=0.1
>>> a *= 3
>>> a
0.30000000000000004
>>>

4.論理型
 bool(論理)型は、通常、TrueとFalseという予約語を使用しますが、Pythonの場合は、0は、Falseと同じ扱いになりま、0以外の数値は、Trueになります。

逆に、TrueやFalseは、int型に変換可能です。
>>> int(True)
1
>>> int(False)
0
>>>

>>> True + 5
6
>>> False * 12
0
>>>

他にも、論理値で判定できる項目があります。

def hantei(val):
if( val ) :
print( True )
else:
print( False )

>>> hantei(0)
False
>>> hantei(1)
True
>>> hantei(100)
True
>>> hantei('AAA')
True
>>> hantei('')
False
>>> hantei(None)
False
>>> hantei(True)
True
>>> hantei({})
False
>>> hantei([])
False
>>> hantei([1,])
True
>>> hantei({'A':'A'})
True
>>>

まだ、説明していませんが、リストや辞書の場合、要素が0個の場合は、Falseですが、設定されている場合は、True になります。

======= <<注釈>>=======

※1 色々と複雑な約束事
 複雑な約束事をきちんとこなさないと、すぐに不機嫌になります。

※2 理解しておきましょう
 下記の説明が判りやすくてよいと思います。
https://qiita.com/tomotaka_ito/items/594ee1396cf982ba9887
Python文字列操作マスター

※3 「ちょっと、しっかりしてよ」
>>> x = a b c
File "<stdin>", line 1
x = a b c
^
SyntaxError: invalid syntax

※4 0!=1 が終了条件
https://mathtrain.jp/0nokaijo
0の階乗を1と定義する理由

※5 「調子に乗ってるんじゃないわよ」
>>> kai(1000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in kai
File "<stdin>", line 5, in kai
File "<stdin>", line 5, in kai
[Previous line repeated 994 more times]
File "<stdin>", line 2, in kai
RecursionError: maximum recursion depth exceeded in comparison

このエラーは、整数値の桁数問題ではなく、再帰定義の深さの問題です。
例えば、組み込み関数では、きちんと計算できます。
>>> import math
>>> math.factorial(1000)

※6 浮動少数点数の厄介な問題
https://docs.python.jp/3/tutorial/floatingpoint.html
15. 浮動小数点演算、その問題と制限

https://qiita.com/u_kan/items/ab20a9ae39d3e0666857
pythonのデータ型についてシンプルにまとめてみる

Comment(5)

コメント

shiracamus

自分自身に文字列を加算(連結)することもできます。

>>> x += a
>>> x
'foobarbasfoo'
>>>

イミュータブル(変更不可)なのに自分自身に文字列を加算できるなんて不思議だと思いませんでしたか?
実は、Pythonインタープリタ内部でエラーが発生して、 x = x + a に読み替えて再実行され、新しい文字列オブジェクトを作って変数に代入します。
そのため 代入前の オブジェクトid と代入後の オブジェクトid が変わってしまいます。

>>> a = 'foo'
>>> x = 'foobarbaz'
>>> id(x)
140085962223024
>>> x += a
>>> id(x)
140085962244400

shiracamus

補足:

+ 演算子は、 __add__ メソッドを呼び出し、新たなオブジェクトを生成します。
>>> x.__add__(a)
'foobarbazfoo'

+= 演算子は、 __iadd__ メソッドを呼び出しますが、文字列ではエラーになります。
>>> x.__iadd__(a)
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'str' object has no attribute '__iadd__'

ちゃとらん

おっしゃるとおりです。

文字列の連結に、+= という構文が使えます。

くらいが、正しいのでしょうね。

ところで、
> 実は、Pythonインタープリタ内部でエラーが発生して、 x = x + a に読み替えて再実行され、
という箇所、 わざわざ、内部でエラーにしなくても、 += という構文をインタープリタが解釈すればよいだけだと思いますが、どうなんでしょう。

import time

x = "1"
a = "2"

start = time.time()
for i in range(1,10000000) :
x += a

end = time.time()
print( end-start )

x = "1"

start = time.time()
for i in range(1,10000000) :
x = x + a

end = time.time()
print( end-start )

で、4回計測したところ、
c:\TEMP>python ./test1.py
8.081801652908325
8.087780475616455

c:\TEMP>python ./test1.py
8.234074592590332
8.19342827796936

c:\TEMP>python ./test1.py
8.174585819244385
8.139858961105347

c:\TEMP>python ./test1.py
8.113073825836182
8.138370513916016

エラー処理と、再計算で、+= の方が、遅くなるはずですが、ほとんど、誤差範囲です。
+= 構文の方が、見やすい(意味がわかりやすい)ので、こちらを使うほうが良いのでしょう。

shiracamus

> += という構文をインタープリタが解釈すればよいだけだと思いますが、どうなんでしょう。

+= という構文を __iadd__ メソッド呼び出しだと解釈しています。
ただ、イミュータブルにはそのメソッドがないので __add__ 呼び出しと解釈します。

コメントを投稿する