فهرست مقاله
یک آزمونِ محلی، آفستِ ساختگیِ ورودی را عوض میکند، کلیدِ کمکی میسازد و وسطِ کار خطا میدهد. آزمونِ بعدی همان دیکشنری را میگیرد؛ آیا فقط مقدارِ آفست باید برگردد یا کلیدِ کمکی هم باید ناپدید شود؟ برای محافظت از دادهٔ فیکسچر، باید وضعیتِ پیش از ورود را دقیق تعریف کنیم. این درس با patch.dict واقعی، یک دیکشنریِ کوچک و مرجعِ مستقل، همین پرسش را بررسی میکند؛ هیچ سرویس، حسگر، محیطِ فرایند یا خطِ CI اجرا نمیشود.
۱. تنظیمِ آزمایشی چرا نباید برای آزمونِ بعد بماند؟

فیکسچرِ ما دو ورودی دارد: offset_mv=1 و gain_code=2. اولی آفستِ فرضی برحسبِ میلیولت است؛ دومی فقط کدِ بدونِ واحد و بهرهٔ اندازهگیریشده نیست. دادهها از دستگاه نیامدهاند. آزمون میخواهد آفست را موقتاً منفی سه ببیند، probe_code=7 بسازد و کلیدِ بهره را حذف کند. وضعیتِ مناسب برای آزمونِ بعدی، همان دو ورودیِ اولیه است؛ نه باقیماندهٔ آخرین فرمانِ بدنه.
دستورِ update مقدارها را مینویسد، اما بهتنهایی نسخهٔ قبلی، محدودهٔ عمر یا مرحلهٔ خروج ندارد. اگر فقط آفست را بعداً یک کنیم، کلیدِ تازه هنوز میماند و کلیدِ حذفشده برنمیگردد. حفاظتِ موردِ نظر، بازگرداندنِ کلِ نگاشتِ سطحِ اول است. این یک سازوکارِ کوچک برای آزموننویسی است؛ ایمنکردنِ سرویس، مدیریتِ رازها و جداسازیِ محیط، مسئلههای بزرگتری هستند که با این نمونه حل نمیشوند.
مستنداتِ رسمیِ patch.dict میگوید دیکشنری پس از محدوده به وضعیتِ اولیه بازگردانده میشود. نمونهٔ مستندات، افزودن، تغییر و حذفِ کلید در بدنه را نیز نشان میدهد. ما فقط صورتِ مدیرِ زمینه روی یک dict دقیق را به کار میبریم؛ تزئینگر، نامِ واردشونده، os.environ، sys.modules و نگاشتِ سفارشی واردِ آزمایش نمیشوند.
تابعِ آموزشی چهار نامِ مجاز و مقدارهای صحیحِ منفی سیودو تا سیودو میپذیرد. نامهای mode_code و probe_code هم کدِ ساختگیاند. این محدودیتها برای قراردادِ خوانا و خروجیِ قابلمقایسهاند؛ کتابخانه چنین سقفی برای دیکشنری تعیین نکرده است. مقدارِ منطقی، زیرکلاس و شیء دارای رفتارِ سفارشی رد میشوند تا یک آزمایشِ ساده به اجرای روشهای دلخواه تبدیل نشود.
۲. clear چه چیزی را هنگامِ ورود عوض میکند؟

