You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python人脸识别考勤系统遇TypeError: can only join an iterable 如何解决?

问题描述

我正在使用Python开发一款人脸识别考勤程序,运行程序时终端报错TypeError: can only join an iterable,错误出现在代码行n="+".join(n)处。若注释该行代码,CV捕获窗口中的Course、Semester、Roll No、Name字段仅显示None。

相关代码:

def mark_attendance(self,i,r,n,name):
    with open("attendance.csv","r+",newline="\n") as f:
        myDatalist=f.readlines()
        name_list=[]
        for line in myDatalist:
            entry=line.split((","))
            name_list.append(entry[0])

        if((name not in name_list) and (i not in name_list)):
            now=datetime.now()
            d1=now.strftime("%Y/%m/%d")
            dtString=now.strftime("%H:%M:%S")
            f.writelines(f"{n}, {r}, {i}, {name}, {dtString}, {d1}, Present\n")

#================face recognition==================
def face_recog(self):
    def draw_boundray(img,classifier,scaleFactor,minNeighbors,color,text,clf):
        gray_image=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        features=classifier.detectMultiScale(gray_image,scaleFactor,minNeighbors)

        coord=[]
        
        for (x,y,w,h) in features:
            cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),3)
            id,predict=clf.predict(gray_image[y:y+h,x:x+w])

            confidence=int((100*(1-predict/300)))

            conn = mysql.connector.connect(username='root', password='',host='localhost',database='face_recognition',port=3306)
            cursor = conn.cursor()

            cursor.execute("select Course from student where Roll_No="+str(id))
            n=cursor.fetchone()
            n="+".join(n)

            cursor.execute("select Semester from student where Roll_No="+str(id))
            r=cursor.fetchone()
            r="+".join(r)

            cursor.execute("select Roll_No from student where Roll_No="+str(id))
            i=cursor.fetchone()
            i="+".join(i)

            cursor.execute("select Name from student where Roll_No="+str(id))
            name=cursor.fetchone()
            name="+".join(name)


            if confidence > 77:
                cv2.putText(img,f"Course: {n}",(x,y-105),cv2.FONT_HERSHEY_COMPLEX,0.8,(64,15,223),2)
                cv2.putText(img,f"Semester: {r}",(x,y-80),cv2.FONT_HERSHEY_COMPLEX,0.8,(64,15,223),2)
                cv2.putText(img,f"Roll No: {i}",(x,y-55),cv2.FONT_HERSHEY_COMPLEX,0.8,(64,15,223),2)
                cv2.putText(img,f"Name: {name}",(x,y-30),cv2.FONT_HERSHEY_COMPLEX,0.8,(64,15,223),2)
                self.mark_attendance(i,r,n,name)
            else:
                cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),3)
                cv2.putText(img,"Not Found",(x,y-5),cv2.FONT_HERSHEY_COMPLEX,0.8,(255,255,0),3)   

            coord=[x,y,w,y]
        
        return coord    


    #==========
    def recognize(img,clf,faceCascade):
        coord=draw_boundray(img,faceCascade,1.1,10,(255,25,255),"Face",clf)
        return img
    
    faceCascade=cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
    clf=cv2.face.LBPHFaceRecognizer_create()
    clf.read("clf.xml")

    videoCap=cv2.VideoCapture(0)

    while True:
        ret,img=videoCap.read()
        img=recognize(img,clf,faceCascade)
        cv2.imshow("Face Detector",img)

        if cv2.waitKey(1) == 27:
            break
    videoCap.release()
    cv2.destroyAllWindows()

终端错误信息:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Khursaid\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1885, in __call__
    return self.func(*args)
  File "E:\Final Project\New FAS\login.py", line 417, in face_recog
    img=recognize(img,clf,faceCascade)
  File "E:\Final Project\New FAS\login.py", line 406, in recognize
    coord=draw_boundray(img,faceCascade,1.1,10,(255,25,255),"Face",clf)
  File "E:\Final Project\New FAS\login.py", line 374, in draw_boundray
    n="+".join(n)
TypeError: can only join an iterable
解决方案

问题根源

  • 当数据库中没有匹配当前Roll_No的记录时,cursor.fetchone()返回None,此时调用"+".join(None)会触发TypeError,因为None不是可迭代对象。
  • 即使有匹配记录,fetchone()返回的是单元素元组(例如("计算机科学",)),用join完全没必要,直接提取元组内的元素即可。

修改步骤

  1. 先判断fetchone()的返回值是否为None,避免空值报错;
  2. 直接提取元组中的第一个元素,替代不必要的join操作;
  3. 改用参数化查询,避免SQL注入风险。

修改后的数据库查询代码:

# 建立数据库连接(建议提到函数外部,避免重复创建连接)
conn = mysql.connector.connect(username='root', password='',host='localhost',database='face_recognition',port=3306)
cursor = conn.cursor()

# 查询Course
cursor.execute("select Course from student where Roll_No=%s", (id,))
n = cursor.fetchone()
n = n[0] if n else "Unknown"

# 查询Semester
cursor.execute("select Semester from student where Roll_No=%s", (id,))
r = cursor.fetchone()
r = r[0] if r else "Unknown"

# 查询Roll_No
cursor.execute("select Roll_No from student where Roll_No=%s", (id,))
i = cursor.fetchone()
i = str(i[0]) if i else "Unknown"

# 查询Name
cursor.execute("select Name from student where Roll_No=%s", (id,))
name = cursor.fetchone()
name = name[0] if name else "Unknown"

额外优化建议

  • 减少数据库连接次数:当前代码每次人脸检测循环都创建新的数据库连接,会大幅降低性能,建议将连接放在draw_boundray函数外部,或者使用数据库连接池。
  • 优化考勤判断逻辑:mark_attendance函数中if((name not in name_list) and (i not in name_list))存在逻辑问题,应仅通过学号(Roll_No)判断是否已考勤,因为姓名可能存在重复。

内容的提问来源于stack exchange,提问作者Khursaid Ansari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:18:34