2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonメモ

Last updated at Posted at 2021-12-26

最近はPythonとTypeScriptを交互に使うことが多く、頭の中で両言語がごっちゃになっているので、本記事でPythonについてメモします。
情報の網羅性はありません。
気づいた時点で随時追加します。

ループ

ループ中でbreak、continueが使える。

while文

else節は、whileでbreakが実行されなかったときのみ実行される。


while :
    スイート
else:
    スイート

for文

while文同様、else節が書ける。

様々な書き方:


for i in range(n):

for i in range(a, b):

for i in range(a, b, step):

for i in list(range(1, 8)) + list(range(9, 13))

for i, ch in enumerate(s):

# 1からカウント
for i, ch in enumerate(s, 1):

for ch in s:

# カウンタ用変数を使わないなら、_を使うと良い。
for _ in range(n):

データ型

型を調べるには

type(式)
※ 式には型と値がある。

NoneType型

  • 他言語のNULLに近いのが、NonType型のNone

if x is None:

if x is not None:

bool型

  • False(内部的に0)とTrue(内部的に1)。先頭が大文字。
  • 偽とみなされるのは、False、0、0.0、None、空文字''、空リスト[]、空タプル()、空辞書{}等。これら以外とTrueは真とみなされる。

数値型

  • int : 整数型(桁数に制限なし)
  • float : 浮動小数点型(倍精度)
  • お金の計算には、decimalモジュールのDecimal型を使う。

数値リテラル

途中の任意の場所に_を入れられる。


10_000_000_000

算術演算


# 除算演算子(演算は実数で行われる)
x / y

# 切捨て除算演算子(小数部を切り捨てて整数値を生成)
x // y
  • ++、--はないが、+=、-=等はある。

文字列型(str型)


# 文字数
len(s)

# 部分文字列
s[begin:end]

# 反転
s[::-1]
reversed(s)

# 文字列が別の文字列に含まれているか
if pattern [not] in text:
  • 文字列結合は、+でつなぐよりもjoinメソッドを使った方が高速。

f文字列


a, b, c = 1, 2, 3
print(f"{a} + {b} + {c} = {a + b + c}")

ヒアドキュメント

