فهرست مقاله
۱. پیش از اجرا، شکلِ درخواست را مشخص کنیم

در یک ابزارِ آزمایشی، درخواستِ محاسبه ممکن است ابتدا به صورت داده ساخته شود و بعد به تابع برسد. دیدنِ چهار عدد کافی نیست: باید بدانیم هر عدد قرار است کدام پارامتر را پُر کند، چه چیزی حذف شده و کدام نام دوبار آمده است. اگر عیبِ چیدمان را تنها هنگامِ اجرای تابع کشف کنیم، گزارشِ خطا با منطقِ محاسبه درهم میآمیزد. اینجا یک برنامهٔ کوچک میسازیم که ابتدا طرحِ فراخوانی را آماده میکند و اجرای صریح را مرحلهای جدا نگه میدارد.
تابعِ تألیفیِ ما شمارشِ ساختگی را در یک بهرهٔ قراردادی ضرب میکند و آفستی بر حسب میلیولت میافزاید. شمارش از صفر تا شش، بهره از یک تا چهار، آفست از منفی سه تا سه و برچسبِ کانال از صفر تا دو مجاز است. بهره را برای همین تمرین با واحدِ میلیولت بر شمارش تفسیر میکنیم. هیچ مبدل، حسگر یا کالیبراسیونِ واقعی در کار نیست؛ نامِ مهندسیِ پارامتر، صحتِ فیزیکیِ ورودی را ثابت نمیکند.
درسِ مرزِ Protocol در زمان اجرا پیشتر تفاوتِ حضورِ عضو و رفتارِ یک خواندن را بررسی کرده است. مسئلهٔ تازه، نگاشتِ یک درخواستِ مشخص به جایگاههای یک تابعِ مشخص است. نه نمونههای آداپتور را بازسازی میکنیم و نه صرفِ قابلفراخوانیبودن را معیارِ پذیرش میگیریم. دو ورودیِ آماده داریم: تا چهار آرگومانِ موقعیتی و تا پنج زوجِ نام و مقدار؛ این سقفها سیاستِ آموزشیِ خودماناند.
۲. خطِ مورب و ستاره، جایگاهِ آرگومان را تعیین میکنند

در امضای تابع، counts پیش از علامتِ / قرار دارد و فقط موقعیتی است. gain میتواند موقعیتی یا با نام داده شود. دو پارامترِ پس از *، یعنی offset_mv و channel، فقط کلیدواژهایاند. کانال پیشفرض ندارد؛ آفست صفر و بهره دو پیشفرضهای صریحاند. مرجعِ رسمیِ Signature و Parameter این گونههای پارامتر و قراردادِ نگاشت را توضیح میدهد.
بنابراین درخواستِ دارای یک مقدارِ موقعیتی و نامِ کانال میتواند کامل باشد، ولی فرستادنِ شمارش با نام، جای آرگومانِ موقعیتی را پُر نمیکند. سه مقدارِ موقعیتی هم در این امضا جایی ندارند؛ ستاره اجازه نمیدهد آفست را با تکیه بر ترتیب عبور دهیم. اگر بهره یک بار موقعیتی و بارِ دیگر با نام برسد، یک جایگاه دو مقدار گرفته است. برنامه برای این خطاها پیامِ کتابخانه را به عنوانِ شناسهٔ پایدار ذخیره نمیکند؛ فقط ردهٔ خطا و نبودِ طرحِ پذیرفتهشده را میسنجد.
بخشِ کاملِ فراخوانیها در مرجعِ زبان، جایگاهِ پُرشده، مقدارِ تکراری، پیشفرض و آرگومانِ ناشناخته را شرح میدهد. ورودیِ نامدارِ برنامهٔ ما زوجها را تا زمانِ بررسی نگه میدارد؛ پس دو زوجِ همنام پیش از تبدیل به دیکشنری رد میشوند. این قاعدهٔ پذیرشِ درخواست را خودمان افزودهایم. اگر از ابتدا یک دیکشنری ساخته و مقدارِ قبلی را جایگزین کرده باشیم، دیگر نمیتوان تاریخچهٔ آن تکرار را از دیکشنریِ نهایی بازیابی کرد.
۳. bind و پیشفرضها، بدون ورود به بدنه

