Python报错'tuple' object has no attribute 'x'原因与解决

问题现象
运行求解三维空间两线段最短距离的Python代码时,mid(a, b)函数抛出'tuple' object has no attribute 'x'错误,无法访问入参a、b的x、y、z属性。自定义point类中x、y、z均为公开属性,但传入mid的参数被解释器识别为tuple类型,连续触发3次同类错误。
错误根因
报错是传参错误导致的,和point类的属性定义无关:
- 在
my_sol函数构造next列表的第一行,错误写为mid((p, q), q),其中(p, q)是将两个point对象打包成的元组,不是point实例,传入mid函数后尝试访问元组的x属性,自然触发报错。 - 对比同函数其余3个
next元素的计算逻辑、以及direction函数中的同场景写法,L1线段右侧中点的正确传参应该是mid(mid(p, q), q),多余的一层括号把两个点包成了元组,是触发错误的直接原因。
补充:point类定义时类层级写的x=0/y=0/z=0属于冗余类属性,实例初始化时会被__init__里的实例属性覆盖,不影响功能运行,可以删除。
修复方案
将my_sol函数中出错的那行代码的多余括号删除即可,修正后的关键代码段:
def my_sol(p, q, r, s, prev_l, flag): ep = 0.0001 # end condition next = [] # 修正前:mid((p, q), q) 多了一层括号把p、q包成元组 next.append(my_length(mid(mid(p, q), q), mid(r, s))) next.append(my_length(mid(p, mid(p, q)), mid(r, s))) next.append(my_length(mid(p, q), mid(r, mid(r, s)))) next.append(my_length(mid(p, q), mid(mid(r, s), s))) # 其余逻辑保持不变
修正后完整可运行代码:
import math points = [] class point: def __init__(self, x, y, z): self.x = x self.y = y self.z = z def printInfo(self): print(f"x={self.x} | y={self.y} | z={self.z}") def my_length(a, b): length = math.sqrt( math.pow(a.x - b.x, 2) + math.pow(a.y - b.y, 2) + math.pow(a.z - b.z, 2) ) return length def mid(a, b): x1 = a.x * 0.5 + b.x * 0.5 y1 = a.y * 0.5 + b.y * 0.5 z1 = a.z * 0.5 + b.z * 0.5 return point(x1, y1, z1) def my_input(): global points for i in range(4): x, y, z = map(int, input().split()) points.append(point(x, y, z)) return def direction(p, q, r, s, flag): if flag == "L1": len_1 = my_length(mid(p, mid(p, q)), mid(r, s)) len_2 = my_length(mid(mid(p, q), q), mid(r, s)) if len_1 > len_2: return "Right" elif len_1 < len_2: return "Left" else: return "change" elif flag == "L2": len_1 = my_length(mid(p, q), mid(r, mid(r, s))) len_2 = my_length(mid(p, q), mid(mid(r, s), s)) if len_1 > len_2: return "Right" elif len_1 < len_2: return "Left" else: return "change" def my_sol(p, q, r, s, prev_l, flag): ep = 0.0001 next = [] next.append(my_length(mid(mid(p, q), q), mid(r, s))) next.append(my_length(mid(p, mid(p, q)), mid(r, s))) next.append(my_length(mid(p, q), mid(r, mid(r, s)))) next.append(my_length(mid(p, q), mid(mid(r, s), s))) if abs(min(next) - prev_l) < 0.05: print(my_length(mid(p, q), mid(r, s))) return my_length(mid(p, q), mid(r, s)) if flag == "L1": if direction(p, q, r, s, flag) == "Right": my_sol(mid(p, q), q, r, s, next[0], "L1") elif direction(p, q, r, s, flag) == "Left": my_sol(p, mid(p, q), r, s, next[1], "L1") elif direction(p, q, r, s, flag) == "change": my_sol(p, q, r, s, my_length(mid(p, q), mid(r, s)), "L2") else: if direction(p, q, r, s, flag) == "Right": my_sol(p, q, r, mid(r, s), next[2], "L2") elif direction(p, q, r, s, flag) == "Left": my_sol(p, q, mid(r, s), s, next[3], "L2") elif direction(p, q, r, s, flag) == "change": my_sol(p, q, r, s, my_length(mid(p, q), mid(r, s)), "L2") if __name__ == "__main__": my_input() a, b, c, d = points[0], points[1], points[2], points[3] my_sol(a, b, c, d, 0, "L1")
内容的提问来源于stack exchange,提问作者차현대
相关产品推荐
相关产品推荐

