Help us understand the problem. What is going on with this article?

あまり知られていないPythonの言語仕様(Python3.4以降対応)

More than 5 years have passed since last update.

はじめに

Pythonの言語仕様であまり知られていない(と勝手に思っている)ものをまとめてみる。

初級・中級・上級の分類は適当。

他にもあれば追記していく。

初級編

複素数リテラル

複素数の演算が標準でできるようになっている。
添字はiではなくjを使う。

>>> c1 = 1 + 1j
>>> c2 = 1 - 2j
>>> c1 + c2
(2-1j)
>>> c1 * c2
(3-1j)
>>> c1 / c2
(-0.2+0.6j)

複数のfor..inを含む内包表記

内包表記の中にfor..inを複数書ける。

>>> a = range(3)
>>> b = range(4)
>>> [x + y for x in a for y in b]
[0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5]

n個おきのスライス

次のように書くことでリストなどの要素をn個おきに取り出せる。

>>> a = list(range(20))
>>> a[::2]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

スライスによるリストのコピー

スライス構文にインデックスを渡さなければリストのコピーを作れる。

>>> a = range(10)
>>> b = a
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b is a # bとaは同一のオブジェクト
True
>>> c = a[:]
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> c is a # bとaは別個のオブジェクト
False

中級編

Ellipsis

... が「省略」を表すオブジェクトとして扱われる。
詳しくはこちらを参照。

>>> ...
Ellipsis
>>> bool(...)
True

キーワード限定引数

関数定義中で *, を書くと、以降の引数を必ずキーワード引数として呼び出さなければならないようにできる。

>>> def f(a, *, b):
...     pass
...
>>> f(1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'b'
>>> f(1,2)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1,b=2)
>>>

関数アノテーション

関数の引数と返り値にアノテーションをつけられる。
ドキュメントなどに使うためのアノテーションなので、違う型のオブジェクトが与えられてもエラーにはならない。

>>> def f(x : int, y : int) -> int:
...     return x + y
...
>>> f(2, 3)
5
>>> f('hoge', 'fuga') # エラーにはならない
'hogefuga'

global

global によって、どのスコープからでもグローバル変数を実行時に定義できる。

>>> def f():
...     global a
...     a = 1
...
>>> a # ここではaは未定義
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'a' is not defined
>>> f() # fの呼び出しによりグローバル変数aが定義される
>>> a
1

nonlocal

nonlocal によって、ひとつ外側のスコープに属する変数への代入が可能となる。
クロージャが簡単に作れる。

>>> def make_counter():
...     count = 0
...
...     def counter():
...         nonlocal count
...         count += 1
...         return count
...
...     return counter
...
>>> c = make_counter()
>>> c(), c(), c()
(1, 2, 3)

上級編

引数付きデコレータ

「『関数を受け取って関数を返す関数』を返す関数」を書くことで引数付きデコレータが作れる。
Flaskの @route('/') などはこれを用いて実装されていると思われる。

>>> def greet(before, after):
...      def decorator(func):
...          def wrapper(*args, **kwargs):
...              print(before)
...              func(*args, **kwargs)
...              print(after)
...          return wrapper
...      return decorator
...
>>> @greet('Hi.', 'Bye.')
... def introduce(name):
...     print('I am ' + name + '.')
...
>>> introduce('yubessy')
Hi.
I am yubessy.
Bye.

クラスデコレータ

クラスをラッピングするデコレータを書くことができる。
以下は簡易シングルトンの実装例。

>>> def singleton(cls):
...   instances = {}
...   def getinstance(*args, **kwargs):
...     if cls not in instances:
...         instances[cls] = cls(*args, **kwargs)
...     return instances[cls]
...   return getinstance
...
>>> @singleton
... class C(object):
...   pass
...
>>> c1 = C()
>>> c2 = C()
>>> c1 is c2
True

yield from

他のイテレータから値を返すジェネレータを作れる。

>>> def g():
...     yield from range(5)
...     yield from range(5, 10)
...
>>> [i for i in g()]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

raise from

例外を連鎖する際に、送出元の例外を保持する。

>>> try:
...     raise Exception('e1') from Exception('e2')
... except Exception as e:
...     print(e.__cause__)
...
e2

参考

livesense
求人情報サイト「マッハバイト」「転職ナビ」「転職会議」「転職ドラフト」および不動産情報サイト「IESHIL」などを開発・運営しています。
https://www.livesense.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away