前回の記事で「RにはないPythonの文法・テクニック」として演算子,for文,条件分岐について書きました。記事を公開してからRガチ勢の方々に「これはRでもあるよ!」とツッコミを頂きすぐに訂正しました。
今回はデータ型についてピックアップしてみます。名著である『Python 実践入門』と『Python言語によるプログラミングイントロダクション』を参考にしながら,Python documentationを参照したいと思います。
Rに無いものだけピックアップする予定だったのに,書いてる途中にいくつかの機能はRにもあることが判明しました(私の知識不足)。でもメジャーな機能ではないということで載せたままにします爆
文字列への変数の埋め込み + 書式化
フォーマット済み文字列リテラル (f-string)
Python documentationの 2.4.3. フォーマット済み文字列リテラルのページに以下の記述があります。
フォーマット済み文字列リテラル(formatted string literal)または f-string は、接頭辞 'f' または 'F' の付いた文字列リテラルです。これらの文字列には、波括弧 {} で区切られた式である置換フィールドを含めることができます。
まず文字列リテラルとは単純にクオーテーション'で囲んでできる文字列/str型を指します。"apple"みたいなものです。フォーマット済み文字列リテラルは,文字列リテラルの一部を,別で用意している変数(文字列や数値)と置き換えられるという機能です*1。変数の埋め込みを行う際のポイントは2点です。
- クオーテーションの前にfを付け
- クオーテーションの中で{変数名}を用いる
>>> my_name = "パイソン太郎" >>> my_age = 65 >>> f"Hi, my name is {my_name}. I'm {my_age} years old" "Hi, my name is パイソン太郎. I'm 65 years old"
また以下のように数値や日付の書式化も可能です。
>>> width = 10 >>> precision = 4 >>> value = 12.34567 >>> f"result: {value:{width}.{precision}}" 'result: 12.35'
- Rにおける変数埋め込みと書式化 -
「Rで変数埋め込みと書式化をするなら可読性の酷いpaste()とsprintf()の組み合わせだろうなぁ」と思っていましたが念の為調べてみると,なんとRにもf-stringと同じ用途のライブラリが3つもありました。
- fstringsパッケージ
- stringr::str_interp: 有名なHadley氏の文字列操作パッケージstringrの関数
- glue::glue: こちらもtidyverseのパッケージ
どのライブラリもPythonのf-stringを模して作成されたものだと思います。str_interpとglueを使ってみました。超使いやすいです。
> library(stringr) > my_name <- "パイソン太郎" > my_age <- 65 > str_interp("Hi, my name is ${my_name}. I'm ${my_age} years old") [1] "Hi, my name is パイソン太郎. I'm 65 years old" > library(glue) > glue("Hi, my name is {my_name}. I'm {my_age} years old") Hi, my name is パイソン太郎. I'm 65 years old
ただ,Pythonではf-stringがデフォルトで搭載されている機能であるのに対し,Rのstr_interpやglueは比較的新しい関数なので,こういった記法がRユーザーの中ではまだ定着していないのではないかなと感じます。便利なのでどんどん使っていきましょう。
str.format
文字列メソッドの1つであるstr.formatはf-stringと同じように変数の埋め込みに利用できます。用語集に以下の記述があります。
文字列の書式化操作を行います。このメソッドを呼び出す文字列は通常の文字、または、 {} で区切られた置換フィールドを含みます。それぞれの置換フィールドは位置引数のインデックスナンバー、または、キーワード引数の名前を含みます。返り値は、それぞれの置換フィールドが対応する引数の文字列値で置換された文字列のコピーです。
少し分かりづらいのでまとめると以下です。
- 文字列の中に波括弧{}を含める
- 文字列の後に.formatメソッドを続け,波括弧{}に入れたいもの(文字列や数値)を引数として渡す
>>> "Hi, my name is {}. I'm {} years old".format("パイソン太郎", 65) "Hi, my name is パイソン太郎. I'm 65 years old"
他にも辞書型とformatを組み合わせた書き方など色々ありますが割愛します。
- Rにおけるstr.format -
str.formatはRのsprintfに似ていますが,sprintfは実数のみ扱えるのに対し,str.formatは文字列でも数値でも式でも扱えるので,これらは適応範囲が異なります。しかしながら上に挙げたstr_interpやglueで代用できるのでこのstr.formatの記法がRになくても特に問題なさそうです。
immutable(不変)なオブジェクト
用語集のimmutableを見てみます。
immutable(イミュータブル): 固定の値を持ったオブジェクトです。イミュータブルなオブジェクトには、数値、文字列、およびタプルなどがあります。これらのオブジェクトは値を変えられません。別の値を記憶させる際には、新たなオブジェクトを作成しなければなりません。
抑えておくべき点は数値・文字列・タプルは不変で,オブジェクトの中身を変えられないという点です。つまり数値1や文字列"a"に何か代入することができない,ということです。
>>> 1 = 2 File "<input>", line 1 SyntaxError: cant assign to literal >>> "a" = 2 File "<input>", line 1 SyntaxError: cant assign to literal
Rでも数値や文字列に何か代入するはできませんが,そもそもそんな馬鹿げたことは誰もやらないと思います。なのでRユーザーで普段から"immutableなオブジェクト"について意識している人は少ないかと思います。
では何故Pythonにおいてimmutableなオブジェクトが敢えて取り上げられるのか。理由がこちらです。
イミュータブルなオブジェクトは、固定のハッシュ値が必要となる状況で重要な役割を果たします。辞書のキーがその例です。
つまり,辞書型のキーにはimmutableなオブジェクトしか与えられないということです。
# immutableオブジェクトの例 >>> {'one': 1} # 文字列 {'one': 1} >>> {('John', '26'): 1} # タプル {('John', '26'): 1} >>> {1: 'one'} # 数値 {1: 'one'} # mutable object >>> {[1]: 0} # リストを辞書のキーとして与える Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: unhashable type: 'list' >>> {{'one': 1}: 'first case'} # 辞書を辞書のキーとして与える Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: unhashable type: 'dict'
Rで普段意識しない"不変なオブジェクト"について,Pythonでは意識する必要があります。
カッコなしでタプルを作成
入門書には必ず説明が載っている配列の1つがタプルです。リストは要素が可変(mutable)な配列ですが,タプルは要素が不変(immutable)な配列です。
タプルの作り方についてPython documentationの5.3. タプルとシーケンスを見てみましょう。
タプルの表示には常に丸括弧がついていて、タプルのネストが正しく解釈されるようになっています。タプルを書くときは必ずしも丸括弧で囲まなくてもいいですが、(タプルが大きな式の一部だった場合は) 丸括弧が必要な場合もあります。
要するに,タプルは丸括弧かカッコなしで作成できます。また要素1つのタプルは,1つめの要素の直後にカンマを打てば作れます。
# カッコあり >>> x = (1, 2, 3) >>> print(x) (1, 2, 3) # カッコなし >>> y = 1, 2, 3 >>> print(y) (1, 2, 3) # 要素一つカッコなし >>> z = 1, >>> print(z) (1,)
このカッコなしで配列を作れたり,カンマで終了してOKという記法がRユーザーにとって見慣れない部分かなと思います。Rでベクトル/行列/配列を作る際は,それぞれc(),matrix(), array()関数で作りますが,関数なので当然カッコが必要あり,カンマで終わったりできません。
終わりに
間違いがあればすぐに訂正するので是非ご指摘ください。
書きながら思ったんですが,「RにないPythonのテクニック」なんて挙げ始めたら切りがないですね。 それでもメジャー所をピックアップしているつもりなので目を瞑ることにします。
次回は内包表記を取り上げます。
*1:Python3.6以前は%演算子を使った方法が主流でしたが,可読性が低いためPython3.6以降はf-stringが推奨されています。参照: PEP 498 Literal String Interpolation