با signature فقط امضای همین تابعِ ساده و مورداعتماد را میگیریم. سپس bind آرگومانهای دادهشده را به پارامترها نسبت میدهد یا خطای نوع ایجاد میکند. نتیجهٔ اولیه فقط مقدارهای صریح را دارد. در شاهدِ شمارشِ سه و کانالِ صفر، بهره و آفست هنوز در نگاشتِ نتیجه نیستند. پس از apply_defaults، بهرهٔ دو و آفستِ صفر نیز افزوده میشوند؛ وجودِ پیشفرض در تعریف با حضورِ آن در نگاشتِ اولیه یکی نیست.
مقدارِ صریحِ None جایگاه را پُر میکند و علامتِ حذفِ آرگومان نیست. به همین دلیل افزودنِ پیشفرض، بهرهٔ برابرِ None را به دو تبدیل نمیکند. همچنین bind_partial عمداً میتواند پارامترهای اجباری را جا بگذارد. حتی پس از افزودنِ پیشفرضها، درخواستِ خالی هنوز شمارش و کانال ندارد. این خروجی برای ساختِ تدریجیِ یک درخواست مفید است، اما در قراردادِ ما طرحِ آمادهٔ اجرا محسوب نمیشود.
پذیرشِ شکل، اعتبارِ مقدار نیست. در شاهدِ جدا، رشتهای به جای شمارش به امضا متصل میشود، ولی شرطِ نوعِ دقیقِ برنامه آن را رد میکند. محدودیتِ عددی و ردِ مقدارِ منطقی، زیرکلاس و تبدیلِ ضمنی را صریح نوشتهایم. این مسئولیت با اعتبارسنجیِ رکوردِ dataclass خویشاوند است، اما این بار ساختِ شیء یا رفتارِ frozen موضوعِ درس نیست؛ جایگاهِ بررسیِ مقدار پس از تشخیصِ شکلِ درخواست است.
این مراحل بدنهٔ تابعِ ثابت را اجرا نمیکنند. شمارندهٔ آموزشی، آمادهسازی را از فراخوانیِ صریح جدا نشان میدهد. بااینحال، این نتیجه را به دروننگریِ هر شیءِ ناشناس تعمیم نمیدهیم: مستندات برای امضای سفارشی، حاشیهنویسیها و بعضی فراخواندنیها ملاحظاتِ دیگری دارند. خودِ عبارتهای آرگومان نیز پیش از تلاشِ فراخوانی ارزیابی میشوند. مثالِ حاضر تنها دادههای ازپیشساخته را میپذیرد و جعبهٔ ایمنیِ اجرای افزونه یا کدِ نامطمئن نیست.
۴. کدِ کامل و مرجعِ مستقلِ جایگاهها

