1
0

More than 3 years have passed since last update.

Python3.8の新機能を一部触ってみた①

Last updated at Posted at 2020-03-06

はじめに

弱々Pythonエンジニアがpython3.8の新機能を一部触ってみました。
よくわからないものはすっ飛ばしてます(ビルドだプロファイルだなんだのは飛ばしてます)。
詳しくは公式ドキュメント参照

セイウチ演算子

大きな構文の一部として、変数に値を割り当てる新しい構文 := が追加されました。 この構文は セイウチの目と牙 に似ているため、「セイウチ演算子」の愛称で知られています。

image.png
セイウチ演算子カワイイ

array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# python3.8以前
# n = len(array) > 10
# if n:
#     print(f"List is too long ({n} elements, expected <= 10)")

# python3.8
if n := len(array) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

出力結果

List is too long (True elements, expected <= 10)

判定と一緒に変数宣言できる感じ??

while文や内包表記でも使用できるので詳しくは公式ドキュメント参照

位置専用引数

関数の引数が位置引数として指定されねばならずキーワード引数としては指定できないことを表す、新しい構文 / を追加しました。この構文は、help() で Larry Hasting の Argument Clinic でアノテートした C関数を表示したときと同じ表記です。

正しい関数呼び出し

def profile(first_name, last_name, /, gender, age, *, zip_code, address):
    print(f'\
        姓:{first_name}\n\
        名:{last_name}\n\
        性:{gender}\n\
        歳:{age}\n\
        〒:{zip_code}\n\
        住:{address}')

profile('鈴木', '一郎', '男', 99, zip_code='000-0000', address='宇宙')  # OK
profile('鈴木', '一郎', '男', age=99, zip_code='000-0000', address='宇宙')  # OK
profile('鈴木', '一郎', gender='男', age=99, zip_code='000-0000', address='宇宙')  # OK

引数は左から順に、
位置引数:first_name, last_name
位置引数でもあり、キーワード引数でもある:gender, age
キーワード引数:zip_code, address

誤った関数呼び出し

profile('鈴木', '一郎', gender='男', 99, zip_code='000-0000', address='宇宙')  # SyntaxError: positional argument follows keyword argument
profile('鈴木', '一郎', age=99, '男', zip_code='000-0000', address='宇宙')  # SyntaxError: positional argument follows keyword argument
profile('鈴木', '一郎', '男', 99, '000-0000', address='宇宙')  # TypeError: profile() takes 4 positional arguments but 5 positional arguments (and 1 keyword-only argument) were given
profile('鈴木', '一郎', '男', 99, zip_code='000-0000', '宇宙')  # SyntaxError: positional argument follows keyword argument

キーワード引数としての利用を排除

/より前の引数は位置引数になるので、python3.8以前ではできていた以下のような呼び出し方を排除できるようになりました。
位置引数として強制させることができるので遠慮なく引数名を変更できますね!!!

# python3.8以前は位置引数としても、キーワード引数としても利用できた。
def profile(first_name, last_name):
    print(f'{first_name} {last_name}')
profile2(first_name='吉田', last_name='花子')  # 吉田 花子
...
..
.
# python3.8位置専用引数 / を使用
def profile(first_name, last_name, /):
    print(f'{first_name} {last_name}')
profile2(first_name='吉田', last_name='花子')  # TypeError: profile2() got some positional-only arguments passed as keyword arguments: 'first_name, last_name'

任意のキーワード引数を受け取るこんな書き方もできるよ。

def profile(first_name, last_name, /, **kwargs):
    print(f'{first_name} {last_name} {kwargs}')
profile('吉田', '花子', first_name='鈴木', last_name='一郎')  # 吉田 花子 {'first_name': '鈴木', 'last_name': '一郎'}

これにより、任意のキーワード引数を受け取る関数やメソッドを定義するのが、ぐんとシンプルになります。

と公式にありますが、弱々エンジニアなので旨味がわかってません。

キャッシュファイルを別の場所に格納する機能

暗黙のバイトコードキャッシュは、デフォルトでは各ソースコードのディレクトリ内の pycache サブディレクトリを使用しますが、新たに追加された環境変数 PYTHONPYCACHEPREFIX (またはコマンドラインオプション -X pycache_prefix) を指定すると、ソースコードと分離されたディレクトリツリーに格納されるようになります。

キャッシュの場所は sys.pycache_prefix で参照できます(pycache を使用する場合は:const:None になります)。

うまく検証できなかったので、とりあえずスルー。。。

フォーマット済み文字列リテラル(f-string)で「=」指定子が有効になった

string = 'エフストリング'

# python3.8.0 以前
print(f'{string}')  # エフストリング

# python3.8.0
print(f'{string=}')  # string='エフストリング'

デバッグで役立ちそう(小並感)

dict と dictview は、reversed() を使って逆順でイテレートすることが可能に

python3.7までは、dictreversedで逆順にしようとするとTypeError: 'dict' object is not reversibleになってしまいます。

# python3.8.0 以前
dictionary = {'a': 1, 'b': 2, 'c': 3}

for d in reversed(dictionary):
    print(d)

>> TypeError: 'dict' object is not reversible

python3.8からはそれが可能になりました!

# python3.8.0 以前
dictionary = {'a': 1, 'b': 2, 'c': 3}

for d in reversed(dictionary):
    print(d)

>> c
>> b
>> a

collections.namedtuple() の _asdict() メソッドがdictを返すようになった

そもそもnamedtupleって何ぞやって方はこちらにわかりやすく解説があります!!!

python3.8以前はOrderedDictを返すようになっていました。

import collections
Human = collections.namedtuple('Human', ['first_name', 'last_name', 'age'])
human = Human('yamada', 'taro', 25)
print(human._asdict())

>> OrderedDict([('first_name', 'yamada'), ('last_name', 'taro'), ('age', 25)])

python3.8ではDictを返してくれるようになりました!

import collections
from collections import OrderedDict

Human = collections.namedtuple('Human', ['first_name', 'last_name', 'age'])
human = Human('yamada', 'taro', 25)
print(human._asdict())
# print(OrderedDict(human._asdict()))  # 3.8でもOrderedDict特有の機能を使いたい場合はキャストして使用することが推奨されています。

>> {'first_name': 'yamada', 'last_name': 'taro', 'age': 25}

csv.DictReaderもdictを返すようになった

この変更によって、順序を保ちながら、より高速にかつメモリの使用量を減らして実行できます。

らしいです。やったぜ。

datetimeモジュールに2つメソッドが追加

ISO の規定に沿った年、週番号、曜日によって、date や datetime オブジェクトを作成するメソッド datetime.date.fromisocalendar() と datetime.datetime.fromisocalendar() が追加されました; これは、各クラスの isocalendar メソッドの逆を行うものです。

なんのこっちゃ。
出力してみた。

from datetime import datetime

date = datetime.now()  # 2020-03-06(時分秒省略)
print(date.isocalendar())  # (2020, 10, 5)
print(date.fromisocalendar(2020, 4, 1))  # 2020-01-20 00:00:00
print(datetime.fromisocalendar(2020, 4, 1))  # 2020-01-20 00:00:00

まずは既存のisocalendar()

2020-03-06は2020年 の 10週目 金(5)曜日
image.png

3.8で追加されたfromisocalendar

print(date.fromisocalendar(2020, 4, 1)) # 2020-01-20 00:00:00
引数の詳細は左から順に西暦, , 曜日

``2020年 の 4週目 月(1)曜日

image.png

①は一旦ここまで

疲れたのでこれにて終了。
②もそのうち出します。(自己満)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0