با clear=False، ورودیهای اولیه نگه داشته و مقدارهای overlay روی آنها نوشته میشوند. در شاهدِ اصلی، هنگامِ ورود بهرهٔ دو و آفستِ منفی سه دیده میشود. با clear=True، دیکشنری پیش از اعمالِ overlay خالی میشود؛ پس فقط آفستِ منفی سه باقی میماند. این دو سیاست، نقطهٔ شروعِ بدنه را عوض میکنند، نه وضعیتِ نهاییِ پس از خروج را.
مقدارِ بخشِ as همان دیکشنریِ وصلهشده است. مستندات این مقدارِ برگشتی را از نسخهٔ 3.8 ذکر میکند. نامِ دیگری که از قبل به آن دیکشنری اشاره میکرد، تغییرِ موقت را میبیند؛ کپیِ مستقلی برای هر نام ساخته نشده است. بنابراین «موقت» به معنی پنهانبودن از دیگر مشاهدهکنندگان نیست. مثالِ ما مالکیتِ همگامِ محلی را فرض میکند و دربارهٔ دسترسیِ همزمانِ نخ، وظیفه یا سرویس تضمینی نمیدهد.
حتی overlay تهی هم معنی دارد. بدونِ clear، بدنه با تنظیماتِ اولیه آغاز میشود، اما تغییرهای بعدیاش هنگامِ خروج برمیگردند. همراهِ clear، بدنه از نگاشتِ تهی آغاز میشود و خروج باز هم تنظیماتِ اولیه را میگذارد. این تفاوت کمک میکند آزمون واقعاً نبودِ یک ورودی را ببیند؛ لازم نیست مقدارِ ساختگیِ «غایب» جایِ نبودِ کلید قرار دهیم.
۳. تغییرهای بدنه و خروجِ استثنایی هم بازگردانده میشوند

در بدنهٔ شاهد، پس از افزودنِ کلیدِ کمکی سه ورودی داریم؛ بعد از حذفِ بهره، فقط آفستِ موقت و کلیدِ کمکی باقیاند. خروج باید بهرهٔ اولیه را برگرداند، آفست را یک کند و کلیدِ کمکی را حذف کند. بازگردانی فقط معکوسِ overlay نیست؛ کلیدهایی که خودِ بدنه ساخته یا پاک کرده هم در نتیجهٔ نهایی اثرِ ماندگار ندارند.
در کدِ منبعِ دقیقِ CPython 3.14.5، کلاسِ _patch_dict هنگامِ ورود از نگاشتِ قبلی نسخه میگیرد و هنگامِ خروج، نگاشتِ فعال را خالی و نسخهٔ ذخیرهشده را اعمال میکند. خروج False برمیگرداند؛ پس خودِ این مدیر خطای بدنه را سرکوب نمیکند. کدِ منبع را خواندهایم و نسخهٔ دانلودشده را اجرا نمیکنیم؛ رفتارِ برنامه با کتابخانهٔ نصبشده سنجیده میشود.
پوشانندهٔ ما میتواند پس از تعدادِ مشخصی فرمان، خطای ساختگیِ FixtureAbort بدهد. صفر یعنی خطا بلافاصله پس از ورود؛ یک یعنی فقط فرمانِ نخست انجام شده است. این خطای مشخص بیرونِ محدوده برای ساختِ گزارش گرفته میشود. شاهدِ جدا نشان میدهد یک ValueError نامرتبط با همان هویت از محدوده عبور میکند و تنظیمات نیز برگشتهاند؛ این رفتار را با سیاستِ عمومیِ بلعیدنِ خطا اشتباه نمیگیریم.
ذخیرهسازی سطحی است. اگر مقدارِ یک کلید فهرست باشد و بدنه خودِ آن فهرست را تغییر دهد، برگرداندنِ ارجاعِ قبلی لزوماً تغییرِ محتوای فهرست را خنثی نمیکند. API این درس عمداً فقط عددِ صحیح میپذیرد. همچنین بازگردانیِ یک نگاشتِ محلی، تراکنش، جبرانِ درخواستِ شبکه یا بازیابی پس از نابودیِ فرایند نیست؛ هیچکدام از این اثرها در نمونه ایجاد نشدهاند.
۴. کدِ کامل و مرجعِ مستقلِ آخرین رخدادِ هر کلید

