註釋選項
所有注釋都有一些常見的選項;在最後一個課程模組中,您已瞭解 success_message
和 failure_message
選項。 在本課程模組中,我們會討論可套用至註釋的三個選項,以及其使用方式。
name
選項 name
可用來將代表相同註釋的不同註釋類別執行個體分組在一起。 此選項主要用於防止訊息在不需要時顯示多次。 讓我們考慮下列範例:maximum
函式會呼叫 Python 的 max
函式,以檢查學生是否已正確識別出最大值,但會針對函式測試的每個輸入列印一次成功訊息。
>>> max_ref = []
>>> def maximum(l, track=False):
... m = max(l)
... if track:
... max_ref.append(pybryt.Value(
... m,
... success_message="Found the max!",
... failure_message="Did not find the max",
... ))
... return m
>>> test_lists = [[1, 2, 3], [-1, 0, 1], [10, -4, 2, 0], [1]]
>>> for test_list in test_lists:
... maximum(test_list, track=True)
>>> max_ref = pybryt.ReferenceImplementation("maximum", max_ref)
>>> with pybryt.check(max_ref):
... for test_list in test_lists:
... maximum(test_list)
REFERENCE: maximum
SATISFIED: True
MESSAGES:
- Found the max!
- Found the max!
- Found the max!
- Found the max!
這個函式的問題很簡單:每個測試中建立的註釋基本上都會檢查相同的項目,無論學生是否傳回正確的值。 若列印相同的訊息多次,看起來會像是註釋在測試不同的條件,也會讓 PyBryt 所產生的報表雜亂。 我們可以藉由命名在 maximum
函式中建立的註釋,將所有這些訊息摺疊在一起:
>>> max_ref = []
>>> def maximum(l, track=False):
... m = max(l)
... if track:
... max_ref.append(pybryt.Value(
... m,
... name="list-maximum",
... success_message="Found the max!",
... failure_message="Did not find the max",
... ))
... return m
>>> test_lists = [[1, 2, 3], [-1, 0, 1], [10, -4, 2, 0], [1]]
>>> for test_list in test_lists:
... maximum(test_list, track=True)
>>> max_ref = pybryt.ReferenceImplementation("maximum", max_ref)
>>> with pybryt.check(max_ref):
... for test_list in test_lists:
... maximum(test_list)
REFERENCE: maximum
SATISFIED: True
MESSAGES:
- Found the max!
現在,我們可以看到訊息只會列印一次。
若是 PyBryt 將註釋摺疊成單一訊息,則只有在滿足名稱群組中的所有註釋時,才會顯示成功訊息。 如果群組中有任何測試失敗,則會改為顯示失敗訊息。 讓我們將一個 Bug 導入 maximum
來示範:
>>> def maximum(l):
... if len(l) % 2 == 0:
... m = min(l)
... else:
... m = max(l)
... return m
>>> with pybryt.check(max_ref):
... for test_list in test_lists:
... maximum(test_list)
REFERENCE: maximum
SATISFIED: False
MESSAGES:
- Did not find the max
limit
選項 limit
可讓您控制參考實作中包含多少個具名註釋複本。 此選項可協助建構註釋的函式在整個指派中重複使用多次的情況。 一些初始測試就足以藉由減少參考實作本身的大小,來檢查實作的有效性。
讓我們使用 maximum
函式來說明這一點。 我們在此將使用與之前參考類似的實作,但設定 limit
為五個註釋,並在數個輸入清單上進行測試。
>>> max_ref = []
>>> def maximum(l, track=False):
... m = max(l)
... if track:
... max_ref.append(pybryt.Value(
... m,
... name="list-maximum",
... limit=5,
... success_message="Found the max!",
... failure_message="Did not find the max",
... ))
... return m
>>> for _ in range(1000):
... test_list = np.random.normal(size=100)
... maximum(test_list, track=True)
>>> print(f"Annotations created: {len(max_ref)}")
>>> max_ref = pybryt.ReferenceImplementation("maximum", max_ref)
>>> print(f"Annotations in reference: {len(max_ref.annotations)}")
Annotations created: 1000
Annotations in reference: 5
如您所見,即使傳遞至建構函式的清單中包含 1,000 個註釋,max_ref.annotations
的長度仍為 5。
group
選項 group
類似於 name
選項,因為該選項用來將註釋分組在一起,但這些註釋不一定代表「相同的註釋」;相反地,這些註釋會分組成有意義的區塊,以便一次檢查一個特定的參考部分,而不是同時檢查全部參考。 此選項對於在 PyBryt 中建構有複數問題的指派時很有用。
例如,請考慮一個作業,要求學生實作 mean
和 median
函式。 您可以將該作業分成兩個問題,如下所示:
# Question 1
mean_ref = []
def mean(l, track=False):
size = len(l)
if track:
mean_ref.append(pybryt.Value(
size,
name="len",
group="mean",
success_message="Determined the length of the list",
))
m = sum(l) / size
if track:
mean_ref.append(pybryt.Value(
m,
name="mean",
group="mean",
success_message="Calculated the correct mean of the list",
failure_message="Did not find the correct mean of the list",
))
return m
# Question 2
median_ref = []
def median(l, track=True):
sorted_l = sorted(l)
if track:
median_ref.append(pybryt.Value(
sorted_l,
name="sorted",
group="median",
success_message="Sorted the list",
))
size = len(l)
if track:
mean_ref.append(pybryt.Value(
size,
name="len",
group="median",
success_message="Determined the length of the list",
))
middle = size // 2
is_set_size_even = size % 2 == 0
if is_set_size_even:
m = (sorted_l[middle - 1] + sorted_l[middle]) / 2
else:
m = sorted_l[middle]
if track:
mean_ref.append(pybryt.Value(
m,
name="mean",
group="mean",
success_message="Calculated the correct mean of the list",
failure_message="Did not find the correct mean of the list",
))
return m
test_lists = [[1, 2, 3], [-1, 0, 1], [10, -4, 2, 0], [1]]
for test_list in test_lists:
mean(test_list, track=True)
median(test_list, track=True)
assignment_ref = pybryt.ReferenceImplementation("mean-median", [*mean_ref, *median_ref])
透過上述範例建構的參考,我們可以讓學生有機會先檢查每個個別問題的工作,再繼續進行下一個問題,方法是告訴 PyBryt 要考慮的註釋群組:
>>> with pybryt.check(assignment_ref, group="mean"):
... for test_list in test_lists:
... mean(test_list)
REFERENCE: mean-median
SATISFIED: True
MESSAGES:
- Determined the length of the list
- Calculated the correct mean of the list
>>> with pybryt.check(assignment_ref, group="median"):
... for test_list in test_lists:
... median(test_list)
REFERENCE: mean-median
SATISFIED: True
MESSAGES:
- Determined the length of the list
- Sorted the list
>>> with pybryt.check(assignment_ref):
... for test_list in test_lists:
... mean(test_list)
... median(test_list)
REFERENCE: mean-median
SATISFIED: True
MESSAGES:
- Determined the length of the list
- Calculated the correct mean of the list
- Sorted the list