IronPython 3.4 の正式リリース(2022年12月)から1年以上が過ぎました。
マイナーな存在ですが、Python と .NET のいいとこ取りができるので、個人利用の小規模なスクリプトを書くのに適しています。
.NET 8 もリリースされた機会に、備忘録を兼ねて IronPython との付き合い方をまとめておきます。
(2024.3.6 追記) 続編を投稿しました。
確認環境
- Windows 11 Pro(Ver. 23H2)
- .NET Runtime 8.0.2 (64-bit)
- IronPython 3.4.1 (3.4.1.1000)
IronPython のインストール
Windows 以外にも .NET や Mono(www.mono-project.com) 環境があれば、Linux, Mac を問わず動作します。(なお、Linux へのインストールはすでに投稿しています。)
IronPython の手動インストール
まずは、こちらから IronPython.3.4.1.zip をダウンロードします。
zip ファイルを適当な場所に展開し、「net6.0」と「lib」の2つのディレクトリを任意の場所にコピーして完了です。zip は削除して構いません。
c:\Users\User\IronPython
└── 📁 3.4
├── 📁 net6.0
└── 📁 lib
msi ファイル(IronPython-3.4.1.msi)は ipy.exe をインストールします。
こちらは.NET Framework がターゲットです。
インストールの詳細はこちらでご確認を。
起動
dotnet
コマンドに net6.0\ipy.dll を渡せば起動します。
.NET 8 で動かす場合は --roll-forward LatestMajor
オプションが必要です。
dotnet --roll-forward LatestMajor "C:\Users\User\IronPython\3.4\net6.0\ipy.dll"
(参考)環境による起動メッセージの違い
Windows + .NET 8(dotnet ipy.dll
で起動) <こちらが本記事の環境>
Linux + .NET 8(dotnet ipy.dll
で起動)
Windows + .NET Framework 4.8(ipy.exe
で起動)
import System
は必須
.NET API を利用する場合は、最低でも import System
が必要です。
整数を代入した変数 i
に対して import System
前と後とで dir(i)
を比較してみます。
i = 123
# import System 前
[attr for attr in dir(i) if attr[:2] != '__']
# ['bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator',
# 'real', 'to_bytes']
# import System 後
import System
[attr for attr in dir(i) if attr[:2] != '__']
# ['Abs', 'Add', 'Clamp', 'Compare', 'CompareTo', 'CopySign', 'CreateChecked',
# 'CreateSaturating', 'CreateTruncating', 'DivRem', 'Divide', 'Equals',
# 'GetBitLength', 'GetByteCount', 'GetHashCode', 'GetShortestBitLength', 'GetType',
# 'GetTypeCode', 'GreatestCommonDivisor', 'IsEven', 'IsEvenInteger', 'IsNegative',
# 'IsOddInteger', 'IsOne', 'IsPositive', 'IsPow2', 'IsPowerOfTwo', 'IsZero',
# 'LeadingZeroCount', 'Log', 'Log10', 'Log2', 'Max', 'MaxMagnitude', 'MaxValue',
# 'MemberwiseClone', 'Min', 'MinMagnitude', 'MinValue', 'MinusOne', 'ModPow',
# 'Multiply', 'Negate', 'One', 'Parse', 'PopCount', 'Pow', 'ReferenceEquals',
# 'Remainder', 'RotateLeft', 'RotateRight', 'Sign', 'Subtract', 'ToBigInteger',
# 'ToBoolean', 'ToByte', 'ToByteArray', 'ToChar', 'ToDateTime', 'ToDecimal',
# 'ToDouble', 'ToInt16', 'ToInt32', 'ToInt64', 'ToSByte', 'ToSingle', 'ToString',
# 'ToType', 'ToUInt16', 'ToUInt32', 'ToUInt64', 'TrailingZeroCount',
# 'TryConvertFromChecked', 'TryConvertFromSaturating', 'TryConvertFromTruncating',
# 'TryConvertToChecked', 'TryConvertToSaturating', 'TryConvertToTruncating',
# 'TryFormat', 'TryParse', 'TryWriteBigEndian', 'TryWriteBytes',
# 'TryWriteLittleEndian', 'WriteBigEndian', 'WriteLittleEndian', 'Zero', 'bit_length',
# 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
データ型について
Python の基本的な組み込み型は、.NET のクラスで実装されています。
int
は要注意です。後で触れます。
Python | .NET |
---|---|
object |
System.Object |
int |
System.Int32 System.Numerics.BigInteger
|
float |
System.Double |
str |
System.String |
complex |
System.Numerics.Complex |
bool |
System.Boolean |
IronPython では、Python と .NET のクラスや属性を混用できてしまうので要注意です。
Python の str
型と String
(System.String) クラスを混用してみます。
# 例1
from System import String
str.Join(', ', map(chr, range(65, 70)))
# 'IronPython.Runtime.Map'
str.Join
(J は大文字)は .NET の String.Join
メソッドとして解釈されます。
第2引数は “map オブジェクトの文字列表現” (ToString
)になるため、想定外(?)の結果を返します。
# 例1の補足 (map オブジェクトの文字列表現)
map(chr, range(65, 70)).ToString()
# 'IronPython.Runtime.Map'
String.join
(j は小文字)は Python の str.join
と解釈されます。
# 例2
String.join(', ', map(chr, range(65, 70)))
# 'A, B, C, D, E'
おまけですが、String.Join
メソッドでもmap
をアンパックすれば要素を結合します。
String.Join(', ', *map(chr, range(65, 70)))
# 'A, B, C, D, E'
Int32
や Double
なども、int
,float
と解釈され、Python 的に振る舞います。
from System import Double, Int32
Int32(1.0) # int(1.0) と解釈
# 1
Int32('1') # int('1')
# 1
Double(1) # float(1)
# 1.0
Double('1') # float('1')
# 1.0
なお、下の例のように競合する記述は Python の解釈が優先されます。
ca = 'XYZ'.ToCharArray() # System.Array[Char] を作って...
print(ca)
# Array[Char](('X', 'Y', 'Z'))
System.String(ca) # System.String コンストラクタで 'XYZ' を期待しても...
# "Array[Char](('X', 'Y', 'Z'))" str 関数として機能する
IronPython では 型を[ ]
で囲みます。< >
ではありません。
文字列を作る代替手段はいくらでもあるので大した問題ではありません。
''.join(ca) # 'XYZ'
System.String.Concat(ca) # 'XYZ'
int
は要注意
下の例のように整数データは int
, Int32
, System.Numerics.BigInteger
(以下BigInteger
)それぞれの属性を持ちます。
j = 1234 # 整数型データ j に対して
j.bit_length() # Python のメソッド (int.bit_length) も
# 11
j.ToString('e3') # .NET のメソッド (Int32.ToString) も
# '1.234e+003'
j.IsEven # .NET のプロパティ (BigInteger.IsEven) も使える
# True
Python3 の仕様に合わせるため、int
は Int32
と BigInteger
の2つを使った特殊な実装です。
特に .NET API で整数を扱う場合は要注意です。
たとえば int
は .NET 目線で見ると「暗黙の型変換」が発生している場合があります。
big = 0x7fffffff
print(f'Value : {big} Type : {type(big)} <{big.GetType()}>')
# Value : 2147483647 Type : <class 'int'> <System.Int32>
big += 1
print(f'Value : {big} Type : {type(big)} <{big.GetType()}>')
# Value : 2147483648 Type : <class 'int'> <System.Numerics.BigInteger>
# Int32 の最大値を超えると、内部では BigInteger に変換されている
big -= 1
print(f'Value : {big} Type : {type(big)} <{big.GetType()}>')
# Value : 2147483647 Type : <class 'int'> <System.Numerics.BigInteger>
# Int32 には自動的には戻らない
詳細はこちらに記載されています。
コレクションについて
Python のリスト、タプル と .NET の System.Collections.Generic.List
や System.Array
などの主なコレクションは簡単に相互変換できます。
Python のコレクションを .NET のコレクションに変換
# Python のコレクションを .NET のコレクションに変換する
from System import Array
from System.Collections.Generic import List
py_list = [1, 2, 3]
py_tuple = ('A', 'B', 'C')
List[int](py_list)
# List[int]([1, 2, 3])
List[str](py_tuple)
# List[str](['A', 'B', 'C'])
Array[int](py_list)
# Array[int]((1, 2, 3))
Array[str](py_tuple)
# Array[str](('A', 'B', 'C'))
渡した要素の型が指定と異なる場合、通常はエラーになりますが、Array
は受け入れます。
# List コンストラクタは指定以外の型を拒否する
List[int]([1, 2.5, 3]) # エラー(float 要素が入っている)
# TypeError: Error in IEnumeratorOfTWrapper.Current. Could not cast: from System.Double to System.Numerics.BigInteger
List[float]([1, 2.5, 3]) # エラー(int 要素が入っている)
# TypeError: Error in IEnumeratorOfTWrapper.Current. Could not cast: from System.Int32 to System.Double
# 型が混在する場合は object にします
List[object]([1, 2.5, 3])
# List[object]([1, 2.5, 3])
# Array コンストラクタは型変換して受け入れる
Array[int]([1, 2.5, 3]) # 小数部は切り捨てられる
# Array[int]((1, 2, 3))
Array[float]([1, 2.5, 3])
# Array[float]((1.0, 2.5, 3.0))
Array
クラスのコンストラクタは言語(IronPython)側での実装なので型の緩さがあります。
また、Array
要素への代入でも同様に型変換されます。
.NET のコレクションを Python のコレクションに変換
list
,tuple
に渡します。
NET_List = List[str]() # str型で空の List を作成
NET_List.Add('A'); NET_List.Add('B'); NET_List.Add('C') # 3つの要素を追加
list(NET_List)
# ['A', 'B', 'C']
tuple(NET_List)
# ('A', 'B', 'C')
NET_Array = Array.CreateInstance(int, 3) # int型で要素数3の Array を作成
NET_Array[0], NET_Array[1], NET_Array[2] = 1, 2, 3 # 要素を代入
list(NET_Array)
# [1, 2, 3]
tuple(NET_Array)
# (1, 2, 3)
「int
問題」と回避策
通常は、Int32
と BigInteger
の壁を IronPython が処理するので、ユーザーは意識する必要がありません。
例えば List[int]
の実体として List[BigInteger]
が作られます。
そこに Int32
インスタンスを渡しても受け入れます。
NET_List = List[int]([1, 2])
print(f'Value : {NET_List} Type : {type(NET_List)} <{NET_List.GetType()}>')
# Value : List[int]([1, 2]) Type : <class 'List[int]'> <System.Collections.Generic.List`1[System.Numerics.BigInteger]>
# List[BigInteger] が作られていることがわかる
j1, j2 = 12, 123 # j1, j2 は Int32 のインスタンス
print(f'Value : {j1} Type : {type(j1)} <{j1.GetType()}>')
# Value : 12 Type : <class 'int'> <System.Int32>
print(f'Value : {j2} Type : {type(j2)} <{j2.GetType()}>')
# Value : 123 Type : <class 'int'> <System.Int32>
NET_List[1] = j1 # List[BigInteger] に対して
NET_List.Add(j2) # Int32 を問題なく代入・追加できる
NET_List
# List[int]([1, 12, 123])
ただし、受け入れない場合もあります。
NET_Array = Array[int]([1, 2, 3])
print(f'Value : {NET_Array} Type : {type(NET_Array)} <{NET_Array.GetType()}>')
# Value : Array[int]((1, 2, 3)) Type : <class 'Array[int]'> <System.Numerics.BigInteger[]>
NET_Array.SetValue(123, 2) # Int32 は受け付けない
# TypeError: Object cannot be stored in an array of this type.
NET_Array.SetValue((123).ToBigInteger(), 2) # 回避策
NET_Array
# Array[int]((1, 2, 123))
IronPython は回避策として ToBigInteger
メソッドを実装していますが、.NET API を使う場合は Int32
など、可能な限り .NET の整数型を明示する方が無難でしょう。
from System import Int32
NET_Array = Array[Int32]([1, 2, 3])
NET_Array.SetValue(123, 2) # 問題ない
NET_Array
# Array[Int32]((1, 2, 123))
コレクションの操作について
IronPython は List
や Array
にもスライスやアンパックが使えます。
Array
に対しては負のインデックスも許可しています。
いろいろ試しましたが、おおむね対応できています。
NET_List = List[str](['A', 'B', 'C'])
NET_Array = Array[Int32]([1, 2, 3])
NET_List[:2] # スライス
# List[str](['A', 'B'])
NET_List[::-1] # スライスによるリバース
# List[str](['C', 'B', 'A'])
print(*NET_List, sep=' - ') # アンパック
# A - B - C
[*map(lambda s: s.lower(), NET_List)] # map
# ['a', 'b', 'c']
[*zip(NET_List, NET_Array)] # zip
# [('A', 1), ('B', 2), ('C', 3)]
NET_Array[-1] # Array は負のインデックスも許可
# 3
NET_Array[-1:-3:-1] # スライス
# Array[int]((3, 2))
[i * 2 for i in NET_Array] # 内包表記
# [2, 4, 6]
NET_Array + NET_Array # シーケンス演算(結合)
# Array[int]((1, 2, 3, 1, 2, 3))
NET_Array * 3 # シーケンス演算(繰り返し)
# Array[int]((1, 2, 3, 1, 2, 3, 1, 2, 3))
それぞれのコレクションで全ての操作が等しくサポートされているわけではありません。
# Array ではできても List ではできないこと
NET_List[-1] # 負のインデックスはエラー
# ValueError: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
NET_List + NET_List # シーケンス演算も不可
# TypeError: unsupported operand type(s) for +: 'List[str]' and 'List[str]'
NET_List * 3
# TypeError: unsupported operand type(s) for *: 'List[str]' and 'int'
未解決の問題も残っています。
[*map(int, List[str](['1', '3', '5', '7', '9']))] # 問題なし
# [1, 3, 5, 7, 9]
[*map(int, Array[str](['1', '3', '5', '7', '9']))] # 問題発生...
# TypeError: int() takes at most 3 arguments (6 given)
この事象は報告済みですが、問題の根は深いようです。
ImportError
について
一部のクラスで import
できないことがありますが、これは IronPython ではよくある事象です。
clr
モジュールをインポートして、アセンブリへの参照設定 clr.AddReference(アセンブリ)
で解決します。
アセンブリは .NET API ブラウザで確認できます。
LinkedList
の場合は System.Collections.dll が参照先ですが ".dll" は外します。
.NETCore と .NETFramework とでエラーになるクラスが異なる場合もあります。
また、参照するアセンブリも一部で異なります。
【.NETFramework では hashSet
がエラーになる】
LINQ の利用
以下3行で LINQ の拡張メソッドが使えます。
import System, clr
clr.AddReference('System.Core')
clr.ImportExtensions(System.Linq)
拡張メソッドはリストやタプルに対しても機能します。
Min
メソッド と Max
メソッド
普通に使えるのですが...
[2, 5, 1, 4].Min() # list
# 1
(9, -5, 0, 4).Max() # tuple
# 9
「int
は要注意」の具体例
Int32
と BigInteger
の混在によるトラブル例です。
# 全要素が BigInteger なら問題ないが
[4000000000, 5000000000, 6000000000].Max()
# 6000000000
# Int32 と BigInteger が混在するとエラー
[1000000000, 2000000000, 3000000000].Max()
# ValueError: The parameter must be a BigInteger. (Parameter 'obj')
[3000000000, 2000000000, 1000000000].Max()
# ValueError: Object must be of type Int32.
int
型の明示で回避できます。
# 解決策
[1000000000, 2000000000, 3000000000].Max[int]()
# 3000000000
[3000000000, 2000000000, 1000000000].Max[int]()
# 3000000000
文字列では min
, max
関数と挙動が異なる
文字列については min
, max
関数と異なる結果を返します。
LINQ の Min
や Max
メソッドは全角文字が混在しても辞書順です。
# 'A' だけ全角文字
# min 関数 や max 関数はコードポイント順
min(['A', 'B', 'c'])
# 'B'
max(['A', 'B', 'c'])
# 'A'
# Min() や Max() は辞書順
['A', 'B', 'c'].Min()
# 'A'
['A', 'B', 'c'].Max()
# 'c'
変換関数の使用
変換関数を使う場合は System.Func
を介します。
lambda
式も使えます。
from System import Func
(-9, 5, 2, -4).Max(Func[int, int](abs))
# 9
(-9, 5, 2, -4).Max[int](Func[int, float](lambda i: 1 / i)) # Max[int] の明示が必要
# 0.5
.NET6 で追加された MinBy
や MaxBy
メソッドは System.Func
不要です。
(-9, 5, 2, -4).MaxBy(lambda i: abs(i))
# -9
(-9, 5, 2, -4).MaxBy(lambda i: 1 / i)
# 2
Sum
メソッド と Average
メソッド
次の2点に注意します。
-
AsEnumerable[T]()
やCast[T]()
を通す - 整数は
int
ではなくSystem.Int32
など、.NETネイティブな整数型にする
# 失敗例
(-9, 5, 2, -4).Sum()
# TypeError: Sum() takes exactly 1 argument (0 given)
(-9, 5, 2, -4).AsEnumerable[int]().Sum()
# TypeError: Sum() takes exactly 1 argument (0 given)
# 成功例
from System import Int32
(-9, 5, 2, -4).AsEnumerable[Int32]().Sum() # -6 AsEnumerable または
(-9, 5, 2, -4).Cast[Int32]().Sum() # -6 Cast を使う
変換関数の使用
ここでも System.Func
を介します。
Func
を使うときは AsEnumerable
や Cast
は省略できます。
2乗和と2乗平均の例です。
(-9, 5, 2, -4).Sum(Func[int, Int32](lambda i: i * i))
# 126
(-9, 5, 2, -4).Average(Func[int, Int32](lambda i: i * i))
# 31.5
その他応用例を示しておきます。
# int と float の混在
[7.6, 2.5, -4, -1.1, 6].Average(Func[object, float](float))
# 2.2000000000000002
# 誤差を嫌う場合は Decimal で
from System import Decimal
[7.6, 2.5, -4, -1.1, 6].Average(Func[object, Decimal](Decimal))
# 2.2
# OfType[T] の使用
[7.6, 2.5, -4, -1.1, 6].OfType[float]().Average() # float だけの平均
# 3.0
[7.6, 2.5, -4, -1.1, 6].OfType[Int32]().Average() # Int32 だけの平均
# 1.0
# None が存在する場合は System.Nullable を使う
from System import Int32, Nullable
[1, None, 2, None, 3].AsEnumerable[Nullable[Int32]]().Average()
# 2.0
その他あれこれ
IEnumerable
もアンパックできる
LINQ では多くのメソッドが IEnumerable
を返しますが、こちらもアンパックできます。
# dict を SelectMany に渡してリストに展開
cities = {'新潟県': ('新潟市', '長岡市', '上越市'), '宮城県': ('仙台市', '石巻市')}
[*cities.SelectMany(lambda pref: cities[pref], lambda pref, city: f'{pref} {city}')]
# ['宮城県 仙台市', '宮城県 石巻市', '新潟県 新潟市', '新潟県 長岡市', '新潟県 上越市']
メソッドチェーン
見やすくできます。
# 上の例を print で出力
(cities
.SelectMany(lambda pref: cities[pref],
lambda pref, city: f'{pref} {city}')
.ToList()
.ForEach(print))
# 宮城県 仙台市
# 宮城県 石巻市
# 新潟県 新潟市
# 新潟県 長岡市
# 新潟県 上越市
GroupBy
OrderBy
の使用例
LINQ の GroupBy
は itertools.groupby
と異なり事前のソートは不要で、元データの順番を維持します。
# 40個のランダムな整数を用意(最小0 最大99)
from random import randint
data = [randint(0, 99) for _ in range(40)]
# 値を10刻みでグループ分け
groups = data.GroupBy(lambda i: i // 10).OrderBy(lambda group: group.Key)
# データと結果を表示
from pprint import pprint
pprint(data, width=40, compact=True)
# [2, 76, 37, 8, 22, 66, 43, 18, 19, 4,
# 39, 54, 42, 61, 45, 78, 98, 44, 12, 46,
# 45, 0, 28, 40, 99, 56, 62, 12, 47, 25,
# 87, 46, 76, 0, 61, 7, 2, 53, 17, 72]
for group in groups:
print(f'{group.Key * 10:2} -{group.Key * 10 + 9:3} : {[*group]}')
# 0 - 9 : [2, 8, 4, 0, 0, 7, 2]
# 10 - 19 : [18, 19, 12, 12, 17]
# 20 - 29 : [22, 28, 25]
# 30 - 39 : [37, 39]
# 40 - 49 : [43, 42, 45, 44, 46, 45, 40, 47, 46]
# 50 - 59 : [54, 56, 53]
# 60 - 69 : [66, 61, 62, 61]
# 70 - 79 : [76, 78, 76, 72]
# 80 - 89 : [87]
# 90 - 99 : [98, 99]
map, zip との組み合わせ
# わかりにくいコレよりも...
[*zip(*[iter(range(15))] * 5)]
# [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14)]
# Chunk がわかりやすい
[*map(tuple, range(15).Chunk(5))]
# [(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14)]
# zip(*) を使って転置行列を作成
[*zip(*range(15).Chunk(5))]
# [(0, 5, 10), (1, 6, 11), (2, 7, 12), (3, 8, 13), (4, 9, 14)]
参照渡しについて
.NET API で参照渡しを必要とする場合があります。
たとえば、Int32.TryParse
メソッドの引数は「変換したい文字列」と「変換結果を受け取る変数の参照」です。
ただし、IronPython は TryParse
などに「暗黙的に結果を受け取る」手段を用意しているので、通常は参照渡しを回避できます。
Int32.TryParse('123') # TryParse は「変換の成否」と「変換結果」をタプルで返す
# (True, 123)
Int32.TryParse('12-3') # 変換できない場合
# (False, 0)
参考までに、参照渡しの手順も示します。
i_ref = clr.Reference[Int32]() # 変換結果を受け取る変数(の参照)を作成
Int32.TryParse('123', i_ref) # TryParse は成否を bool で返す
# True
i_ref.Value # Value プロパティで変換結果を得る
# 123
Int32.TryParse('12-3', i_ref) # 変換できない文字列を渡す
# False
i_ref.Value # 変換に失敗すると 0
# 0
ファイル入出力について
単純なファイル出力であれば、with open('file', 'w') as f:
よりも WriteAllLines
が簡潔で使いやすいでしょう。リストのまま渡すこともできます。
from System.IO.File import ReadAllLines, WriteAllLines
# リストをファイルに書き込む
dec_hex = ['10進\t2進'] + [f'{i:2}\t{i.ToString("B4")}' for i in range(16)]
WriteAllLines('Dec-Hex.txt', dec_hex)
【結果】
ファイルからの入力例として、ReadAllLines
を使ってファイルの先頭5行を表示します。
# Array.ForEach には Action で渡す
from System import Array, Action
# ファイルの先頭5行を表示
Array.ForEach(ReadAllLines('Dec-Hex.txt')[:5], Action[str](print))
# 10進 2進
# 0 0000
# 1 0001
# 2 0010
# 3 0011
日付の処理について
記事の趣旨から逸脱して .NET API の紹介ぽくなりますが、備忘録としての観点で書いておきます。
和暦の処理に絞ったメモです。こちらの記事を参考にさせていただきました。
和暦から西暦へ
こちらは非常に簡単です。
# 和暦を西暦に変換する
from System import DateOnly
DateOnly.Parse('R6.1.1').ToLongDateString() # 元号の略号(R)もO.K.
# '2024年1月1日'
DateOnly.Parse('令和6年1月1日').ToLongDateString() # 漢字表記もO.K.
# '2024年1月1日'
DateOnly.Parse('S100.1.1').ToLongDateString() # 来年は昭和100年
# '2025年1月1日'
西暦から和暦へ
カルチャを設定して
from System.Globalization import CultureInfo, JapaneseCalendar
ci = CultureInfo('ja-JP')
ci.DateTimeFormat.Calendar = JapaneseCalendar()
カルチャ付き ToString
で和暦を取得できます。
DateOnly(2024, 1, 1).ToString('gy年M月d日', ci)
# '令和6年1月1日'
元年表記にも対応します。
d = DateOnly(2019, 4, 30)
d.ToString('gy年M月d日', ci) # 改元前日
# '平成31年4月30日'
d.AddDays(1).ToString('gy年M月d日', ci) # 改元初日
# '令和元年5月1日'
補足
和暦を Parse
する場合、カルチャを指定すると「元年」も受け付けます。
DateOnly.Parse('令和1年5月1日').ToLongDateString()
# '2019年5月1日'
# カルチャを指定しない場合「元年」はエラー
DateOnly.Parse('令和元年5月1日').ToLongDateString()
# SystemError: String '令和元年5月1日' was not recognized as a valid DateOnly.
# カルチャを指定するとO.K.
DateOnly.Parse('令和元年5月1日', ci).ToLongDateString()
# '2019年5月1日'
まとめ
- スクリプトの先頭に最低限書いておくもの
import System, clr
from System import Int32, String
- コレクションを使うために入れておきたいもの
from System import Array, Action, Func
from System.Collections.Generic import List
clr.AddReference('System.Core')
clr.ImportExtensions(System.Linq)
- ファイル処理をする場合入れておきたいもの
from System.IO.File import ReadAllLines, WriteAllLines
- 可能な限り
int
はInt32
にする
参考
本家 Python との違いもありますので、こちらもご確認ください。