9cubed
ブログ | Tailwind | Vite | Python | Node.js | Linux | PowerShell | その他 | 将棋ウォーズ | 歌の練習
< 前の記事

外部ファイルのインポート

次の記事 >

音声から文字起こし

Python

[Python]ぼーっとPython のコードを眺める

公開日:2025-12-14
更新日:2025-12-14

1. 概要

ぼーっとPython のコードを眺めて、気になったところを確認します。

2. 親パッケージのインポート

見たコード
コード
from .apibase import (
    BINARY as BINARY,
    DATETIME as DATETIME,
    NUMBER as NUMBER,
    ROWID as ROWID
)

import は複数インポートの指定ができる。
改行しているため、( ) で囲っている。1行で書く場合は不要。

. は、相対パスの ./ のようなもので、現在のパッケージを表す

コード
from .   import pkg  #    同じパッケージの pkg をインポート
from ..  import pkg  # 1つ上のパッケージの pkg をインポート
from ... import pkg  # 2つ上のパッケージの pkg をインポート

注意:プロジェクトのフォルダはパッケージではないため、「.」や「..」でプロジェクトのフォルダを指すことはできない。

3. アンパック、スライス

見たコード
コード
return Date(*time.gmtime(ticks)[:3])
time.gmtime(ticks) は、time.struct_time と言う型の値を返してくる。

実行結果
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=1, tm_sec=40, tm_wday=3, tm_yday=1, tm_isdst=0)
これは __getitem__ を実装しているため、time.gmtime(ticks)[:3] のようにスライスで使用できる。

実行結果
(1970, 1, 1)
先頭に * がついているので、このタプルを展開して、Date() に3つの引数を渡している。

4. Union型の型ヒント、位置専用引数

見たコード
コード
def gmtime(seconds: float | None = None, /) -> struct_time: ...

seconds: float | None

Union型の型ヒント。seconds は、float または None の値が入る。

= None

デフォルト値

引数の最後の /

位置専用引数を示します。
add(v1 = 1, v2 = 2) のように、引数名を指定して渡すとエラーになります。

...

メソッドのヘッダのみでここには実装がないと言う意味。

上記を使った使用例

コード
def add(v1: int | float = 0, v2: int | float = 0, /) -> int | float:
    return v1 + v2

print(add(1, 2.2)) # 3.2
引数に int と float のどちらを指定しても型チェッカーでエラーが出ない。

5. @final

クラスの継承の禁止を意味する。クラスを継承すると型チェッカーでエラーが出る。
コード
from typing import final

@final
class Test:
    pass

class TestEx(Test):  # 型チェッカーでエラーが出る
    pass

6. ジェネリクス

見たコード
コード
class struct_time(structseq[Any | int], _TimeTuple):

[Any | int] はジェネリクス。
struct_time クラスは、ジェネリクスで型が指定された structseqクラス と _TimeTupleクラスを継承すると言う意味。

ジェネリクスの従来の書き方
コード
from typing import TypeVar, Generic

T = TypeVar('T', int, float)

class Calculator(Generic[T]):
    def add(self, v1: T, v2: T) -> T:
        return v1 + v2

int_calc   = Calculator[int]()
float_calc = Calculator[float]()

print(int_calc.add(1, 2))      # 3
print(float_calc.add(1.5, 2))  # 3.5

ジェネリクスの Python 3.12 以降で使える書き方
コード
from typing import TypeVar, Generic

# Python 3.12 以降で使える書き方
class Calculator[T:(int, float)]:
    def add(self, v1: T, v2: T) -> T:
        return v1 + v2

int_calc       = Calculator[int]()
float_calc     = Calculator[float]()
int_float_calc = Calculator[int | float]()

print(int_calc.add(1, 2))          # 3
print(float_calc.add(1.5, 2))      # 3.5
print(int_float_calc.add(1.5, 2))  # 3.5

7. キーと値の関連付け

見たコード
コード
directions = {
    0: "Unknown",
    1: "Input",
    2: "Output",
    3: "InputOutput",
    4: "Return",
}
キーが 0 ~ 4 のため、リストにした場合も directions[0] ~ [4] で参照できますが、
辞書にしてキーを指定することで、明示的にキーと値の関連付けをしています。
リストの場合は、たまたま 0 から 4 が関連付けられており、要素を途中に追加する場合は注意する必要がある。

8. Final

