今回は少し細かい話で、タイトルにある通り数値と文字の違いについての確認になります。細かいですがプログラムを勉強する上で、知っておかなく必要がある大切な内容です。
数値と文字(列)は別物
「2
」(整数)や「3.0
」(小数点数)の様に表される値で算術に用いることができます。スロットゲームでは所持コイン数や、絵柄が揃ったときの倍率にも使用しています。
Python に限らずほとんどのプログラミング言語では整数と浮動小数点数を分けているのも特徴です。整数と小数点数の両方を用いて計算した場合、結果は小数点数になります。

一方、文字(列)は「'あいうえお'
」や「"かきくけこ"
」のように、シングルクォーテーション('
)または、ダブルクォーテーション("
)で囲って表現されます。文字(列)は足し算をすることで、文字列を結合できるという特徴があります。

この例だけだと、別物と思うのは当然だと思います。しかし「2
」と「'2'
」、「3.0
」と「"3.0"
」ではどうでしょうか?Python では、一部の例外を除いて数値と文字(列)を同じ式の中で扱うことが許されておりません。実際に確認してみましょう。ここでは、何回もエラーになるので、対話モードで確認してます。
1 + '2.0' #==> TypeError: unsupported operand type(s) for +: 'int' and 'str' '3.123' - 0.123 #==> TypeError: unsupported operand type(s) for -: 'str' and 'float' 5.0 * '6.0' #==> TypeError: can't multiply sequence by non-int of type 'float' 5 * '6.0' #==> '6.06.06.06.06.0' '6.0' * 5 #==> '6.06.06.06.06.0' '7' / 8 #==> TypeError: unsupported operand type(s) for /: 'str' and 'int'

もうお分かりいただけたと思いますが、上記の “一部の例外” とは “文字列と整数の掛け算” のことでした。このケースだけ、文字列を繰り返した結果になります。面白いですねw

これはプログラミング言語によって扱いが違います。
本文下の方に、私の身近なプログラミング言語についてまとめておきますね。
型(type)
ここまで日本語では説明に「整数」「浮動小数点数」「文字(列)」を使ってきました。これを Python 風に呼称するにはどうしたらいいでしょうか?そのヒントは、上記のエラー内容に隠れています。
エラー内容を細かく見てみると、「type(s)
」の後に「int
」「float
」「str
」と出力されています。これが Python 内での……動(やや)もすると、ほとんど全てのプログラミング言語での呼称になります。
値の種類を「型」(type)というもので分類し、代表的なものには以下のようなものがあります。そして「int型」(いんとがた)とか、「str(ing)型」(すとりんぐがた)のように “型” と合わせて会話に登場します。
※型(type)は自作することもできるため無限に存在します。
型 | 意味 | Python での表記 |
int | integer の略。整数。 | 1 、234 |
float | 浮動小数点数。 | 2.0 、3.14 |
str | string の略。文字列 | 'hello' 、"world" |
bool | boolean の略。真偽値。 真(True)と偽(False)しかない。 | True 、False |
list | リスト、配列。 型を問わず、復数個の値を保持できる。 | [1, 2.0, 'a', True] |
dict | 辞書。 キー(key)と値(value)のペアを複数個保持できる。 | {0: 'hello', 'w': 'world'} |
set | 集合。 順不同、重複しない複数個の値を保持できる。 | {0, 1, 'hello', 'world'} |
tuple | タプル。 リストっぽいけど、変更不可(イミュータブル)。 | (1, 2.0, ‘a’, True) |
型の調べ方
Python では「type
」を使って型を調べることができます。その様子を下記します。ほとんどは「あれ、この変数に入ってるのって何型の値だっけ?」という場合かと思いますので、あえて変数に代入してから調べてます。
※ print()
を使って結果を表示することもできます。しかし type()
が目立たなくなってしまうので、今回も対話モードで確認しました。
a = 1 type(a) #==> <class 'int'> b = 2.0 type(b) #==> <class 'float'> c = 'hello' type(c) #==> <class 'str'> d = True type(d) #==> <class 'bool'> e = [1, 2.0, 'a', True] type(e) #==> <class 'list'> f = {0: 'hello', 'w': 'world'} type(f) #==> <class 'dict'> g = {0, 1, 'hello', 'world'} type(g) #==> <class 'set'> h = (1, 2.0, 'a', True) type(h) #==> <class 'tuple'> # 変数にいれなくても確認できます type('hello') #==> <class 'str'>

(おまけ)Python は小数点数の扱いがニガテ……
小数点数を用いた計算「0.5 + 0.25 == 0.75
」「1.11 + 2 == 3.11
」は成り立つと思いますか?普段の暮らしでこれを疑うことはないでしょう。これは Python でも当然……ではないんです!実は Python は小数点数を用いた計算がとてもニガテです。実際にプログラムを書いて確認してみましょう。
if 1.5 + 2.25 == 3.75: print('正しい') # 結果はこちらになる。これは正しい。 else: print('違う!!') if 1.11 + 2.00 == 3.11: print('正しい') else: print('違う!!') # 結果はこちらになる!