مرجعِ مستقل، برای همین امضای محدود یک دستورِ زبانِ کوچک دارد: شمارش باید موقعیتی باشد، بهره تنها یک منبع داشته باشد، کانال حاضر باشد و نامِ ناشناخته وجود نداشته باشد. سپس پیشفرضهای صریح و جدولِ مستقلِ بازهها را اعمال میکند. در مسیرِ انتظار از inspect، تابعِ اصلیِ آمادهسازی یا اجرای بدنه استفاده نمیکنیم. این استقلال، محدود به قرارداد و خانوادهٔ متناهیِ آزمایش است؛ اثباتِ تمامِ زبان یا پیادهسازیِ پایتون نیست.
"""A bounded call-plan exercise for one trusted, authored plain function.
No arbitrary callable, expression, plugin, device or static type checker is run.
The body counter is an educational observation, not a hardware measurement.
"""
from inspect import signature, Parameter
from itertools import product
import json
import platform
import sys
MAX_POSITIONAL = 4
MAX_NAMED = 5
ORDER = ('counts', 'gain', 'offset_mv', 'channel')
_BODY_ENTRIES = 0
def synthetic_voltage(counts: int, /, gain: int = 2, *,
offset_mv: int = 0, channel: int) -> int:
"""Authored arithmetic in mV; not a sensor or calibration implementation."""
global _BODY_ENTRIES
_BODY_ENTRIES += 1
return counts * gain + offset_mv
SIGNATURE = signature(synthetic_voltage)
def _envelope(positional, named):
"""Accept only bounded already-materialized requests, without coercion."""
if type(positional) is not tuple or type(named) is not tuple:
raise TypeError('request parts must be exact tuples')
if len(positional) > MAX_POSITIONAL or len(named) > MAX_NAMED:
raise ValueError('request exceeds authored envelope caps')
seen = set()
for pair in named:
if type(pair) is not tuple or len(pair) != 2:
raise TypeError('each named entry must be an exact pair tuple')
key = pair[0]
if type(key) is not str:
raise TypeError('keyword names must be exact strings')
if not 1 <= len(key) <= 16 or not key.isascii():
raise ValueError('keyword spelling outside authored envelope')
if key in seen:
raise ValueError('duplicate named entry before dict construction')
seen.add(key)
def _values(values):
if any(type(value) is not int for value in values):
raise TypeError('parameters require exact ints, not annotations alone')
counts, gain, offset_mv, channel = values
if not (0 <= counts <= 6 and 1 <= gain <= 4
and -3 <= offset_mv <= 3 and 0 <= channel <= 2):
raise ValueError('parameters outside authored integer domains')
return tuple(value for value in values)
def prepare_call(positional, named):
"""Return an immutable canonical value plan; do not enter the fixed body."""
_envelope(positional, named)
bound = SIGNATURE.bind(*positional, **dict(named))
bound.apply_defaults()
return _values(tuple(bound.arguments[name] for name in ORDER))
def invoke_plan(plan):
"""An explicit, separate body call, only for a validated four-value plan."""
if type(plan) is not tuple or len(plan) != 4:
raise TypeError('plan must be an exact four-value tuple')
counts, gain, offset_mv, channel = _values(plan)
return synthetic_voltage(counts, gain, offset_mv=offset_mv, channel=channel)
def _observe(positional, named):
try:
return ('ok', prepare_call(positional, named))
except (TypeError, ValueError) as error:
return (type(error).__name__, None)
def _slot_grammar_reference(positional, named):
"""Finite-family oracle: direct fixed-slot rules, no inspect or main calls.
Family inputs are already tuples with distinct keys and small integers.
This reference intentionally does not reuse either production validator.
"""
table = dict(named)
if len(positional) not in (1, 2):
return ('TypeError', None)
if any(key not in ('gain', 'offset_mv', 'channel') for key in table):
return ('TypeError', None)
if 'channel' not in table or (len(positional) == 2 and 'gain' in table):
return ('TypeError', None)
result = (positional[0],
positional[1] if len(positional) == 2 else table.get('gain', 2),
table.get('offset_mv', 0), table['channel'])
limits = ((0, 6), (1, 4), (-3, 3), (0, 2))
if any(not lower <= value <= upper
for value, (lower, upper) in zip(result, limits)):
return ('ValueError', None)
return ('ok', result)
def _rejects(call, kind):
try:
call()
except kind:
return True
return False
def run_example():
manual = prepare_call((3,), (('offset_mv', 1), ('channel', 0)))
alternate = prepare_call((3, 4), (('channel', 2), ('offset_mv', -1)))
manual_mv, alternate_mv = invoke_plan(manual), invoke_plan(alternate)
kinds = [(name, value.kind, value.default)
for name, value in SIGNATURE.parameters.items()]
expected_kinds = [
('counts', Parameter.POSITIONAL_ONLY, Parameter.empty),
('gain', Parameter.POSITIONAL_OR_KEYWORD, 2),
('offset_mv', Parameter.KEYWORD_ONLY, 0),
('channel', Parameter.KEYWORD_ONLY, Parameter.empty),
]
before_defaults = SIGNATURE.bind(3, channel=0)
explicit_before = dict(before_defaults.arguments)
projection_before = (before_defaults.args, before_defaults.kwargs)
before_defaults.apply_defaults()
explicit_after = dict(before_defaults.arguments)
projection_after = (before_defaults.args, before_defaults.kwargs)
partial = SIGNATURE.bind_partial()
partial.apply_defaults()
none_bound = SIGNATURE.bind(3, gain=None, channel=0)
none_bound.apply_defaults()
annotated_wrong = SIGNATURE.bind('3', channel=0)
annotated_wrong.apply_defaults()
# A valid shape is also not a promise of successful body execution.
class BodyFailure(Exception):
pass
sentinel = BodyFailure('authored body probe, not an external failure')
body_probe_calls = []
def raises_in_body(counts: int, /, gain: int = 2, *,
offset_mv: int = 0, channel: int) -> int:
body_probe_calls.append((counts, gain, offset_mv, channel))
raise sentinel
probe_bound = signature(raises_in_body).bind(3, channel=0)
probe_bound.apply_defaults()
probe_calls_before_explicit_call = len(body_probe_calls)
same_body_error = False
try:
raises_in_body(*probe_bound.args, **probe_bound.kwargs)
except BodyFailure as error:
same_body_error = error is sentinel
body_before_prepare = _BODY_ENTRIES
prepared_only = prepare_call((2,), (('channel', 1),))
SIGNATURE.bind(2, channel=1).apply_defaults()
body_after_prepare = _BODY_ENTRIES
shape_rejections = (
((), (('channel', 0),)),
((1,), ()),
((1, 2, 3), (('channel', 0),)),
((1,), (('counts', 2), ('channel', 0))),
((1, 2), (('gain', 3), ('channel', 0))),
((1,), (('spare', 0), ('channel', 0))),
)
# Exactly one finite family, with a separate fixed-slot grammar reference.
family_count = 0
statuses = {'ok': 0, 'TypeError': 0, 'ValueError': 0}
family_passed = True
family_body_before = _BODY_ENTRIES
keys = ('counts', 'gain', 'offset_mv', 'channel', 'spare')
for length in range(5):
for positional in product((0, 2), repeat=length):
for choices in product((None, 0, 2), repeat=len(keys)):
named = tuple((key, value) for key, value in zip(keys, choices)
if value is not None)
actual = _observe(positional, named)
expected = _slot_grammar_reference(positional, named)
family_passed = family_passed and actual == expected
statuses[actual[0]] += 1
family_count += 1
family_body_after = _BODY_ENTRIES
class IntChild(int):
pass
class TupleChild(tuple):
pass
class StrChild(str):
pass
coercion_calls = []
class CoercionProbe:
def __int__(self):
coercion_calls.append('int')
return 1
wrong_values = (True, False, 1.0, '1', None, IntChild(1), CoercionProbe())
numeric_types_rejected = all(
_rejects(lambda value=value: prepare_call((value,), (('channel', 0),)),
TypeError) for value in wrong_values)
boundary_plans = ((0, 1, -3, 0), (6, 4, 3, 2))
boundary_passed = all(prepare_call((a, b), (('offset_mv', c), ('channel', d)))
== (a, b, c, d) for a, b, c, d in boundary_plans)
outside_plans = ((-1, 1, 0, 0), (7, 1, 0, 0), (1, 0, 0, 0),
(1, 5, 0, 0), (1, 1, -4, 0), (1, 1, 4, 0),
(1, 1, 0, -1), (1, 1, 0, 3))
numeric_bounds_rejected = all(_rejects(
lambda p=p: prepare_call((p[0], p[1]),
(('offset_mv', p[2]), ('channel', p[3]))),
ValueError) for p in outside_plans)
invalid_envelopes = (
([], ()), ((1,), {}), (TupleChild((1,)), ()),
((1,), TupleChild(())), ((1,), (['channel', 0],)),
((1,), (('channel',),)), ((1,), ((2, 0),)),
((1,), ((StrChild('channel'), 0),)),
)
too_large_envelopes = (((1,) * 5, ()),
((1,), tuple(('k' + str(i), 0) for i in range(6))),
((1,), (('', 0),)),
((1,), (('x' * 17, 0),)),
((1,), (('\u03b1', 0),)))
generator_pulls = []
def values_generator():
generator_pulls.append('pulled')
yield 1
generator = values_generator()
generator_rejected = _rejects(
lambda: prepare_call(generator, (('channel', 0),)), TypeError)
generator.close()
positional, named = (3,), (('channel', 1), ('gain', 4), ('offset_mv', -2))
saved_request = (positional, named)
first = prepare_call(positional, named)
second = prepare_call(positional, tuple(reversed(named)))
mutation_rejected = _rejects(lambda: first.__setitem__(0, 9), AttributeError)
before_bad_invocation = _BODY_ENTRIES
bad_plan_rejected = _rejects(lambda: invoke_plan((3, 0, 0, 0)), ValueError)
after_bad_invocation = _BODY_ENTRIES
checks = {
'fixed_parameter_kinds_order_and_defaults_match_literal_contract':
kinds == expected_kinds,
'manual_plans_and_explicit_synthetic_mV_results_match_hand_values':
manual == (3, 2, 1, 0) and alternate == (3, 4, -1, 2)
and (manual_mv, alternate_mv) == (7, 11),
'positional_or_keyword_gain_and_named_order_have_one_canonical_plan':
first == second == (3, 4, -2, 1)
and prepare_call((3, 4), (('offset_mv', -2), ('channel', 1))) == first,
'missing_duplicate_unknown_and_wrong_positions_rejected_one_family':
all(_observe(a, b) == ('TypeError', None) for a, b in shape_rejections),
'defaults_are_absent_until_apply_defaults_and_projections_are_explicit':
explicit_before == {'counts': 3, 'channel': 0}
and projection_before == ((3,), {'channel': 0})
and explicit_after == {'counts': 3, 'gain': 2, 'offset_mv': 0,
'channel': 0}
and projection_after == ((3, 2), {'offset_mv': 0, 'channel': 0}),
'bind_partial_plus_defaults_is_not_a_complete_ready_call':
partial.arguments == {'gain': 2, 'offset_mv': 0}
and _rejects(lambda: SIGNATURE.bind(), TypeError),
'valid_shape_is_neither_type_validation_nor_body_success':
annotated_wrong.arguments['counts'] == '3'
and _rejects(lambda: prepare_call(('3',), (('channel', 0),)), TypeError)
and probe_calls_before_explicit_call == 0
and same_body_error and len(body_probe_calls) == 1,
'explicit_None_is_not_replaced_by_a_default_and_own_policy_rejects_it':
none_bound.arguments['gain'] is None and none_bound.args == (3, None)
and _rejects(lambda: prepare_call((3,), (('gain', None),
('channel', 0))), TypeError),
'preparation_and_default_application_do_not_enter_fixed_body':
prepared_only == (2, 2, 0, 1)
and body_before_prepare == body_after_prepare,
'finite_slot_grammar_family_matches_without_inspect_in_expected_path':
family_passed and family_count == 7533
and statuses == {'ok': 36, 'TypeError': 7473, 'ValueError': 24}
and family_body_before == family_body_after,
'outer_exact_types_and_caps_checked_without_consuming_generator':
all(_rejects(lambda a=a, b=b: prepare_call(a, b), TypeError)
for a, b in invalid_envelopes)
and all(_rejects(lambda a=a, b=b: prepare_call(a, b), ValueError)
for a, b in too_large_envelopes)
and generator_rejected and generator_pulls == [],
'duplicate_named_entries_rejected_before_silent_dict_collapse':
_rejects(lambda: prepare_call((1,), (('channel', 0),
('channel', 1))), ValueError)
and _rejects(lambda: prepare_call((1,), (('gain', 2), ('gain', 3),
('channel', 0))), ValueError),
'numeric_domains_are_closed_exact_int_and_never_coerce':
numeric_types_rejected and boundary_passed and numeric_bounds_rejected
and coercion_calls == [] and bad_plan_rejected
and before_bad_invocation == after_bad_invocation,
'accepted_plans_are_fresh_immutable_and_request_tuples_unchanged':
type(first) is type(second) is tuple and first is not second
and mutation_rejected and (positional, named) == saved_request,
}
assert len(checks) == 14 and all(type(value) is bool and value
for value in checks.values()), checks
return {
'python': platform.python_version(),
'implementation': platform.python_implementation(),
'model': 'fixed_plain_function_call_shape_then_authored_value_domain',
'function_signature': str(SIGNATURE),
'canonical_parameter_order': ORDER,
'manual': {'plan': manual, 'explicit_result_mV': manual_mv,
'alternate_plan': alternate, 'alternate_result_mV': alternate_mv},
'default_observation': {'explicit_before': explicit_before,
'after_apply_defaults': explicit_after},
'partial_after_defaults_still_missing_counts_and_channel': partial.arguments,
'fixed_body_entries_during_prepare_probe': body_after_prepare - body_before_prepare,
'fixed_body_entries_during_finite_family': family_body_after - family_body_before,
'authored_raising_body_probe': {'calls_before_explicit_invocation':
probe_calls_before_explicit_call,
'actual_calls': len(body_probe_calls),
'same_exception_instance': same_body_error},
'case_counts_not_extra_groups': {'finite_slot_grammar_profiles': family_count,
'family_statuses': statuses,
'manual_shape_rejections': len(shape_rejections),
'invalid_envelope_type_profiles': len(invalid_envelopes),
'invalid_envelope_bounds': len(too_large_envelopes),
'invalid_numeric_types': len(wrong_values),
'numeric_outside_cases': len(outside_plans)},
'scope': 'materialized bounded requests, one fixed plain function, authored units',
'hardware_or_calibration_performed': False,
'static_type_checker_executed': False,
'arbitrary_callable_introspection_claimed_safe': False,
'checks': checks,
}
if __name__ == '__main__':
result = run_example()
sys.stdout.buffer.write((json.dumps(result, ensure_ascii=True, indent=2,
allow_nan=False) + '\n').encode('utf-8'))
{
"python": "3.14.5",
"implementation": "CPython",
"model": "fixed_plain_function_call_shape_then_authored_value_domain",
"function_signature": "(counts: int, /, gain: int = 2, *, offset_mv: int = 0, channel: int) -> int",
"canonical_parameter_order": [
"counts",
"gain",
"offset_mv",
"channel"
],
"manual": {
"plan": [
3,
2,
1,
0
],
"explicit_result_mV": 7,
"alternate_plan": [
3,
4,
-1,
2
],
"alternate_result_mV": 11
},
"default_observation": {
"explicit_before": {
"counts": 3,
"channel": 0
},
"after_apply_defaults": {
"counts": 3,
"gain": 2,
"offset_mv": 0,
"channel": 0
}
},
"partial_after_defaults_still_missing_counts_and_channel": {
"gain": 2,
"offset_mv": 0
},
"fixed_body_entries_during_prepare_probe": 0,
"fixed_body_entries_during_finite_family": 0,
"authored_raising_body_probe": {
"calls_before_explicit_invocation": 0,
"actual_calls": 1,
"same_exception_instance": true
},
"case_counts_not_extra_groups": {
"finite_slot_grammar_profiles": 7533,
"family_statuses": {
"ok": 36,
"TypeError": 7473,
"ValueError": 24
},
"manual_shape_rejections": 6,
"invalid_envelope_type_profiles": 8,
"invalid_envelope_bounds": 5,
"invalid_numeric_types": 7,
"numeric_outside_cases": 8
},
"scope": "materialized bounded requests, one fixed plain function, authored units",
"hardware_or_calibration_performed": false,
"static_type_checker_executed": false,
"arbitrary_callable_introspection_claimed_safe": false,
"checks": {
"fixed_parameter_kinds_order_and_defaults_match_literal_contract": true,
"manual_plans_and_explicit_synthetic_mV_results_match_hand_values": true,
"positional_or_keyword_gain_and_named_order_have_one_canonical_plan": true,
"missing_duplicate_unknown_and_wrong_positions_rejected_one_family": true,
"defaults_are_absent_until_apply_defaults_and_projections_are_explicit": true,
"bind_partial_plus_defaults_is_not_a_complete_ready_call": true,
"valid_shape_is_neither_type_validation_nor_body_success": true,
"explicit_None_is_not_replaced_by_a_default_and_own_policy_rejects_it": true,
"preparation_and_default_application_do_not_enter_fixed_body": true,
"finite_slot_grammar_family_matches_without_inspect_in_expected_path": true,
"outer_exact_types_and_caps_checked_without_consuming_generator": true,
"duplicate_named_entries_rejected_before_silent_dict_collapse": true,
"numeric_domains_are_closed_exact_int_and_never_coerce": true,
"accepted_plans_are_fresh_immutable_and_request_tuples_unchanged": true
}
}
چهارده گروهِ نامدار، شاهدهای دستی، پیشفرض و مقدارِ صریح، درخواستِ ناقص، خطاهای چیدمان، محدودیتِ پاکت، نوع و بازه، عدمِ مصرفِ مولد و تازگیِ طرح را در بر میگیرند. هفتهزار و پانصد و سیوسه پروفایلِ کوچک فقط یک گروهِ مقایسه با مرجعاند. آمادهسازیِ تمامِ آن خانواده، شمارندهٔ بدنه را افزایش نمیدهد. دو محاسبهٔ صریحِ دستی نیز هفت و یازده میلیولتِ قراردادی میدهند؛ این اعداد دادهٔ اندازهگیریشده نیستند.
تابعِ آزمایشیِ دیگری با شکلِ معتبر عمداً در بدنه استثنا میدهد. پیش از فراخوانیِ صریح، شمارندهاش صفر است؛ پس از آن، همان شیءِ استثنا با یک ورود به بدنه مشاهده میشود. این شاهدِ کنترلشده خطای فرایندِ اجرای مقاله نیست و موفقیتِ نگاشت را به موفقیتِ محاسبه تبدیل نمیکند. منابعِ جاری با برچسبِ مستنداتِ ۳٫۱۴٫۹ خوانده شدهاند؛ اجرای همراه با CPython ۳٫۱۴٫۵ ثبت میشود. خبری از سنجشِ سرعت، سرویس، ابزارِ بررسیِ ایستا یا دستگاه نیست.
۵. چهار پرسش دربارهٔ نوع، مقدار و اجرا