再代入をすると、型チェッカーでエラーが出る。
コード
from typing import Final

a: Final = 1
b: Final[int] = 2  # Final と型を同時に指定する

a = 3

9. %

古い文字列のフォーマット方法。
% の右側の値を、左側の %s に入れる。
コード
'Name: %s, Dir.: %s, Type: %s, Size: %s, Value: "%s", Precision: %s, NumericScale: %s'
% (
    p.Name,
    adc.directions[p.Direction],
    adc.adTypeNames.get(p.Type, str(p.Type) + " (unknown type)"),
    p.Size,
    p.Value,
    p.Precision,
    p.NumericScale,
)

コード
print('%s %s %d' % ('abc', 'def', 123)) # abc def 123

10. 関数の中の import

関数の中で import した場合は、関数の中だけでインポートしたものを参照可能。
同じ import は1回だけ実行される。2回目以降は実行されないので、繰り返し実行しても問題ない。
コード
def test():
    import sub     # 2回目以降は実行されない
    sub.test_sub()

test()
test()
test()

# sub.test_sub() # エラー : ここでは参照不可。sub は test() の中だけで参照できる。

11. Callable, Iterable, Iterator, Mapping, Sequence の型チェック

コード
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence

# 引数 : 関数
def test1(f: Callable[[int, str], bool]) -> bool:
    return f(1, 'a')

values = [1, 2, 3, 4, 5]

# コールバック用の関数(引数:[int, str], 戻り値:bool] )
def func_for_test1(a:int, b:str) -> bool:
    return True

print(test1(func_for_test1))

#--------------------

# 引数 : Iterable
def test2(values: Iterable[int]) -> bool:
    return True

# Iterable(__iter__() を持つオブジェクト。リストも Iterable)
print(test2([1, 2, 3]))
print(test2({0:1, 1:2, 2:3}))

#--------------------

# 引数 : Iterator
def test3(values: Iterator[int]) -> bool:
    return True

# Iterator(__iter__() と __next__() を持つオブジェクト。全体を1度しかアクセスできない)
iterator = iter([1, 2, 3])
print(test3(iterator))

# filter や map の戻り値も Iterator
filtered = filter(lambda v: v % 2 == 1, [1, 2, 3, 4, 5])
print(test3(filtered))

#--------------------

# 引数 : キーが str、値が int の辞書
def test4(users: Mapping[str, int]) -> bool:
    return True

# Mapping : 辞書など。
print(test4({'key1': 1, 'key2':2}))

#--------------------

# 引数 : 値が str のリスト
def test5(items: Sequence[str]) -> bool:
    return True

# Sequence : インデックスアクセスが可能なリストやタプルなど。
print(test5(['a', 'b', 'c']))

12. オーバロード

見たコード
コード
    @overload
    def call(
        self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT]
    ) -> T_Retval: ...

@overload を使うと、型チェッカーに、同じ名前の関数で、異なる引数があることを伝えられます。
Python にはオーバーロードの機能がないため、自分で関数内で分岐して、オーバーロードっぽい動作にする必要があります。
コード
from typing import overload

class Test:
    @overload
    def test(self, value: int) -> bool: ...
    
    @overload
    def test(self, value: str) -> bool: ...
    
    # 
    def test(self, value: int | str) -> bool:
        if isinstance(value, int):
            print('test(int)')
            return True
        elif isinstance(value, str):
            print('test(str)')
            return True
        
obj = Test()
obj.test(1)
obj.test('a')

13. __slots__

__dict__ はインスタンス毎に保持されているため、大量にインスタンスを作成すると、メモリを消費する。
__slots__ を使うと、__dict__ が保持されずに、全インスタンスで共通の固定の属性となる。動的な属性の追加は不可。
これにより、メモリ消費量を抑えることができる
コード
class Test:
    def __init__(self, value1, value2):
        self.value1 = value1
        self.value2 = value2

obj1_1 = Test(1, 2)

obj1_2 = Test(1, 2)
obj1_2.value3 = 3

# __dict__ はインスタンス毎に保持されているため、値が異なる
print(obj1_1.__dict__)   # {'value1': 1, 'value2': 2}
print(obj1_2.__dict__)   # {'value1': 1, 'value2': 2, 'value3': 3}