コンピュータは2進数、つまりゼロ(0)とイチ(1)だけの世界というのは聞いたことがあると思います。そのため整数については「39(10進数) →100111(2進数)」「255(10進数)→11111111(2進数)」のように簡単に表せます。では小数点数についてはどう考えたらいいのでしょうか?
これを説明するのは少し長くなりますので、別の記事にしたいと思います。ここではコンピュータが小数点数を扱うのがニガテだということ、そして Python も同じ様にニガテだということを覚えておいてください。
では、小数点数の計算を正確にやりたい場合はどうしたらいいのでしょうか?答えは「Decimal型」(でしまるがた)です。Python の公式ページ(こちら)の文言を借りると「正確に丸められた十進浮動小数点算術をサポート」されています。
まず「from decimal import Decimal
」と書く必要がある等、使い方にクセがあります。今回のスロットゲームでは必要ないため、この程度の紹介とさせていただきます。
from decimal import Decimal print(type(Decimal('1.11'))) #==> <class 'decimal.Decimal'> if Decimal('1.5') + Decimal('2.25') == Decimal('3.75'): print('正しい') # 正しく計算され、結果はこちらになります else: print('違う') if Decimal('1.11') + Decimal('2.00') == Decimal('3.11'): print('正しい') # 正しく計算され、結果はこちらになります else: print('違う')

あなたが金融や通貨に関するアプリケーションを作るようになった際には必要になります。その頃にはあなたのプログラミング能力も相当高くなっていることでしょうから、ご自身で decimal
について詳しく調べてみてください。
数値を文字列、文字列を数値に型変換
では、「現在の所持コインは 273 枚です」の様に、文字列と数値を合わせて使いたいときにはどうしたらいいでしょうか?「273
」が文字列だったら、上記の例にならって足し算するだけでいいですが、所持コイン数は数値として管理されています。
そんな時に登場するのが「型変換」や「キャスト」と言われる手法です。Python での「型変換(キャスト)」の様子を確認してみましょう。
a = 123 type(a) a = str(a) # str への変換は str() を使用する type(a) #==> <class 'str'> a = int(a) # int への変換は int() を使用する type(a) #==> <class 'int'> a = float(a) # float への型変換は float() を称する type(a) #==> <class 'float'> b = 'aiueo' # 型変換(キャスト)できない場合はエラーが発生 b = int(b) #==> ValueError: invalid literal for int() with base 10: 'aiueo'

ちなみに int型、str型への型変換はスロットゲーム中でも使用されています。

“フォーマット” は型変換をせずに文字列を生成する方法
あれこれ書いてきましたが、今回の目的(数値と文字列を使って、新しい文字列を表現する)には適したやり方ではありません。間違ってはいないのだけど悪手に分類されます。では、どういうやり方が推奨されているかと言うと……
- フォーマット済み文字列リテラル(f-string)を使う
- 文字列の format() メソッドを使う
- 文字列書式設定方法を使う(ただし、古いやりかた)
になります。それぞれの凝った使い方は公式ページ(こちら)に詳しく記載がありますので、そちらを参照していただくとして、ここでは簡単な使い方を確認しましょう。
フォーマット済み文字列リテラル
文字列の頭に f か F を付け、式を {expression}
と書くことで、 Python の式の値を文字列の中に入れ込む方法です。生成される文字列も容易に想像できるので一番オススメな方法になります。
test_result_math = 80 test_result_avg = 68.2343 print(f'数学のテストで {test_result_math} 点を取りました。') # 単純な埋め込み print(f'クラスの平均点は {test_result_avg:.2f} 点です') # 小数点以下の桁数制御 print(f'平均点との差は {test_result_math - test_result_avg:.2f} 点です') # 式を埋め込み print(f'{test_result_math:010}') # ゼロ埋め print(f'{test_result_avg:010.2f}') # ゼロ埋め+小数点以下の桁数制御 print(f'{test_result_avg:.3g}') # 全体の桁数制御 print(f'{test_result_avg:.2e}') # 指数表記(小数点以下の桁数制御) print(f'{test_result_avg:.2%}') # パーセント表記(小数点以下の桁数制御) print(f'My name is {"Michael":13}. Nice to meet you.') # 領域を確保 print(f'My name is {"Christopher":>13}. Nice to meet you.') # 右寄せ print(f'My name is {"Matthew":^13}. Nice to meet you.') # 中央寄せ print(f'My name is {"Joshua":<13}. Nice to meet you.') # 左寄せ print(f'My name is {"Daniel":_^13}. Nice to meet you.') # 寄せ+埋め

