深入解析eval()函数与表达式转换问题及优化评测数据构造技巧
总体思路如上,这里有更多细节

1.1 关于eval()函数无法将包含前导0的字符串转换为表达式的问题
#去除前导0
str = re.sub(r'(?, "", str)
1.2 关于如果转换后的表达式是常量且被识别为int时,无法通过替换求值的问题。
#直接特判
if isinstance(expr,int):
result = expr
else:
#此处令x=2计算数值进行比较
result = expr.evalf(subs={x: 2})
1.3 关于管道的使用
#只是举个例子,说明.sh编写应有的样子
cat $InputFileName | while read line
do
...
correctOutput=$(echo "$line" | python diff.py)
result=$(echo "$myOutPut$space$correctOutput" | python compare.py)
...
done
1.4 sympy的简化方法降低了评估速度。不建议使用1.5关于评估数据的构建(以TaskTwo为例)
由于该任务只有幂函数、sin、cos这三个因素,所以作者选择其中的任意一两个,包括三个7模式来生成测试数据,并将几组指标分别设置为0。 1、-1数据(即将[0-9]全部替换为[0-1])
一些常规规则如下:
regex1 = "[+-][0-9](\\*x(\\*\\*[+-]?[0-9])?)*"
regex2 = "[+-][0-9](\\*sin\\(x\\)(\\*\\*[+-]?[0-9])?)*"
regex6 = "([+-][2-9])\\*sin\\(x\\)(\\*\\*[+-]?[2-9])?\\*cos\\(x\\)(\\*\\*[+-]?[2-9])?"
regex7 = "[+-][0-9]\\*x(\\*\\*[+-]?[0-9])?\\*[0-9]{1,2}\\*sin\\(x\\)(\\*\\*[+-]?[0-9])?"
regex10 = "[+-][0-1]{2,3}(\\*x(\\*\\*[+-]?[0-1])?)+(\\*sin\\(x\\)(\\*\\*[+-]?[0-9])?)+"
由于本次测试的测试数据最多不超过100个字符,因此建议将常数因子设置为个位数。
2.使用Junit
作者:乔盛业
//只是举个例子,Junit的组件还是很多的
import org.junit.Test;
import JUnitTestTools.EnhancedUserTestTools;
import java.io.File;
public class PolyTest {
@Test
public void main() throws Exception {
new EnhancedUserTestTools(Poly.class, 2000).testAll(new File("./test/poly/test1.txt"));
}
}
3.使用子流程
作者:冯天宇
3.1 关于subprocess的使用
我们可以通过调用 subprocess.Popen() 来运行我们的 java 程序。 Popen()提供stdin、stdout等参数。我们可以轻松地将输入和输出重定向到python中的文件对象,或者子进程。 PIPE,直接使用write()、readlines()等方法输入并获取输出。
让我们看一个例子:
from subprocess import Popen, PIPE
p = Popen(r'echo hahaha', stdout = PIPE, shell = True, text=True)
print(p.stdout.readline())
运行结果为:
hahaha
在本例中,我们将输出重定向到 PIPE,然后通过 PIPE 的 readline() 方法读取输出。 text=True参数可以帮助我们将PIPE的输入输出从字节流转换为str类型,以方便数据处理。
同样,如果输入被重定向到PIPE(stdin=PIPE),那么就可以通过p.stdin.write(str)向程序输入数据
3.2 测试流程
整体测试流程大致分为三个部分:测试用例生成、程序执行、运行结果验证。
在测试用例生成部分,我们使用xeger直接生成大量随机数据;
在执行程序部分,我们通过Popen调用Java程序;
在结果验证部分,我们使用sympy对原始表达式进行微分,并将导数结果与程序进行比较。
总体程序框架如下:
import ...
from ... import ...
caseSize = 100
cases = case_gen(caseSize, ...)#input list
p = Popen(r'java -classpath, '
stdin = PIPE, stdout = PIPE, shell = True, text=True)
for case in cases:
p.stdin.write(case)
out = p.stdout.readlines()#output list
ans = calcAns(cases)#answer list
for i in range(caseSize):
if (!equal(out[i],ans[i])):
print("" )
一些建议: 1、只有了解昂神团队对OO的改革,才能知道17级及以上会计专业学生面临的OO体系的合理性。
2、作为贝主任的学生,怎么能错过ljz学长的精彩博客呢?
比如这个新手教程:
3、阿里巴巴团队推出的优秀开发工具:Arthas
相信我,任何 API 都比你的打印更好
4.接口适配器4.1问题介绍:
有时我们编写一个包含多个方法的接口。当我们编写接口的实现类时,必须实现接口中的所有方法。有时这是浪费,因为并非所有方法都是我们需要的。有时只需要一些。 (不考虑接口中的方法可以删除到所有实现类的重写方法的情况,不需要重写多余的方法)
4.2 问题解决:
使用接口的适配器:借助抽象类,抽象类实现接口和所有方法。那么我们就不再和原来的接口打交道了,而只接触抽象类,也就是继承抽象类,然后再重写我们需要的方法
4.3 问题扩展:
上面提到的抽象类还可以提取实现类的公共方法,以简化代码逻辑和数量。
5.理论与实践相结合的经典书籍:6.hdl的随机三角函数化简方法(针对TaskTwo)
一些神秘的简化方法也能达到意想不到的效果,比如hdl使用的蒙特卡罗方法