Следующее решение использует константы в объектах кода для определения значений bool True / False и инструкцию байт-кода 'COMPARE_OP'
для идентификации операции сравнения.Код может быть улучшен, чтобы добавить больше случаев, но это просто, чтобы дать вам преимущество.Чтобы показать все условия, я установил все аргументы в функции как необязательные:
In [130]: def catch_trick_bool(unit_test_result=None, student_compare=None,student_trick=None):
...: student = str(input("Enter student name: "))
...: # import dis - Use this to further examine code objects.
...: # Eg. use dis.dis(co_unit_test) to view the code objects for
...: # the unit test expresssion
...: if unit_test_result:
...: co_unit_test = compile(unit_test_result, 'none', 'single')
...: if False in co_unit_test.co_consts:
...: print("Bool value 'False' returned from Unit Test")
...: elif student_compare:
...: co_student_compare = compile(student_compare, 'none', 'single')
...: if '6b' in co_student_compare.co_code.hex():
...: print("Student {} performed the comparison successfully".format(student))
...: else:
...: co_student_trick = compile(student_trick, 'none', 'single')
...: if False in co_student_trick.co_consts:
...: print("Student {} tried to set a bool value of 'False' for the test".format(student))
...:
In [131]: catch_trick_bool(unit_test_result='is_identical_unit_test = False')
Enter student name: John
Bool value 'False' returned from Unit Test
In [132]: catch_trick_bool(student_trick='is_identical_student_trick = False')
Enter student name: John
Student John tried to set a bool value of 'False' for the test
In [133]: catch_trick_bool(student_compare='id(x) == id(y)')
Enter student name: John
Student John performed the comparison successfully
Пояснение :
Ниже показано, как шестнадцатеричный байт-код 0x6b
ищется в шестнадцатеричном представлении инструкции байт-кода для объекта кода.Этот байт-код соответствует операционному имени 'COMPARE_OP'
.Эта инструкция указывает на операцию сравнения в коде.
In [137]: co = compile('is_identical = id(x) == id(y)', 'none', 'single')
In [138]: type(co)
Out[138]: code
In [139]: dis.dis(co)
1 0 LOAD_NAME 0 (id)
2 LOAD_NAME 1 (x)
4 CALL_FUNCTION 1
6 LOAD_NAME 0 (id)
8 LOAD_NAME 2 (y)
10 CALL_FUNCTION 1
12 COMPARE_OP 2 (==)
14 STORE_NAME 3 (is_identical)
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
In [140]: co.co_code
Out[140]: b'e\x00e\x01\x83\x01e\x00e\x02\x83\x01k\x02Z\x03d\x00S\x00'
In [141]: co.co_code.hex()
Out[141]: '6500650183016500650283016b025a0364005300'
In [142]: dis.opname[0x6b]
Out[142]: 'COMPARE_OP'
In [143]: '6b' in co.co_code.hex()
Out[143]: True
In [144]: co2 = compile('is_identical = 5 > 2', 'none', 'single')
In [145]: co2.co_code.hex()
Out[145]: '640064016b045a0064025300'
In [146]: '6b' in co2.co_code.hex()
Out[146]: True
Аналогично, значения bool преобразуются в инструкции LOAD_CONST
bytecode, к которым можно легко получить доступ с помощью co_consts
:
In [147]: co3 = compile('is_identical = False', 'none', 'single')
In [148]: dis.dis(co3)
1 0 LOAD_CONST 0 (False)
2 STORE_NAME 0 (is_identical)
4 LOAD_CONST 1 (None)
6 RETURN_VALUE
In [149]: co3.co_consts
Out[149]: (False, None)
In [150]: False in co3.co_consts
Out[150]: True
Заключение :
Объекты дизассемблированного кода могут помочь определить источник значения bool.Если оно явно определено, как в приведенном выше случае, значение bool будет разрешено как константа LOAD_CONST
инструкция байт-кода.Если он выводится неявно через логическое выражение, которое использует сравнение (например, 5> 2), код будет преобразован в конкретную инструкцию байт-кода COMPARE_OP
, чтобы указать операцию сравнения.Вы можете дополнительно расширить код, чтобы также проверить достоверность значений и изменить его в соответствии с вашими требованиями.