最近、Pythonでデータ処理を行い、簡単なアラート機能のバッチ処理を行うコードをレビューしています。
その中で、次のようなコードがあってびっくりしました。(若干書き換えてます)
import pandas as pd
def select_this_month(df: pd.DataFrame) -> pd.DataFrame:
"""今月のデータのみを取り出す
Args:
df: フィルタリング対象のデータフレーム
Returns:
フィルターしたデータフレーム
"""
now = df["Date"].max()
y, m = now[0:4], now[5:7]
res = df[df['Date'] >= (y + "-" + m + "-01")]
return res
このコードを見た際、pandasのmax
で最大値を取り出しているし(数値型やdatetime型?)、スライスで部分文字列を取り出している(文字列型?)し、「なんだコレ?pandas組み込みの日付型?」と思ってしまいました。
よくよく調べると、これはただの文字列型で、それに比較演算子(不等号)が定義されているだけでした。
a = '2016-12-31'
b = '2016-01-01'
a > b
# => True
a < b
# => False
Pythonの公式ドキュメントにも、比較演算子の結果を明示している箇所を見つけました
。
Strings (instances of str) compare lexicographically using the numerical Unicode code points (the result of the built-in function ord()) of their characters.
Strings and binary sequences cannot be directly compared.
とりあえずGoogle翻訳しておきます。
文字列(strのインスタンス)は、文字のUnicodeコードポイント(組込み関数ord()の結果)を使って辞書的に比較します。 [3]
ストリングとバイナリシーケンスを直接比較することはできません。
ord関数のドキュメントにもこう書いてあるのでUnicodeポイントで比較されるみたいですね。
1 文字の Unicode 文字を表す文字列に対し、その文字の Unicode コードポイントを表す整数を返します。例えば、 ord('a') は整数 97 を返し、 ord('€') (ユーロ記号) は 8364 を返します。これは chr() の逆です。
ということで、
- 日付の文字列が必ず0詰めされている
- YYYY-MM-DDの形式で計算されている
なら文字列型でも問題なく挙動しそうです。
やっぱり日付型を使ったほうがいいとは思いますが。