大 创 实 验 室
警惕(tì)|Python程序员的24个常见错误(wù)!发表时间(jiān):2019-01-09 09:41作者(zhě):中科(kē)四(sì)平网址:http://www.shaoyang.zj.huaibei.xinxiang.zz.pingliang.ww38.viennacitytours.com 本文将总结(jié)新(xīn)老Python程序员(yuán)常(cháng)犯的一些(xiē)错误,以帮助(zhù)大家(jiā)在自己的工作(zuò)避免(miǎn)犯同样或(huò)类似错误。 语用(yòng)错误 让我们(men)从(cóng)基础开始,从那(nà)些刚学(xué)习(xí)编程的人钻研语法之前碰到的事情开始。如果你已经编过(guò)一些程了,那么以下(xià)这些可能(néng)看起来十分的简(jiǎn)单;如果你曾(céng)经尝试(shì)过教新手们怎(zěn)么(me)编程,它们(men)可能就不这么(me)简单了。 1. 在交互提示(shì)符中输入(rù)Python代码 在>>>交互提示符中你只能输入Python代码,而不是系统命令。时常(cháng)有人在这个提示符下输入emacs,ls,或者(zhě)edit之类(lèi)的命令,这些可不是Python代码。 在Python代码中确实有办法来调用系统(tǒng)命(mìng)令(lìng)(例(lì)如os.system和os.popen),但可不是像直(zhí)接输入(rù)命(mìng)令这么直接。如果(guǒ)你想(xiǎng)要在交(jiāo)互提示符中启动一个Python文(wén)件,请用(yòng)import file,而不是系(xì)统命令python file.py。 2. Print语句(仅仅)是(shì)在文件(jiàn)中需要(yào) 因为(wéi)交互解释器会自动(dòng)的(de)讲表(biǎo)达式的结果输(shū)出,所以你不需要交互的键(jiàn)入完整的print语句。这是(shì)个很(hěn)棒的(de)功能,但是记(jì)住在代码文(wén)件里,通常(cháng)你只有用print语(yǔ)句才能看得到输出。 3. 小心Windows里(lǐ)的(de)自动(dòng)扩(kuò)展名 如果(guǒ)你在Windows里使用记事本(běn)来编辑代码(mǎ)文件的话,当你保持的时候小心选(xuǎn)择“所有文件”(All Files)这(zhè)个(gè)类(lèi)型,并且明(míng)确(què)的给你的文件加一个(gè).py的后缀。不然的(de)话记事本会(huì)给(gěi)你的文件加一个.txt的扩展名(míng),使得在某些(xiē)启动(dòng)方法中(zhōng)没法跑这个程序。 更糟糕的是(shì),像Word或(huò)者是写字板一类的文字处理(lǐ)软(ruǎn)件还(hái)会默(mò)认(rèn)的加上(shàng)一些格式(shì)字符,而这些(xiē)字符(fú)Python语(yǔ)法是(shì)不认的。 所以(yǐ)记(jì)得,在Windows下(xià)总是(shì)选(xuǎn)“所有文件”(All Files),并保存为纯(chún)文本,或者使用更加“编(biān)程友好”的文本编辑(jí)工具,比如IDLE。在IDLE中,记得在(zài)保存时手(shǒu)动加上.py的扩展名。 4. 在Windows下点击(jī)图标(biāo)的问题 在Windows下(xià),你能靠点击(jī)Python文件来(lái)启动(dòng)一(yī)个Python程序,但这有时会有问题。首先,程序的输出窗(chuāng)口在程(chéng)序(xù)结束的瞬(shùn)间也就(jiù)消失了,要让它(tā)不消失(shī),你可以(yǐ)在文(wén)件(jiàn)最后加一条raw_input()的调用。另外,记住如(rú)果有错的话,输出窗(chuāng)口也就立即消失了。 要看(kàn)到你的错误信息的话,用别的方法来调(diào)用你的程序:比如从系统命令行启动,通过提(tí)示符下用import语句,或(huò)者IDLE菜(cài)单里的选项,等(děng)等。 5. Import只在第一(yī)次有效 你可以在交互(hù)提示(shì)符中通过(guò)import一个文件来运行它,但是(shì)这只会在(zài)一个(gè)会话中起一次作用;接下来的import仅仅是返回这个已经加载的模块(kuài)。要想强制Python重新(xīn)加(jiā)载一个文(wén)件的代码,请调用函数reload(module)来达到这个目的。注意对reload请(qǐng)使用括号,而import不要使用括(kuò)号。 6. 空白行(仅仅)在交互提示符(fú)中有(yǒu)作用 在模(mó)块文件(jiàn)中(zhōng)空白行和注释统统会(huì)被忽略掉(diào),但是在交(jiāo)互提示符中键(jiàn)入代(dài)码时,空白行表示(shì)一个复(fù)合语(yǔ)句的结束。 换句话说,空(kōng)白行告(gào)诉交(jiāo)互提示(shì)符你(nǐ)完成(chéng)了一(yī)个复合语句;在你真正(zhèng)完成之前不要键入回车。事实上当你要开始一个新的语句时(shí),你需要键入一个空行来结束(shù)当前的语(yǔ)句——交互提示符一次只运行一条语句。 代码错误 一旦你开始认真写Python代码(mǎ)了,接下来了一堆(duī)陷(xiàn)阱就更加危险了(le)——这(zhè)些都是(shì)一些跨语言特性(xìng)的基本代码错误,并常常困扰(rǎo)不细心的程序员。 7. 别忘了冒号(hào) 这是新手程序员(yuán)最(zuì)容易犯的一(yī)个(gè)错误:别忘了在复合语句的起始语句(if,while, for等语句的第一行)结束的地方加上一个(gè)冒号“:”。也许你刚开(kāi)始会忘掉(diào)这个,但(dàn)是(shì)到了很快这就会成为一(yī)个下意识的习惯。课(kè)堂里75%的学(xué)生当天就可以记住这个。 8. 初(chū)始化变量 在(zài)Python里,一个表达式中的名字在它被(bèi)赋(fù)值(zhí)之(zhī)前是没法(fǎ)使用的。这是有意而(ér)为的:这样能避免(miǎn)一些输入失误,同时也能避(bì)免默认究(jiū)竟(jìng)应(yīng)该(gāi)是什(shí)么(me)类型(xíng)的问题(tí)(0,None,””,[],?)。记住把计数器初始化为0,列(liè)表初始化(huà)为[],以此类推。 9. 从第一列开(kāi)始 确(què)保把顶层的,未嵌套的代码放(fàng)在最左(zuǒ)边第一列开始。这包括在模块文(wén)件中未(wèi)嵌套的(de)代码,以及在(zài)交互提示符中未嵌套的代码。Python使用缩进(jìn)的办法来(lái)区分(fèn)嵌套的代码段,因此在你代码左(zuǒ)边的空格(gé)意味着(zhe)嵌套(tào)的代码块。除了缩进以外,空格通常(cháng)是被忽(hū)略掉的。 10. 缩进(jìn)一致 在同(tóng)一个代码块中避免讲tab和空(kōng)格混用来缩进,除非你知(zhī)道运行你的代码的系统(tǒng)是怎么处理(lǐ)tab的。否则的(de)话,在你的编(biān)辑器里看(kàn)起来是tab的缩进也许Python看起来就(jiù)会被视作是一些空格。保险起见,在每个代码块(kuài)中全都是(shì)用tab或者全都是用空(kōng)格来缩进(jìn);用多少由你决(jué)定。 11. 在函(hán)数调用时(shí)使用(yòng)括号 无论一个函数是否(fǒu)需要参数,你必须要加一对括号来调(diào)用它。即,使用function(),而不是function。Python的(de)函数简单来说是具有特殊(shū)功能(néng)(调用)的(de)对象(xiàng),而调用(yòng)是用括号来触发的。像(xiàng)所(suǒ)有(yǒu)的对象一样(yàng),他们也(yě)可以被赋(fù)值给变量,并且间接的使用(yòng)他们(men):x=function:x()。 在Python的培训中,这样的错误常常在文件的操作中出(chū)现。通常会(huì)看到(dào)新(xīn)手用(yòng)file.close来关闭一个问题,而不(bú)是用file.close()。因(yīn)为在Python中引用一个(gè)函数(shù)而不调用它是(shì)合法的,因此不(bú)使用括号的(de)操作(file.close)无(wú)声的成功(gōng)了,但是并没(méi)有关闭这(zhè)个文件(jiàn)! 12. 在Import时不(bú)要使用(yòng)表达式或者路径 在系统(tǒng)的(de)命令行里使用文件夹路径或者文件的扩展名,但不(bú)要在import语句中使用。即,使用import mod,而不是import mod.py,或者import dir/mod.py。 在实际情况中,这大概(gài)是初学(xué)者常犯的第(dì)二大错误了。因为模块(kuài)会有除了.py以为的(de)其他的后(hòu)缀(例(lì)如(rú),.pyc),强制写上某个后缀不仅是不合语法(fǎ)的,也没(méi)有什么意义。 和系统有关的目录路径的格(gé)式是从你(nǐ)的模块(kuài)搜索路径的(de)设置里来的(de),而不是import语句。你可以在文件名里使(shǐ)用点来(lái)指向包的子目录(例如,import dir1.dir2.mod),但是最左边的目录必(bì)须得(dé)通过(guò)模块搜索路径(jìng)能够找到(dào),并且没有(yǒu)在(zài)import中没有其他路(lù)径(jìng)格(gé)式。 不正确(què)的语句import mod.py被Python认为是(shì)要记在一个包(bāo),它先(xiān)加载一个模块(kuài)mod,然后(hòu)试图通(tōng)过在一个叫做mod的目录里去找到叫(jiào)做py的模块,最(zuì)后可能什么也找不到而报出一(yī)系列费解(jiě)的错误信息。 13. 不要在Python中写C代码 以下是给(gěi)不(bú)熟悉Python的C程序(xù)员(yuán)的一些备忘贴士: 在if和(hé)while中(zhōng)条(tiáo)件测试时,不(bú)用输入括号(例如,if (X==1):)。如果你(nǐ)喜欢的话,加上括号也(yě)无(wú)妨,只是在这里是完全多余的。 不要用分号来结束你(nǐ)的(de)语句。从(cóng)技(jì)术上讲(jiǎng)这在(zài)Python里是合法的,但是(shì)这毫(háo)无用处,除非你要把(bǎ)很多语句放在同(tóng)一行里(例如,x=1; y=2; z=3)。 不要在while循环的条件测试中嵌入赋值语句(例如,while ((x=next() != NULL))。在Python中,需要表达式的地方(fāng)不能出(chū)现语句,并且赋值语句(jù)不(bú)是一个表达式。 编程(chéng)错误 下面终于要(yào)讲到当(dāng)你用(yòng)到更多(duō)的Python的功能(数据类(lèi)型,函数,模块,类等等)时(shí)可能碰到(dào)的问(wèn)题了。由于篇幅有(yǒu)限,这(zhè)里(lǐ)尽量精(jīng)简,尤其是对一(yī)些高级的概念。要想了解(jiě)更多的(de)细节,敬(jìng)请阅读《Python学习手册(cè)》。 14. 打开文(wén)件的调用不使用(yòng)模块搜索路径 当你在Python中调用open()来访问一个外部的文(wén)件时,Python不会使用模(mó)块搜索路径来定位这个目标文件。它会使用你提供的绝对路(lù)径,或者假定这个(gè)文件是在当前工作(zuò)目录(lù)中。模块搜索路径(jìng)仅仅为模块加(jiā)载服务的。 15. 不同的类型对应的方法也不同 列表(biǎo)的方法是不能用在(zài)字符串上(shàng)的,反之亦然。通(tōng)常情况下,方法的调用是和数据(jù)类型有关的,但是(shì)内部(bù)函(hán)数通(tōng)常在很多类型上都可以使用。举个例子来说,列表(biǎo)的reverse方法仅仅(jǐn)对列表有用,但(dàn)是len函数对任何(hé)具有(yǒu)长度的对象(xiàng)都适用。 16. 不(bú)能直接改变(biàn)不可变数据类型 记住你没法直接的改变一个不可变的对(duì)象(例如(rú),元组,字符串(chuàn)): T = (1, 2, 3) T[2] = 4 # 错误 用切(qiē)片,联(lián)接等构建一个新的对象,并根据需(xū)求将原来变量的(de)值赋(fù)给它。因为Python会自动回收没(méi)有用的内存,因此这没有(yǒu)看起来那么(me)浪费(fèi): T = T[:2] + (4,) # 没问题了: T 变成了 (1, 2, 4) 17. 使用简单的for循环而不是while或者range 当(dāng)你要从左到右遍历一个有序(xù)的对象的所有(yǒu)元素时,用简(jiǎn)单的for循环(例如,for x in seq:)相比于基于(yú)while-或者range-的计数循环而言会更容易写(xiě),通常运(yùn)行起(qǐ)来也更快。 除非你一定需(xū)要,尽量避免在一个for循环里使(shǐ)用range:让Python来(lái)替你解决(jué)标号的问题。在(zài)下面的(de)例(lì)子中三(sān)个(gè)循环结构(gòu)都没(méi)有问题,但(dàn)是第一(yī)个通(tōng)常来(lái)说更好(hǎo);在Python里,简单至(zhì)上。 S = "lumberjack" for c in S: print c # 最简单(dān) for i in range(len(S)): print S[i] # 太(tài)多了 i = 0 # 太多了 while i < len(S): print S[i]; i += 1 18. 不(bú)要(yào)试(shì)图从那些会改变(biàn)对象(xiàng)的函数得(dé)到结果 诸如像方法list.append()和list.sort()一(yī)类的直接(jiē)改变(biàn)操作会改变一个对象,但不会将它们改(gǎi)变的对象返回出(chū)来(它(tā)们会返回None);正确的做(zuò)法是直接调用它们而不要将结(jié)果赋值。经常会看(kàn)见初学者会写(xiě)诸如此类的代码: mylist = mylist.append(X) 目的是(shì)要得到(dào)append的结果,但是事实上这样做会将None赋值给mylist,而(ér)不是改变后的(de)列表。更加特别的(de)一个例(lì)子是想通过用排序后的(de)键值来遍历一个字(zì)典里的各个(gè)元素(sù),请看下面的例子: D = {...} for k in D.keys().sort(): print D[k] 差(chà)一点儿就成功了——keys方法会创建(jiàn)一个keys的列(liè)表,然后用sort方法(fǎ)来(lái)将这(zhè)个列表排序——但是因为sort方法会返回None,这个循环(huán)会失败,因为它实际(jì)上是(shì)要遍(biàn)历None(这可不是一个序列)。要改正这段代码,将方法的调用分离出(chū)来(lái),放(fàng)在不同的语句中(zhōng),如下: Ks = D.keys() Ks.sort() for k in Ks: print D[k] 19. 只有在数字类(lèi)型(xíng)中才存在(zài)类型转(zhuǎn)换 在Python中,一个诸如123+3.145的(de)表达式是(shì)可(kě)以工作的——它会自动将整数(shù)型转换(huàn)为浮(fú)点型,然后用浮(fú)点(diǎn)运算。但是下面的代码(mǎ)就会出错了: S = "42" I = 1 X = S + I # 类型错误 这同(tóng)样也是有意而为的,因为这是不明确的:究竟是将字符串转换为数(shù)字(进(jìn)行(háng)相加(jiā))呢(ne),还是将数字转换(huàn)为(wéi)字符(fú)串(进行联(lián)接)呢?在Python中,我们认为“明确比含糊好”(即(jí),EIBTI(Explicit is better than implicit)),因此你得(dé)手动转换类型: X = int(S) + I # 做加法: 43 X = S + str(I) # 字符串联接: "421" 20. 循(xún)环的数据结构会导(dǎo)致循环 尽管这(zhè)在实际情况中很少(shǎo)见,但(dàn)是如(rú)果一个对象(xiàng)的集合包(bāo)含了到(dào)它自己的(de)引(yǐn)用,这被(bèi)称为循环(huán)对(duì)象(cyclic object)。如果在一个(gè)对象中发(fā)现一个循环,Python会输出一个[…],以避免在无限循环中卡住: >>> L = ['grail'] # 在 L中又(yòu)引用L自身会 >>> L.append(L) # 在对象中(zhōng)创造一个循(xún)环 >>> L ['grail', [...]] 除了知(zhī)道这三个点在对象中(zhōng)表示循环以外,这(zhè)个例子也是(shì)很值(zhí)得借鉴的。因(yīn)为你可能无意(yì)间(jiān)在你的代(dài)码中出现(xiàn)这样的循环的结构而(ér)导致你(nǐ)的代码出错(cuò)。如果(guǒ)有必(bì)要的话,维护一个列(liè)表或者字典来(lái)表示已经访问(wèn)过(guò)的对象,然后(hòu)通过检查(chá)它来确认(rèn)你是否碰到了循环。 21. 赋值语句不会创建对象的副本,仅仅创建引用 这是(shì)Python的一个核(hé)心(xīn)理念,有时候当行为不对时会(huì)带来错误。在下面的例子中(zhōng),一个列表对象被赋给了(le)名(míng)为L的变量,然后(hòu)L又在(zài)列表M中(zhōng)被引用(yòng)。内部改变L的话,同时也会改变M所引用的对(duì)象,因为它们俩都指(zhǐ)向同一个对象。 >>> L = [1, 2, 3] # 共用的列表对象 >>> M = ['X', L, 'Y'] # 嵌(qiàn)入一个到L的引用 >>> M ['X', [1, 2, 3], 'Y'] >>> L[1] = 0 # 也改变了M >>> M ['X', [1, 0, 3], 'Y'] 通常情况下只有在稍大一(yī)点的程序里这就显得很重要(yào)了,而且这些共用的(de)引(yǐn)用通常确实是你(nǐ)需要的。如果不是(shì)的话,你可以明确的给他们创建一个副本(běn)来避免共(gòng)用的引用;对于列表来说,你(nǐ)可(kě)以通过(guò)使用(yòng)一个空列表的切片来(lái)创建一个顶层的(de)副本(běn): >>> L = [1, 2, 3] >>> M = ['X', L[:], 'Y'] # 嵌(qiàn)入(rù)一(yī)个L的副本(běn) >>> L[1] = 0 # 仅(jǐn)仅改(gǎi)变了L,但(dàn)是不影(yǐng)响(xiǎng)M >>> L [1, 0, 3] >>> M ['X', [1, 2, 3], 'Y'] 切片的范围起始从默认的0到被切片的序列的(de)最大长度。如(rú)果两(liǎng)者(zhě)都省略掉了,那么切片会抽(chōu)取该序列中的所有(yǒu)元(yuán)素,并创造一(yī)个顶(dǐng)层的副本(一个新的,不被(bèi)公用的对(duì)象)。对于字典来说,使(shǐ)用(yòng)字典的dict.copy()方法(fǎ)。 22. 静态识别本地域(yù)的变量名 Python默认将一(yī)个函数(shù)中(zhōng)赋值的变量名视作是本地(dì)域的,它们存(cún)在于该函数的作用域(yù)中并(bìng)且(qiě)仅仅在函数运(yùn)行的时候才存在。从技术上讲,Python是(shì)在编译def代码时,去静态的识别本地变量,而(ér)不是在运行时碰到赋值的时(shí)候(hòu)才识(shí)别到的。 如果(guǒ)不理解这点的(de)话,会引起(qǐ)人们的误解。比如,看看下面的例子,当(dāng)你(nǐ)在(zài)一个引用之后给一个(gè)变量赋值会怎么样: >>> X = 99 >>> def func(): ... print X # 这(zhè)个时(shí)候还不存在(zài) ... X = 88 # 在(zài)整(zhěng)个(gè)def中将X视作本地变量 ... >>> func( ) # 出错了! 你会得(dé)到一个“未定义变量名(míng)”的错误,但是其(qí)原因是(shì)很微妙(miào)的。当编译这则(zé)代码时,Python碰到给X赋值的语句时认为在这个函(hán)数中的任何地方X会被视作一个本地变量(liàng)名。 但(dàn)是之后当真正运行这个函数时,执行print语句的时候,赋值语句还没有发生,这样Python便(biàn)会报告一个“未定义变量名”的错误。 事实(shí)上(shàng),之前(qián)的这个例(lì)子想(xiǎng)要做的事情是很模糊的:你是(shì)想(xiǎng)要先(xiān)输出(chū)那个全局的X,然后(hòu)创建一个(gè)本地的X呢,还(hái)是说这是个程序的错误?如果你真的是想要(yào)输出这个全局的X,你需要(yào)将(jiāng)它(tā)在一个全局语句中声明它,或者通过包(bāo)络(luò)模块的名字来引用它。 23. 默(mò)认参数(shù)和可变对象 在执(zhí)行def语句时,默认参数的值只被解析并保存一次,而(ér)不(bú)是(shì)每次在(zài)调用函数的时候。这通常是(shì)你想要的(de)那样,但是因为(wéi)默认值(zhí)需要在(zài)每次调用时都(dōu)保持同样对(duì)象,你在试图改变可变的默认值(mutable defaults)的时候可要小(xiǎo)心了。 例如,下(xià)面的函数中使用一(yī)个空(kōng)的(de)列(liè)表作为默认值,然后在(zài)之后每一次函(hán)数调用(yòng)的时候改变它的值: >>> def saver(x=[]): # 保(bǎo)存一(yī)个列(liè)表对象(xiàng) ... x.append(1) # 并每次调用的时候(hòu) ... print x # 改变它的值(zhí) ... >>> saver([2]) # 未使用默认值 [2, 1] >>> saver() # 使用默(mò)认值 [1] >>> saver() # 每次调用都会增加! [1, 1] >>> saver() [1, 1, 1] 有的人将(jiāng)这个视(shì)作Python的一个特点——因为(wéi)可变的默(mò)认参数在每次函数调用时保持了它们的(de)状态,它们能提供像C语(yǔ)言中静态本(běn)地函数变量的类似的(de)一些功能。 但是,当(dāng)你第一(yī)次碰到它时会觉得这很奇怪,并且在Python中(zhōng)有更加(jiā)简(jiǎn)单的办法来(lái)在(zài)不(bú)同的调用(yòng)之间保存状态(比如(rú)说类(lèi))。 要摆脱这样的行为,在(zài)函(hán)数开(kāi)始(shǐ)的地方用切(qiē)片或(huò)者方(fāng)法来创(chuàng)建默认(rèn)参数(shù)的副本(běn),或者将(jiāng)默认值的(de)表达式移(yí)到函(hán)数里面(miàn);只要(yào)每(měi)次函(hán)数调用时这些(xiē)值在(zài)函数里,就会每(měi)次都(dōu)得到一个新的(de)对(duì)象: >>> def saver(x=None): ... if x is None: x = [] # 没有传(chuán)入参数? ... x.append(1) # 改变新(xīn)的(de)列表(biǎo) ... print x ... >>> saver([2]) # 没(méi)有使用默认值 [2, 1] >>> saver() # 这次不会变(biàn)了 [1] >>> saver() [1] 24. 其(qí)他(tā)常见的编程陷阱(jǐng) 下面列举了其他(tā)的一些(xiē)在这里没法(fǎ)详述的陷阱: 在顶层文件中语句的顺序是有讲究的:因为运(yùn)行或者加(jiā)载一个(gè)文件会从上到下运行(háng)它的语句,所(suǒ)以请确(què)保将(jiāng)你未嵌套(tào)的函数调用或(huò)者类的(de)调用放在函数或者(zhě)类的定义之后。 reload不影响用from加载的(de)名字(zì):reload最好和(hé)import语句(jù)一起使用。如果(guǒ)你(nǐ)使用from语(yǔ)句,记得在reload之后重(chóng)新运行(háng)一遍from,否(fǒu)则你仍(réng)然(rán)使用之前老的名(míng)字。 在多(duō)重继承(chéng)中混合(hé)的顺序是有讲(jiǎng)究的:这是因为(wéi)对superclass的搜索是从左到右的,在类定义的头(tóu)部,在多重superclass中如果出(chū)现重(chóng)复的名字,则以最左边的类名(míng)为准。 在t 888888 ry语句中空的except子句可能会比你预想(xiǎng)的捕捉(zhuō)到更(gèng)多(duō)的错误(wù)。在(zài)try语(yǔ)句中空(kōng)的(de)except子句表示捕捉(zhuō)所有的错误,即便是真正(zhèng)的程序错误(wù),和sys.exit()调用,也会被(bèi)捕捉到。 中科四平(píng)自成立以来,重视研发、重视关键(jiàn)技术的积累(lèi)和突破。先后(hòu)得到了省市区各级(jí)政府的大力(lì)扶持,并承担了(le)多项(xiàng)重大科研项目(mù)。以打造低功耗无线传感(gǎn)解决方案为(wéi)目标(biāo),目前已经形成系列成熟产品:物联网及机器(qì)人教(jiāo)学产品(pǐn)、创客教育及创意类产品、智慧校园解决方(fāng)案、其它物(wù)联网应(yīng)用等,努力打造物联(lián)网、机器(qì)人教育新体系,为高校提(tí)供(gòng)全方位实验实训服务,为社会多培养一个科技人才(cái)不断努力! |