關聯式註釋
PyBryt 中最基本的註釋種類是值註釋,其會判斷學生記憶體使用量中存在一些值。 不過,這些註釋並不涵蓋所有案例;如果您想要檢查某些值的兩個可能表示,或想要檢查值的順序,該怎麼辦? 這些情況就是關聯式註釋的用武之地。
關聯式註釋會定義其他註釋之間的某種關聯性。 您可以將關聯式註釋視為對其他註釋上運作的註釋,判斷如何滿足註釋的條件。 在上一個課程模組中,您已了解集合註釋,以及如何使用這些註釋來強制執行註釋的排序。 關聯式註釋很類似,事實上,您可以將集合視為關聯式註釋的類型。
PyBryt 目前支援兩種類型的關聯式註釋:時態性註釋和邏輯註釋。
時態性註釋
時態性註釋述不同註釋之間的時態關聯性。 滿足這些註釋的所有子註釋,而且滿足這些註釋之值的時間戳記會以特定順序發生時,就會滿足這些註釋。
PyBryt 只具有一種時態性註釋類型:BeforeAnnotation
,其會判斷滿足其子註釋的時間戳記會以非遞減順序發生。 就像任何其他註釋一樣,您可以直接使用建構函式來具現化這些註釋,不過所有註釋也有 before
和 after
方法,可用來以更語意的方式建構這些註釋:
>>> a1 = pybryt.Value(1)
>>> a2 = pybryt.Value(2)
>>> a1.before(a2), a1.after(a2)
(pybryt.BeforeAnnotation, pybryt.BeforeAnnotation)
如您所見,Annotation.before
和 Annotation.after
會傳回 BeforeAnnotation
,但註釋的順序會在 after
所傳回的註釋中反轉。
當您建立關聯式註釋時,您可以視需要更新每個註釋選項的欄位,或將選項當做關鍵字引數傳遞至 before
或 after
方法:
a1_before_a2 = a1.before(
a2,
success_message="a1 is before a2",
failure_message="a1 is not before a2",
)
# or:
a1_before_a2 = a1.before(a2)
a1_before_a2.success_message = "a1 is before a2"
a1_before_a2.failure_message = "a1 is not before a2"
透過虛擬記憶體使用量,我們可以看到滿足 BeforeAnnotation
的方式。 在下列範例中,我們會使用 pybryt.MemoryFootprint.from_values
方法建立這類使用量,此方法接受替代的值和時間戳記:
pybryt.MemoryFootprint.from_values(val1, ts1, val2, ts2, val3, ts3, ...)
在我們變更使用量及其時間戳記中的值時,請注意關聯式註釋的結果會如何改變。
>>> ref = pybryt.ReferenceImplementation("temporal-annotations", [a1_before_a2])
>>> # the values in the correct order
>>> res = ref.run(pybryt.MemoryFootprint.from_values(1, 1, 2, 2))
>>> print(pybryt.generate_report(res))
REFERENCE: temporal-annotations
SATISFIED: True
MESSAGES:
- a1 is before a2
>>> # put both values at the same timestamp
>>> res = ref.run(pybryt.MemoryFootprint.from_values(1, 1, 2, 1))
>>> print(pybryt.generate_report(res))
REFERENCE: temporal-annotations
SATISFIED: True
MESSAGES:
- a1 is before a2
>>> # put the timestamp of 1 after the timestamp of 2
>>> res = ref.run(pybryt.MemoryFootprint.from_values(1, 2, 2, 1))
>>> print(pybryt.generate_report(res))
REFERENCE: temporal-annotations
SATISFIED: False
MESSAGES:
- a1 is not before a2
>>> # don't satisfy the second annotation
>>> res = ref.run(pybryt.MemoryFootprint.from_values(1, 1))
>>> print(pybryt.generate_report(res))
REFERENCE: temporal-annotations
SATISFIED: False
MESSAGES:
- a1 is not before a2
邏輯註釋
邏輯註釋與滿足註釋時的時態性無關,而是會對是否完全滿足註釋進行處理。 其會判斷是否滿足子註釋的條件,可讓您在參考中建構複雜的布林邏輯,以允許到達相同解決方案的多個路徑。
若要建立邏輯註釋,請在任何注釋上使用 Python 的位元邏輯運算子:
>>> a1 & a2, a1 | a2, a1 ^ a2
(pybryt.AndAnnotation, pybryt.OrAnnotation, pybryt.XorAnnotation)
若要建立涉及兩個以上註釋的條件,您可以鏈結運算子,或直接使用這些註釋的子註釋具現化註釋。 與時態性註釋類似,可以藉由更新註釋物件上的對應屬性來設定邏輯註釋的選項。
a3 = pybryt.Value(3)
all_anns = a1 & a2 & a3
all_anns.success_message = "Found a1, a2, and a3"
all_anns.failure_message = "Did not find a1, a2, and a3"
any_anns = a1 | a2 | a3
any_anns.success_message = "Found a1, a2, or a3"
any_anns.failure_message = "Did not find a1, a2, or a3"
one_ann = a1 ^ a2 ^ a3
one_ann.success_message = "Found exactly of a1, a2, or a3"
one_ann.failure_message = "Did not find exactly one of a1, a2, or a3"
PyBryt 也支援 not (~
) 運算子,以產生只有在不符合其子註釋時才會滿足的註釋。 例如,如果他們的記憶體使用量中有一個不應該存在的特定值,這些註釋可以用來向學生傳送訊息:
not_lst = ~pybryt.Value(lst)
not_lst.failure_message = "Found an incorrect value in your submission; " + \
"please double-check your implementation."
如果上述註釋在記憶體使用量中找到值 lst
,則會提供訊息給學生。 在 pybryt.Value
建構函式中設定 success_message
,即可達到相同的效果。