# __slots__ を使うと、__dict__ が保持されずに、属性は固定になる。動的な属性の追加は不可。
# 大量にインスタンスを作成する場合には、これにより、メモリ消費量を抑えることができる
class Test2:
    __slots__ = ['value1']  # 属性を固定にする

    def __init__(self, value1, value2):
        self.value1 = value1
        # self.value2 = value2  # エラー : 動的に属性を追加できない

    def test(self):
        pass

obj2 = Test2(1, 2)
# print(obj2.__dict__)  # エラー : __dict__ は存在しない
print(obj2.__slots__) # ['value1']

14. with、コンテキストマネージャー

14.1 with

リソースを取得した場合、途中でエラーが発生しても解放できるようにする必要がありますが、コンテキストマネージャーと with を使うと簡単に書くことができます。
コード
f = open('test.txt', 'w')
try:
    f.write('Test')
finally:
    f.close()

with を使った場合。finally や close を書かなくても、必ず close されます。
コード
with open('test.txt', 'w') as f:
    f.write('Test')
open() の戻り値はファイルオブジェクトですが、コンテキストマネージャーでもあります。
コンテキストマネージャーは、__enter__ と __exit__ を持っています。
with の時に __enter__ が呼ばれ、with を抜ける時に、__exit__ が呼ばれます。

メソッドの有無は、hasattr() で確認できる。
コード
print(hasattr(f, '__enter__'))  # True
print(hasattr(f, '__exit__'))   # True

14.2 yield

yield を含む関数は、実行すると generator オブジェクトを返します。
yield は return のように値を返します。また関数が呼ばれた時は、yield の次のコードから処理が再開されます。
コード
def test():
    print('1回目')
    yield 1

    print('2回目')
    yield 2

    print('3回目')
    yield 3

# test() が返す generator オブジェクトでループ
for value in test():
    print(value)

# 実行結果
# 1回目
# 1
# 2回目
# 2
# 3回目
# 3

14.3 独自のコンテキストマネージャーの実装

コード
class TestContextManager:
    def __enter__(self):
        print('with の中に入りました')
        return self  # as の右側に変数に入る値

    def __exit__(self, exc_type, exc_value, traceback):
        print('with から抜けました')
        return False  # True にすると、例外が発生した場合に例外をキャッチして正常終了してしまう

with TestContextManager() as tcm:
    print(type(tcm))
    print('Test')
    raise Exception('Exception')   

# 実行結果
# with の中に入りました
# <class '__main__.TestContextManager'>
# Test
# with から抜けました
# Traceback (most recent call last):
#   File "main.py", line 17, in <module>
#     raise Exception('Exception')
# Exception: Exception

14.4 デコレータを使った実装

コード
from contextlib import contextmanager

@contextmanager
def test_context_manager():
    print('with の中に入りました')
    try:
        yield  # with の中で発生した例外を finally で処理できるようにするため、try の後ろに yield を書く

    finally:
        print('解放処理')

with test_context_manager():
    print('Test')
    raise Exception('Exception')

# 実行結果
# with の中に入りました
# Test
# 解放処理
# Traceback (most recent call last):
#   File "main.py", line 68, in <module>
#     raise Exception('Exception')
# Exception: Exception

< 前の記事

外部ファイルのインポート

次の記事 >

音声から文字起こし

YouTube X

新着一覧

  • SCSS のインストールVite
  • Tailwind CSS のプロジェクトの作成Tailwind
  • TypeScriptのプロジェクトの作成Vite
  • Flask のインストールと動作確認Python
  • 簡易Webサーバーの作成Python
  • pipeline で文章の生成Python
  • pipeline で文章の要約Python
  • 音声から文字起こしPython
  • Node.js のインストールNode.js
  • .ps1(PowerShellスクリプト)を実行可能にするPowerShell

アーカイブ

  • 2025/12
  • 2025/11
  • 2025/10
  • 2025/09
  • 2025/08

以前のカテゴリー一覧

  • CakePHP3
  • CentOS7
  • HTML・CSS・JavaScript
  • Haskell
  • JavaScript
  • Kotlin
  • Laravel5
  • PHP
  • Python
  • Ruby
  • RubyOnRails5
  • TypeScript
  • Vue.js
  • Webサーバ講座
  • Webプログラミング講座
  • jQuery
  • linux
  • パソコン講座
  • ブログ
  • プログラミング講座
  • メモ帳作成講座
  • 数学

Copyright © 9cubed. All Rights Reserved.

プライバシーポリシー 利用規約
▲