فرمانها یک تاپلِ آماده با حداکثر شش عضو هستند: نوشتنِ مقدار یا حذفِ کلید. حذفِ کلیدِ غایب، طبقِ سیاستِ خودِ مثال، بیاثر است؛ این رفتار را از patch.dict نقل نمیکنیم. تمامِ ورودی، حتی فرمانِ نامعتبرِ بعد از نقطهٔ خطای انتخابشده، پیش از ساختنِ محدوده بررسی میشود. انتخابِ خروجِ زودهنگام نباید راهی برای پذیرفتنِ توصیفِ خراب باشد.
گزارش، نگاشتِ مرتبشده را بلافاصله پس از ورود و پس از هر فرمانِ واقعاً انجامشده ثبت میکند. ترتیبِ درجِ کلیدها قراردادِ خروجی نیست؛ زوجهای کلید و مقدار مقایسه میشوند. گزارش و ردیفهای داخلی تاپلاند تا نگهداشتنِ یک مشاهده، آن را با تغییرهای بعدی عوض نکند. دیکشنریِ اولیه همان شیء میماند و overlay نیز پس از پایان دستنخورده است.
"""A bounded primitive dictionary fixture, temporarily patched and restored."""
from itertools import product
from typing import NamedTuple
from unittest.mock import patch
import json
import platform
import sys
AUTHOR_EXECUTION_ENABLED = True
KEYS = ("gain_code", "mode_code", "offset_mv", "probe_code")
MAX_COMMANDS = 6
class FixtureAbort(Exception):
"""One controlled local body failure, not a general exception policy."""
class PatchTrace(NamedTuple):
inside: tuple
final: tuple
applied_commands: int
outcome: str
same_dictionary: bool
same_error_object: object
def _key(value):
if type(value) is not str:
raise TypeError("exact string key required")
if value not in KEYS:
raise ValueError("unknown fixture key")
def _value(value):
if type(value) is not int:
raise TypeError("exact integer fixture value required")
if not -32 <= value <= 32:
raise ValueError("fixture value outside -32..32")
def _admit(initial, overlay, clear, operations, abort_after):
for mapping in (initial, overlay):
if type(mapping) is not dict:
raise TypeError("exact built-in dictionary required")
if len(mapping) > 4:
raise ValueError("at most four declared keys")
for key, value in mapping.items():
_key(key)
_value(value)
if type(clear) is not bool:
raise TypeError("exact Boolean clear flag required")
if type(operations) is not tuple:
raise TypeError("exact materialized command tuple required")
if len(operations) > MAX_COMMANDS:
raise ValueError("at most six commands")
for command in operations:
if type(command) is not tuple or not command:
raise TypeError("exact nonempty command tuple required")
if type(command[0]) is not str:
raise TypeError("exact command name required")
if command[0] == "set" and len(command) == 3:
_key(command[1])
_value(command[2])
elif command[0] == "delete" and len(command) == 2:
_key(command[1])
else:
raise ValueError("unknown command or wrong arity")
if abort_after is not None:
if type(abort_after) is not int:
raise TypeError("exact integer abort position required")
if not 0 <= abort_after <= len(operations):
raise ValueError("abort position outside command prefix")
def _snapshot(mapping):
return tuple(sorted(mapping.items()))
def trace_patch_fixture(initial, overlay, clear, operations, abort_after=None):
"""Observe one actual patch.dict scope and its complete top-level restore.
The caller owns initial and must not access/mutate it concurrently. The
complete materialized declaration is admitted before entering a patch.
Only exact string/int primitive values enter this educational API.
"""
_admit(initial, overlay, clear, operations, abort_after)
alias = initial
observations = []
applied = 0
failure = FixtureAbort("controlled fixture body failure")
caught = None
same_dictionary = False
try:
with patch.dict(initial, overlay, clear=clear) as active:
same_dictionary = active is initial and alias is initial
observations.append(_snapshot(active))
if abort_after == 0:
raise failure
for command in operations:
if command[0] == "set":
active[command[1]] = command[2]
else:
# Own command policy: an absent admitted key is a no-op.
active.pop(command[1], None)
applied += 1
observations.append(_snapshot(active))
if abort_after == applied:
raise failure
except FixtureAbort as error:
if error is not failure:
raise
caught = error
return PatchTrace(tuple(observations), _snapshot(initial), applied,
"normal" if caught is None else "aborted",
same_dictionary, None if caught is None else caught is failure)
def last_event_reference(initial, overlay, clear, operations, abort_after=None):
"""Trusted valid fixtures: independent per-key maximum-event relation.
No dictionary update/delete replay, patch, target API, admission helper,
or target snapshot helper supplies expected observations.
"""
applied = len(operations) if abort_after is None else abort_after
universe = ("gain_code", "mode_code", "offset_mv", "probe_code")
original_rows = tuple((key, initial[key]) for key in universe if key in initial)
expected = []
for prefix in range(applied + 1):
rows = []
for key in universe:
events = tuple((index, command) for index, command in enumerate(operations[:prefix])
if command[1] == key)
if events:
latest = max(events, key=lambda event: event[0])[1]
if latest[0] == "set":
rows.append((key, latest[2]))
elif key in overlay:
rows.append((key, overlay[key]))
elif not clear and key in initial:
rows.append((key, initial[key]))
expected.append(tuple(rows))
return PatchTrace(tuple(expected), original_rows, applied,
"normal" if abort_after is None else "aborted",
True, None if abort_after is None else True)
def _rejected(call):
try:
call()
except (TypeError, ValueError):
return True
return False
def run_example():
checks = {}
initial = {"offset_mv": 1, "gain_code": 2}
overlay = {"offset_mv": -3}
commands = (("set", "probe_code", 7), ("delete", "gain_code"))
baseline = (("gain_code", 2), ("offset_mv", 1))
manual = trace_patch_fixture(initial, overlay, False, commands)
checks["literal_manual_fixture_restores_the_complete_original_mapping"] = (
manual == PatchTrace(((("gain_code", 2), ("offset_mv", -3)),
(("gain_code", 2), ("offset_mv", -3), ("probe_code", 7)),
(("offset_mv", -3), ("probe_code", 7))),
baseline, 2, "normal", True, None)
and initial == {"offset_mv": 1, "gain_code": 2})
cleared = trace_patch_fixture(initial, overlay, True, commands)
checks["clear_changes_entry_contents_but_not_the_final_restore"] = (
cleared.inside == ((("offset_mv", -3),),
(("offset_mv", -3), ("probe_code", 7)),
(("offset_mv", -3), ("probe_code", 7)))
and cleared.final == baseline)
changed = trace_patch_fixture(initial, {"mode_code": 3}, False,
(("set", "offset_mv", 9), ("delete", "gain_code"),
("set", "probe_code", 8)))
checks["body_add_update_delete_are_all_undone_at_top_level"] = (
changed.inside[-1] == (("mode_code", 3), ("offset_mv", 9), ("probe_code", 8))
and changed.final == baseline)
alias = initial
with patch.dict(initial, {"mode_code": 3}) as active:
active["offset_mv"] = 7
live_alias_observation = active is initial is alias and alias["offset_mv"] == 7
checks["context_value_and_existing_alias_observe_the_same_dictionary"] = (
live_alias_observation and initial == {"offset_mv": 1, "gain_code": 2})
empty_overlay = trace_patch_fixture(initial, {}, False,
(("delete", "offset_mv"), ("set", "mode_code", 4)))
checks["empty_overlay_without_clear_still_restores_body_mutations"] = (
empty_overlay.inside[0] == baseline
and empty_overlay.inside[-1] == (("gain_code", 2), ("mode_code", 4))
and empty_overlay.final == baseline)
empty_cleared = trace_patch_fixture(initial, {}, True, ())
checks["empty_overlay_with_clear_is_empty_only_inside_the_scope"] = (
empty_cleared.inside == ((),) and empty_cleared.final == baseline)
at_entry = trace_patch_fixture(initial, overlay, False, commands, 0)
checks["controlled_entry_abort_applies_zero_commands_and_restores"] = (
at_entry.inside == (manual.inside[0],) and at_entry.applied_commands == 0
and at_entry.outcome == "aborted" and at_entry.same_error_object is True
and at_entry.final == baseline)
after_one = trace_patch_fixture(initial, overlay, False, commands, 1)
checks["controlled_prefix_abort_records_no_later_command_and_restores"] = (
after_one.inside == manual.inside[:2] and after_one.applied_commands == 1
and after_one.outcome == "aborted" and after_one.same_error_object is True
and after_one.final == baseline)
ordinary_error = ValueError("separate actual-library body failure")
received = None
try:
with patch.dict(initial, {"probe_code": 5}, clear=True):
initial["mode_code"] = 4
raise ordinary_error
except ValueError as error:
received = error
checks["actual_patch_dict_does_not_suppress_an_unrelated_body_error"] = (
received is ordinary_error and initial == {"offset_mv": 1, "gain_code": 2})
with patch.dict(initial, {"offset_mv": -3}):
outer = tuple(sorted(initial.items()))
with patch.dict(initial, {"mode_code": 6}, clear=True):
inner = tuple(sorted(initial.items()))
initial["probe_code"] = 7
after_inner = tuple(sorted(initial.items()))
checks["nested_primitive_scopes_restore_inner_then_outer_baselines"] = (
outer == after_inner == (("gain_code", 2), ("offset_mv", -3))
and inner == (("mode_code", 6),) and tuple(sorted(initial.items())) == baseline)
repeated_commands = (("set", "probe_code", 1), ("set", "probe_code", 2),
("delete", "probe_code"), ("delete", "probe_code"),
("set", "probe_code", -1))
repeated = trace_patch_fixture({}, {}, False, repeated_commands)
checks["same_key_latest_write_and_absent_delete_have_explicit_own_semantics"] = (
repeated.inside == ((), (("probe_code", 1),), (("probe_code", 2),), (), (),
(("probe_code", -1),)) and repeated.final == ())
def declared_maps(values):
for choices in product((None,) + values, repeat=2):
yield {key: value for key, value in zip(("offset_mv", "gain_code"), choices)
if value is not None}
alphabet = (("set", "offset_mv", 3), ("delete", "offset_mv"),
("set", "gain_code", -3), ("delete", "gain_code"))
family_profiles = 0
for original in declared_maps((0, 1)):
for additions in declared_maps((-2, 2)):
for clear in (False, True):
for length in range(3):
for operations in product(alphabet, repeat=length):
for abort_after in (None,) + tuple(range(length + 1)):
expected = last_event_reference(original, additions, clear,
operations, abort_after)
actual = trace_patch_fixture(original, additions, clear,
operations, abort_after)
assert actual == expected, (original, additions, clear,
operations, abort_after)
family_profiles += 1
checks["bounded_family_matches_independent_last_event_relation_ONE_group"] = (
family_profiles == 12636)
original_patch_dict = patch.dict
entered = []
def forbidden_patch(*args, **kwargs):
entered.append(True)
raise AssertionError("invalid declaration reached patch construction")
invalid_initial = {"offset_mv": 1}
invalid_commands = ((("set", "probe_code", 2), ("set", "mode_code", True)),
(("delete", "offset_mv"), ("delete", "unknown")),
(("set", "probe_code", 2), ["delete", "offset_mv"]))
patch.dict = forbidden_patch
try:
late_rejected = all(_rejected(lambda ops=ops:
trace_patch_fixture(invalid_initial, {}, False, ops, 0))
for ops in invalid_commands)
finally:
patch.dict = original_patch_dict
checks["whole_late_declaration_is_rejected_before_patch_or_mutation"] = (
late_rejected and entered == [] and invalid_initial == {"offset_mv": 1})
class DictChild(dict):
pass
class IntChild(int):
pass
class StrChild(str):
pass
class TupleChild(tuple):
pass
consumed = []
def lazy_commands():
consumed.append(True)
yield ("delete", "offset_mv")
invalid_profiles = (
([], {}, False, (), None), (DictChild(), {}, False, (), None),
({}, DictChild(), False, (), None), ({True: 1}, {}, False, (), None),
({StrChild("offset_mv"): 1}, {}, False, (), None),
({"offset_mv": True}, {}, False, (), None),
({"offset_mv": IntChild(1)}, {}, False, (), None),
({"offset_mv": -33}, {}, False, (), None),
({}, {"offset_mv": 33}, False, (), None),
({"unknown": 1}, {}, False, (), None), ({}, {}, 0, (), None),
({}, {}, False, [], None), ({}, {}, False, TupleChild(), None),
({}, {}, False, lazy_commands(), None),
({}, {}, False, ((),), None),
({}, {}, False, (("set", "offset_mv"),), None),
({}, {}, False, (("delete", "offset_mv", 1),), None),
({}, {}, False, (("other", "offset_mv"),), None),
({}, {}, False, ((StrChild("delete"), "offset_mv"),), None),
({}, {}, False, (("set", "offset_mv", 1.0),), None),
({}, {}, False, (("delete", "offset_mv"),) * 7, None),
({}, {}, False, (), True), ({}, {}, False, (), -1),
({}, {}, False, (), 1), ({}, {}, False, (), 0.0),
)
maximum = {"gain_code": -32, "mode_code": 32, "offset_mv": -32, "probe_code": 32}
maximum_before = tuple(sorted(maximum.items()))
maximum_overlay = dict(maximum)
edge = trace_patch_fixture(maximum, maximum_overlay, True,
(("set", "offset_mv", 32),) * 6, 6)
fresh_one = trace_patch_fixture({}, {}, False, (("set", "mode_code", 0),))
fresh_two = trace_patch_fixture({}, {}, False, (("set", "mode_code", 0),))
checks["strict_envelopes_inclusive_bounds_immutable_fresh_reports_overlay_preserved"] = (
all(_rejected(lambda args=args: trace_patch_fixture(*args)) for args in invalid_profiles)
and consumed == [] and edge.applied_commands == 6 and edge.outcome == "aborted"
and edge.final == maximum_before == tuple(sorted(maximum_overlay.items()))
and fresh_one == fresh_two and fresh_one is not fresh_two
and type(fresh_one.inside) is tuple and type(fresh_one.inside[-1][0]) is tuple)
assert len(checks) == 14 and all(type(v) is bool and v for v in checks.values()), checks
return {"runtime": {"python": platform.python_version(),
"implementation": platform.python_implementation()},
"scope": "Actual unittest.mock.patch.dict, one owned primitive dictionary; no environment, service, hardware or concurrent mutation",
"units": {"offset_mv": "synthetic millivolts", "other_keys": "dimensionless fixture codes"},
"manual_keep": manual._asdict(), "manual_clear": cleared._asdict(),
"manual_abort_after_one": after_one._asdict(),
"independent_oracle": "Per-key greatest-index event relation, no dict update/delete replay or patch in expected path",
"family_profiles_ONE_group": family_profiles,
"invalid_profiles": len(invalid_commands) + len(invalid_profiles),
"groups_total": len(checks), "checks": checks,
"limits": "Top-level shallow restoration only; exact int values exclude nested mutable rollback. No thread/task/service isolation, arbitrary mapping hooks, secrets protection, crash recovery, CI deployment or performance claim."}
if __name__ == "__main__":
if not AUTHOR_EXECUTION_ENABLED:
raise SystemExit("Author execution awaits explicit ROOT authorization")
sys.stdout.buffer.write((json.dumps(run_example(), ensure_ascii=True, indent=2,
allow_nan=False) + "\n").encode("ascii"))
مرجعِ مستقل برای هر کلید، آخرین رخدادِ مربوط به آن را در پیشوندِ فرمانها انتخاب میکند. آخرین نوشتن، مقدار را تعیین میکند؛ آخرین حذف، کلید را غایب میکند؛ بدونِ رخداد، قواعدِ overlay و clear تعیینکنندهاند. این مسیر از patch، تابعِ اصلی، اعتبارسنجِ آن یا حلقهٔ بازپخشِ update و delete برای تولیدِ انتظار استفاده نمیکند. وضعیتِ نهایی نیز از تصویرِ تغییرناپذیرِ ورودی میآید.
چهارده گروهِ معنادار، شاهدهای دستی، هویتِ نامِ مستعار، overlay تهی، خروجِ استثنایی، محدودهٔ تودرتو، پذیرشِ کامل و کرانها را در بر میگیرند. خانوادهٔ محدودِ کلیدهای دوگانه و پیشوندهای فرمان، فقط یک گروه است؛ شمارِ واقعیِ حالتها در خروجی ثبت میشود و برهانِ تمامِ دیکشنریهای پایتون نیست. مستنداتِ خواندهشده 3.14.9 و منبعِ پیادهسازی برچسبِ 3.14.5 است؛ نسخهٔ واقعیِ اجرا جداگانه در خروجی میآید.
{
"runtime": {
"python": "3.14.5",
"implementation": "CPython"
},
"scope": "Actual unittest.mock.patch.dict, one owned primitive dictionary; no environment, service, hardware or concurrent mutation",
"units": {
"offset_mv": "synthetic millivolts",
"other_keys": "dimensionless fixture codes"
},
"manual_keep": {
"inside": [
[
[
"gain_code",
2
],
[
"offset_mv",
-3
]
],
[
[
"gain_code",
2
],
[
"offset_mv",
-3
],
[
"probe_code",
7
]
],
[
[
"offset_mv",
-3
],
[
"probe_code",
7
]
]
],
"final": [
[
"gain_code",
2
],
[
"offset_mv",
1
]
],
"applied_commands": 2,
"outcome": "normal",
"same_dictionary": true,
"same_error_object": null
},
"manual_clear": {
"inside": [
[
[
"offset_mv",
-3
]
],
[
[
"offset_mv",
-3
],
[
"probe_code",
7
]
],
[
[
"offset_mv",
-3
],
[
"probe_code",
7
]
]
],
"final": [
[
"gain_code",
2
],
[
"offset_mv",
1
]
],
"applied_commands": 2,
"outcome": "normal",
"same_dictionary": true,
"same_error_object": null
},
"manual_abort_after_one": {
"inside": [
[
[
"gain_code",
2
],
[
"offset_mv",
-3
]
],
[
[
"gain_code",
2
],
[
"offset_mv",
-3
],
[
"probe_code",
7
]
]
],
"final": [
[
"gain_code",
2
],
[
"offset_mv",
1
]
],
"applied_commands": 1,
"outcome": "aborted",
"same_dictionary": true,
"same_error_object": true
},
"independent_oracle": "Per-key greatest-index event relation, no dict update/delete replay or patch in expected path",
"family_profiles_ONE_group": 12636,
"invalid_profiles": 28,
"groups_total": 14,
"checks": {
"literal_manual_fixture_restores_the_complete_original_mapping": true,
"clear_changes_entry_contents_but_not_the_final_restore": true,
"body_add_update_delete_are_all_undone_at_top_level": true,
"context_value_and_existing_alias_observe_the_same_dictionary": true,
"empty_overlay_without_clear_still_restores_body_mutations": true,
"empty_overlay_with_clear_is_empty_only_inside_the_scope": true,
"controlled_entry_abort_applies_zero_commands_and_restores": true,
"controlled_prefix_abort_records_no_later_command_and_restores": true,
"actual_patch_dict_does_not_suppress_an_unrelated_body_error": true,
"nested_primitive_scopes_restore_inner_then_outer_baselines": true,
"same_key_latest_write_and_absent_delete_have_explicit_own_semantics": true,
"bounded_family_matches_independent_last_event_relation_ONE_group": true,
"whole_late_declaration_is_rejected_before_patch_or_mutation": true,
"strict_envelopes_inclusive_bounds_immutable_fresh_reports_overlay_preserved": true
},
"limits": "Top-level shallow restoration only; exact int values exclude nested mutable rollback. No thread/task/service isolation, arbitrary mapping hooks, secrets protection, crash recovery, CI deployment or performance claim."
}
هر دو مرجع ناشرِ مشترک دارند و دو تأییدِ بیرونیِ مستقل معرفی نمیشوند. تاریخِ دسترسی ۳۰ مهر ۱۴۰۵ است و روزِ نخستین انتشارِ این دو سند معلوم نیست. در درسِ مدیرِ زمینهٔ مولدی، مسئله یک yield و انتشارِ خطا بود؛ اینجا مدیرِ آمادهٔ کتابخانه و بازگردانیِ تمامِ کلیدها مهم است. درسِ ExitStack نیز ترتیبِ آزادسازیِ منابع را میسنجید، نه بازگردانیِ محتوای نگاشت. این دو پیوند از نسخههای منتشرشدهٔ ذخیرهشده خوانده شدهاند؛ دسترسیِ زندهٔ امروز ادعا نمیشود.
۵. چهار پرسش دربارهٔ مرزِ بازگردانی