これくらい覚えておけば(忘れてもこの記事を見ればOK)困ることはないと思います。
文字列の format() メソッド
これは、上記 f-string の一つ前のやり方になります。この形式を使っているプログラムもまだまだ多いかも知れませんね。やれることは同じですが、書き方が変わります。
test_result_math = 80 test_result_avg = 68.2343 print('数学のテストで {} 点を取りました。'.format(test_result_math)) print('クラスの平均点は {:.2f} 点です'.format(test_result_avg)) print('平均点との差は {:.2f} 点です'.format(test_result_math - test_result_avg)) print('平均:{}、点数:{}'.format(test_result_avg, test_result_math)) # 複数、指定 print('平均:{1}、点数:{0}'.format(test_result_math, test_result_avg)) # 順序付き print('平均:{a}、点数:{b}'.format(a=test_result_avg, b=test_result_math)) # 名前付き

文字列書式設定方法
最後に「%
」を使った古いやり方です。
test_result_math = 80 test_result_avg = 68.2343 print('平均:%.2f、点数:%d' % (test_result_avg, test_result_math)) print('平均:%(avg).2f、点数:%(result)d' % {'avg': test_result_avg, 'result': test_result_math})

最後に
スロットゲームのプログラムには、フォーマット文字列を使ったいいやり方と、足し算を使った推奨されないやり方が混在しています。次回は、フォーマットを用いたやり方を復習するために、足し算を使って文字列を作っている箇所をフォーマットを用いたやり方に修正しましょう。
(おまけ)プログラミング言語毎の文字列の掛け算の違い
実行に当たっては paiza.IO を利用して確認いたしました。
Python
Python は文字列が連続して出力されます。
# coding: utf-8 # Your code here! a = 2 b = '3.0' c = a * b print(type(a)) #==> <class 'int'> print(type(b)) #==> <class 'str'> print(type(c)) #==> <class 'str'> print(c) #==> 3.03.0
JavaScript
JavaScript は勝手に数値に変換して計算してくれます。
以下の例で「a
」を「"あ"
」など数値以外にするとエラーが発生します。
process.stdin.resume(); process.stdin.setEncoding('utf8'); // Your code here! a = 2; b = '3.0'; c = a * b; console.log(typeof a); //==> number console.log(typeof b); //==> string console.log(typeof c); //==> number console.log(c); //==> 6
PHP
PHP も JavaScript と同じく勝手に数値に変換して計算してくれます。
数値以外にするとエラーになるのも同じ。
<?php // Your code here! $a = 2; $b = '3.0'; $c = $a * $b; echo gettype($a) . PHP_EOL; //==> integer echo gettype($b) . PHP_EOL; //==> string echo gettype($c) . PHP_EOL; //==> double echo $c . PHP_EOL; //==> 6 ?>
Ruby
Ruby ではエラーになります。Ruby は文末に「;」がなかったり「def」を使ったりと、Python に似ている部分が多いです。日本人が作ったプログラミング言語としても有名です。スタートアップ企業で採用されることも多いです。
# Your code here! a = 2 b = '3.0' c = a * b #==> String can't be coerced into Integer (TypeError) p a.class #==> Integer p b.class #==> STring
Java
かの有名な Java も同様にエラーになります。こちらは一昔前まで、プログラミングの登竜門みたいになってましたね。
import java.util.*; public class Main { public static void main(String[] args) throws Exception { // Your code here! var a = 2; var b = "3.0"; var c = a * b; //==> Main.java:9: error: bad operand types for binary operator '*' System.out.println(((Object)a).getClass().getName()); //==> java.lang.Integer System.out.println(b.getClass().getName()); //==> java.lang.String } }
C#
C# でもエラーになります。C# 以前に C++ というプログラミング言語があります。「++」を2つ重ねて「#」にした……という噂を聞いたことがあります。
public class Hello{ public static void Main(){ // Your code here! var a = 2; var b = "3.0"; var c = a * b; //==> Main.cs(7,17): error CS0019: Operator `*' cannot be applied to operands of type `int' and `string' System.Console.WriteLine(a.GetType()); //==> System.Int32 System.Console.WriteLine(b.GetType()); //==> System.String } }
Clojure
Clojure でもエラーになります。Java を元に作られているのでエラー内容に “java” が登場します。
Clojure は “神の言語” と名高い LISP を模したプログラミング言語です。作者のコメントがこちらで翻訳されていました。
; Your code here! (let [a 2 b "3.0" c (* a b)] ;;==> Syntax error (ClassCastException) compiling at (Main.clj:1:1). ;; class java.lang.String cannot be cast to class java.lang.Number (println (type a)) ;;==> java.lang.Long (println (type b))) ;;==> java.lang.String
コメント