ヒアドキュメントは'''または"""で囲み、ソースコードでインデントしたら textwrap.dedent() で余計な空白等を削除できる。


import textwrap

if True:
    s = '''
        SELECT
            *
        FROM
            dual;
    '''

    print("----")
    print(s)
    print("----")
    print(textwrap.dedent(s)[1:-1])
    print("----")

実行結果


----

        SELECT
            *
        FROM
            dual;
    
----
SELECT
    *
FROM
    dual;
----

バイト列型(bytes型)

バイナリデータ。


b"..."

リスト型(list型)


# リスト表記演算子
[ ...]

# 反転
list(reversed(x))
  • Pythonのリストは、連結リストではなく、配列である。

  以下の本の p.173 に、そう説明されている。

  新・明解Python入門 柴田望洋/著 SBクリエイティブ 20190524
  https://www.amazon.co.jp/dp/4815601526

  ※ teratailで関連質問している方がいました。
  https://teratail.com/questions/113885

リスト内包表記


# [ 式 for 要素 in イテラブル ]
[ n - 1 for n in range(1, 8) ]

# [ 式 for 要素 in イテラブル if 判定式 ]
[ n for n in range(1, 8) if n % 2 == 0 ]

タプル型(tuple型)


# 式結合演算子(タプル表記演算子)
( ...)

# 複数の変数へ異なる値を一括代入
x, y, z = 1, 2, 3
  • イミュータブルなのでリストより低コスト
  • ()は省略可

辞書型(dict型)


# 辞書表記演算子
{ キー :  }

x = {}

# in演算子で調べられるのはキーで、値ではない。
if key in dic:

for key in dic.keys():

for key, value in dic.items():
  • キーはイミュータブルである必要がある。
  • キーが存在しないとき、値を取り出そうとしたら KeyError例外が発生する。

辞書内包表記


{  :  for 要素 in イテラブル }

集合型(set型)


# 集合表記演算子
{ ...}

x = set()

# ソート
sorted(x)

集合内包表記


{  for 要素 in イテラブル }

言語について、その他

  • 行の終端の\で次の行に継続できる。
  • カッコ記号()、[]、{}の中では自由に改行できる。

変数

  • Pythonの変数は、値を格納する箱ではなく、オブジェクトを参照するもの(オブジェクトに結びつけられた名前)である。

    以下の本の p.114 に、そう説明されている。

    新・明解Python入門 柴田望洋/著 SBクリエイティブ 20190524
    https://www.amazon.co.jp/dp/4815601526

  ※ 関数型言語の名前束縛と同じかな。束縛からの解放がdelか。

  • ミュータブルな型(値が変更可能):リスト、辞書、集合など
  • イミュータブルな型(値が変更不能):数値、文字列、タプルなど

三項演算子(条件演算子)


x if y else z

何も行わない文


pass

文書化文字列


def foo(n: int, s: str) -> None:
    """sをn回表示

    仮引数:
        n -- 表示する文字列の個数
        s -- 表示する文字列
    返却値:
        無し

    """
    for _ in range(n):
        print(s)


# 関数fooのドキュメントを表示する
help(foo)

# アノテーションを表示
print(foo.__annotations__)

# 文書化文字列を表示
print(foo.__doc__)

global文、nonlocal文


n = 1

def foo():
    global n # この文がないと、次の行のnがローカル変数になる
    n = 2

def foo():
    n = 1
    def bar():
        nonlocal n # この文がないと、次の行のnがbar()のローカル変数になる
        n = 2

ラムダ式

文ではなく式として関数を実現する。

lambda 仮引数並び : 返却値


foo = lambda x, y: x + y

print((lambda x, y: x + y)(1, 2))

カリー化

参考サイト:
https://kk6.hateblo.jp/entry/20110905/1315221175

モジュール自作


if __name__ == "__main__":
    テストデバッグ用のコード

モジュール利用


# モジュール名.オブジェクト名でアクセス
import モジュール名

# 別名.オブジェクト名でアクセス
import モジュール名 as 別名

# 単純名でアクセス。多用すべきでない
from モジュール名 import 名前1, 名前2, ...

# 原則として使うべきでない
from モジュール名 import *

# 名前に別名を与える
from モジュール名 import 名前 as 別名
  • ディレクトリをPYTHONPATHに設定する。

例外処理


class MyException(Exception):
    """マイ例外"""
    pass

try:
    raise MyException
except MyException as e:
    print(traceback.format_exc())    # トレースバックを表示
except (例外1, 例外2) as e:    # 複数の例外をタプルとして書ける
    スイート
except Exception as e:    # 事実上の最上位クラス
    スイート
except:    # 全ての例外をキャッチ。ただしExceptionで捕捉すべき。
    スイート
else:    # 省略可能。例外が捕捉されなかった場合に行う正常処理。
    スイート
finally:    # 省略可能。例外発生の有無に関わらず行う後処理。
    スイート

try:
    スイート
finally:
    スイート

Tips

ファイル処理

テキストファイルを1行ずつ読み書きするサンプル


with open("input.txt", mode="r", encoding="utf-8") as fi, \
     open("output.txt", mode="w", encoding="utf-8") as fo:
    for line in fi:    # fiはイテラブルオブジェクト
        # lineには最後の改行文字も含まれている
        fo.write(line)

sleep


import time

time.sleep()

ロギング

参考サイト:
https://qiita.com/knknkn1162/items/87b1153c212b27bd52b4

以下、コード例:

モジュール自作側


import logging

logger = logging.getLogger(__name__)

...

# コード中のログ出力したい場所に埋め込む
logger.debug(文字列)
logger.info(文字列)

モジュール利用側


import logging
from pathlib import Path
import os
import datetime


def make_logfile_path(file: str) -> str:
    """
    ログファイル名の作成

    Parameters
    ----------
    file: str
        __file__が渡されることを想定

    Returns
    -------
    anonymous: str
        フルパスのログファイル名
    """
    log_dir = Path.cwd() / "log"

    # ディレクトリがなければ作成
    log_dir.mkdir(parents=True, exist_ok=True)

    return log_dir / os.path.basename(os.path.splitext(file)[0] + datetime.datetime.today().strftime("_%Y%m%d_%H%M%S.log"))


def get_logger(name: str, filepath: str):
    """
    ロガーの取得

    Parameters
    ----------
    name: str
        __name__が渡されることを想定
    filepath: str
        make_logfile_path(__file__)の戻り値が渡されることを想定

    Returns
    -------
    anonymous
        ログをコンソールに送るハンドラ
    anonymous
        ロガー
    """
    # 設定例
    LOG_LEVEL_FILE = logging.DEBUG      # ログファイルには詳細に出力
    LOG_LEVEL_CONSOLE = logging.INFO    # コンソールには簡便に出力

    # フォーマットを指定 (https://docs.python.jp/3/library/logging.html#logrecord-attributes)
    _detail_formatting = "\n%(asctime)s %(levelname)-8s [%(module)s#%(funcName)s %(lineno)d]\n%(message)s"

    logging.basicConfig(
        level=LOG_LEVEL_FILE,
        format=_detail_formatting,
        filename=filepath
    )

    # ログをコンソールに送るハンドラconsoleを作成
    console = logging.StreamHandler()
    console.setLevel(LOG_LEVEL_CONSOLE)
    console_formatter = logging.Formatter(_detail_formatting)
    console.setFormatter(console_formatter)

    # ロガーを取得し、consoleハンドラを追加する
    logger = logging.getLogger(name)
    logger.addHandler(console)
    return console, logger

###################################################################

console, logger = get_logger(__name__, make_logfile_path(__file__))

def main():
    logging.getLogger(使うモジュール名1).addHandler(console)
    logging.getLogger(使うモジュール名2).addHandler(console)

    ...

    # コード中のログ出力したい場所に埋め込む
    logger.debug(文字列)
    logger.info(文字列)

pytest

PyCharmでpytestを使う設定:
https://pleiades.io/help/pycharm/pytest.html

  • 以前使っていた各種ファイル
tests/pytest.ini

[pytest]
#addopts = -rsxX -l --tb=short --strict    -v --runxfail
addopts = -rsxX -l --strict    -v -x --capture=no
xfail_strict = true
tests/conftest.py

import pytest
import time
import sys
import os

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from src import common
from tests import tescommon


console, logger = common.get_logger(__name__, tescommon.stub_make_logfile_path("test"))


@pytest.fixture(autouse=True, scope='session')
def session_scope():
    """Report test durations after each session."""
    start = time.time()
    logger.info(f"pytest started : {time.strftime('%d %b %X', time.localtime(start))}")
    yield
    stop = time.time()
    delta = stop - start
    logger.info(f"pytest finished : {time.strftime('%d %b %X', time.localtime(stop))}")
    logger.info("pytest session duration : {:0.3} seconds".format(delta))


@pytest.fixture(autouse=True)
def function_scope():
    """Report test durations after each function."""
    start = time.time()
    yield
    stop = time.time()
    delta = stop - start
    logger.info("pytest function duration : {:0.3} seconds".format(delta))


@pytest.fixture(scope="session")
def pg_server_conn():
    # DB接続 & テスト呼び出し
    with common.connect_pg_server() as conn:
        yield conn


@pytest.fixture(scope="session")
def sqlite_conn():
    if common.is_in_docker_container():
        yield None
    else:
        # DB接続 & テスト呼び出し
        with common.connect_sqlite() as conn:
            yield conn
2
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?