PY/TESTS JAVA → TS → GO →

Python

type hints: 注釈はruntimeで引数を強制しない

type hints: 注釈はruntimeで引数を強制しない

Python 3.13+
conceptpythontyping
01 / 01 proof
Sourceruntime_typing.py
Python 3.13
def repeat(value: str) -> str:
    return value * 2
Source✓Test
Testtest_lessons.py
Python 3.13
from datetime import UTC, datetime

import pytest

from python_by_tests.attributes import Label
from python_by_tests.closures import late_bound_callbacks
from python_by_tests.copies import deep, shallow
from python_by_tests.dataclasses_example import Ticket
from python_by_tests.datetimes import naive_at, utc_at
from python_by_tests.defaults import append_item
from python_by_tests.equality import ProductCode
from python_by_tests.exception_chaining import required_setting
from python_by_tests.generators import doubled
from python_by_tests.identity import same_identity, same_value
from python_by_tests.iterators import numbers
from python_by_tests.none_values import is_missing
from python_by_tests.protocols import Printer, Renderable
from python_by_tests.references import independent_rows, shared_rows
from python_by_tests.resources import TrackedResource
from python_by_tests.runtime_typing import repeat


def test_is_and_equals_have_different_contracts() -> None:
    left, right = ["python"], ["python"]
    assert not same_identity(left, right)
    assert same_value(left, right)


def test_mutable_default_argument_is_shared_between_calls() -> None:
    append_item.__defaults__[0].clear()  # type: ignore[index]
    assert append_item("first") == ["first"]
    assert append_item("second") == ["first", "second"]


def test_shallow_copy_shares_nested_objects_but_deep_copy_does_not() -> None:
    original = [["before"]]
    shallow_copy, deep_copy = shallow(original), deep(original)
    original[0][0] = "after"
    assert shallow_copy == [["after"]]
    assert deep_copy == [["before"]]


def test_closure_late_binding_reads_the_final_loop_value() -> None:
    assert [callback() for callback in late_bound_callbacks()] == [2, 2, 2]


def test_generator_is_lazy_and_is_consumed_once() -> None:
    calls: list[int] = []
    values = doubled([1, 2], calls)
    assert calls == []
    assert list(values) == [2, 4]
    assert calls == [1, 2]
    assert list(values) == []


def test_context_manager_calls_exit_after_the_with_block() -> None:
    events: list[str] = []
    with TrackedResource(events):
        events.append("use")
    assert events == ["enter", "use", "exit"]


def test_list_multiplication_shares_nested_list_references() -> None:
    shared = shared_rows()
    shared[0].append("x")
    assert shared == [["x"], ["x"], ["x"]]

    independent = independent_rows()
    independent[0].append("x")
    assert independent == [["x"], [], []]


def test_none_is_checked_by_identity() -> None:
    assert is_missing(None)
    assert not is_missing("")


def test_iterator_advances_and_raises_after_consumption() -> None:
    iterator = numbers()
    assert next(iterator) == 1
    assert list(iterator) == [2, 3]
    with pytest.raises(StopIteration):
        next(iterator)


def test_exception_chaining_preserves_the_original_cause() -> None:
    with pytest.raises(ValueError) as caught:
        required_setting({})
    assert str(caught.value) == "region must be configured"
    assert isinstance(caught.value.__cause__, KeyError)


def test_instance_assignment_shadows_but_does_not_change_class_attribute() -> None:
    left, right = Label(), Label()
    left.value = "local"
    assert left.value == "local"
    assert right.value == "shared"
    assert Label.value == "shared"


def test_custom_equality_without_hash_is_not_hashable() -> None:
    assert ProductCode("A-1") == ProductCode("A-1")
    with pytest.raises(TypeError):
        {ProductCode("A-1")}


def test_dataclass_generates_value_equality_and_readable_repr() -> None:
    assert Ticket(1, "fix") == Ticket(1, "fix")
    assert repr(Ticket(1, "fix")) == "Ticket(id=1, title='fix')"


def test_type_hints_are_not_runtime_argument_validation() -> None:
    assert repeat(3) == 6  # type: ignore[arg-type, return-value]


def test_protocol_accepts_structure_without_explicit_inheritance() -> None:
    printer = Printer()
    assert isinstance(printer, Renderable)
    assert printer.render() == "printed"


def test_timezone_aware_datetimes_compare_but_naive_and_aware_do_not() -> None:
    assert utc_at(9) < datetime(2026, 1, 1, 10, tzinfo=UTC)
    with pytest.raises(TypeError):
        _ = utc_at(9) < naive_at(10)
01Assertion

このテストで確認できること

  • str注釈の関数にintを渡せる
  • 結果は実際の演算に従う

型注釈は静的解析の入力です。runtimeで検証したい境界には明示的な検証を置きます。

OBSERVED RESULTrepeat(3) → 6

Static index

教材を検索

テーマ、タグ、テスト名、カテゴリ、Pythonバージョンで絞り込みます。

16件の教材を表示しています。

Python · Python 3.13+is と ==: 同一性と値の等価性は別Test isとequalsは別の契約Python · Python 3.13+mutable default argument: 呼び出し間で値を共有するTest mutable default argumentは共有されるPython · Python 3.13+copy: shallow copyは入れ子を共有しdeepcopyは共有しないTest shallowとdeep copyは入れ子の共有が違うPython · Python 3.13+closure: loop変数はlate bindingで最後の値を読むTest closureは最後のloop値を読むPython · Python 3.13+generator: 遅延評価され、一度消費すると戻らないTest generatorはlazyかつsingle-usePython · Python 3.13+with: __enter__と__exit__でリソース境界を固定するTest context managerはexitを呼ぶPython · Python 3.13+list multiplication: 入れ子の要素は同じlistを参照するTest list multiplicationは入れ子を共有するPython · Python 3.13+None: 値の不在は == ではなく is None で判定するTest Noneはsingletonとして比較するPython · Python 3.13+iterator: nextで進み、消費した要素は戻らないTest iteratorは一度ずつ消費されるPython · Python 3.13+exception chaining: raise ... from ... で原因を失わないTest 例外のcauseを明示するPython · Python 3.13+class attribute: instanceへの代入は共有値を上書きしないTest class属性とinstance属性は別の場所にあるPython · Python 3.13+__eq__ / __hash__: 等価性を定義するとhash契約も変わるTest 自作の等価性はhashabilityに影響するPython · Python 3.13+dataclass: 宣言から__init__と値比較を生成するTest dataclassは値比較を生成するPython · Python 3.13+type hints: 注釈はruntimeで引数を強制しないTest 型注釈だけではruntime検証されないPython · Python 3.13+Protocol: 継承なしでも必要な操作を満たせば扱えるTest runtime-checkable Protocolで構造を確認するPython · Python 3.13+datetime: awareとnaiveは比較できず、timezoneを揃えるTest awareとnaiveの比較はTypeError