پرسش اول: چرا نوشتنِ counts به عنوانِ کلید، درخواست را کامل نمیکند؟ پاسخ: در این تابع، آن پارامتر پیش از خطِ مورب است و تنها جایگاهِ موقعیتی دارد. کانال برعکس، فقط با نام داده میشود. این دو محدودیت به مقدارِ عدد وابسته نیستند؛ عددِ مجاز هم اگر در مسیرِ نامناسب برسد، شکلِ فراخوانی را اصلاح نمیکند.
پرسش دوم: آیا برای بهرهٔ None باید پیشفرض را خودکار جایگزین کنیم؟ پاسخ: خیر؛ این کار معنای ورودیِ صریح را تغییر میدهد. bind آن مقدار را نگه میدارد و سیاستِ عددیِ ما آن را رد میکند. اگر برنامهای None را فرمانِ انتخابِ پیشفرض میداند، باید قراردادِ جدا و آزمونِ مستقلِ همان تبدیل را تعریف کند؛ آن رفتار از apply_defaults به دست نمیآید.
پرسش سوم: چرا نتیجهٔ bind_partial را مستقیم اجرا نکنیم؟ پاسخ: نبودنِ خطا هنگامِ اتصالِ جزئی، حضورِ همهٔ پارامترهای لازم را تضمین نمیکند. پیشفرض هم برای پارامترِ اجباریِ بدونِ پیشفرض مقداری اختراع نمیکند. مرزِ اجرای این مثال فقط طرحِ کامل و دارای مقدارهای مجاز را میپذیرد؛ فراخواننده باید میانِ پیشنویسِ درخواست و درخواستِ آماده تفاوت بگذارد.
پرسش چهارم: آیا طرحِ معتبر، نتیجهٔ درستِ مهندسی را تضمین میکند؟ پاسخ: فقط چیدمان و دامنهٔ تألیفیِ همان ورودی بررسی شده است. تابع هنوز باید صریح اجرا شود و ممکن است بدنه خطا بدهد. برچسبِ میلیولت، بهرهٔ درستِ یک دستگاه یا صحتِ داده را تضمین نمیکند. برای گسترش، ابتدا تابع و واحدها را عوض کنید و سپس مرجع و شاهدهای مخالف را بازنویسی کنید؛ موفقیتِ این مجموعه مجوزِ حذفِ آزمونِ لایهٔ بعد نیست.
منابع و مطالعهٔ بیشتر
- Python3.14.9؛ Signature و bind و BoundArguments و پیشفرضها
- مرجع زبان Python3.14.9؛ نگاشت آرگومانها در فراخوانی
بررسی منابع: ۲۹ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.