پرسش اول: چرا update کافی نیست؟ update فقط مقدارهای دادهشده را اعمال میکند و سابقهای برای خروج ندارد. برگرداندنِ دستیِ یک مقدار هم کلیدِ تازهٔ بدنه را حذف یا کلیدِ پاکشده را بازسازی نمیکند. قراردادِ این آزمایش، برابریِ کاملِ نگاشتِ نهایی با نگاشتِ پیش از ورود و حفظِ همان شیء است.
پرسش دوم: آیا clear=True تنظیمِ اولیه را برای همیشه پاک میکند؟ خیر؛ خالیکردن، نقطهٔ شروعِ موقتِ بدنه را تعیین میکند. تصویرِ اولیه پیش از آن گرفته شده و هنگامِ خروج بازمیگردد. پس در شاهدِ اصلی، بهره داخلِ محدوده غایب است ولی پس از خروج دوباره دو است؛ آفست نیز به یک برمیگردد.
پرسش سوم: اگر پس از افزودنِ probe_code خطا بدهیم چه میماند؟ ردِ داخل فقط ورود و فرمانِ نخست را دارد؛ حذفِ بعدی اجرا نشده است. با این حال، خروج کلیدِ تازه را برمیدارد و هر دو ورودیِ اولیه را برمیگرداند. خودِ مدیر خطا را پنهان نمیکند؛ پوشاننده فقط خطای ساختگیِ تعیینشدهٔ خودش را برای گزارش میگیرد.
پرسش چهارم: آیا همین نتیجه برای مقدارِ فهرستی یا کارِ همزمان هم کافی است؟ خیر؛ نسخهٔ سطحی، محتوای شیء داخلی را تکثیر نمیکند و نامِ مستعار، تغییرِ موقتِ نگاشت را میبیند. مقدارهای صحیحِ دقیق، دامنهٔ این مثالاند. پیش از افزودنِ نوعِ تغییرپذیر، اجرای همزمان یا سرویسِ واقعی، قراردادِ مالکیت و جداسازی باید جدا طراحی و آزموده شود.
منابع و مطالعهٔ بیشتر
بررسی منابع: ۳۰ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.

