新手Pythonista在这里。
我有一个问题。我想打印一个特定的输出,该输出需要像 Point(x = 1,y = 2,z = 3)(xyz的值当然可以不同)。
这是代码:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __str__(self):
return f"Point(x={self.x}, y={self.y}, z={self.z})"
这是测试代码:
import unittest
from point import Point
class PointTests(unittest.TestCase):
"""Tests for Point."""
def test_attributes(self):
point = Point(1, 2, 3)
self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
point.x = 4
self.assertEqual(point.x, 4)
def test_string_representation(self):
point = Point(1, 2, 3)
self.assertEqual(str(point), 'Point(x=1, y=2, z=3)')
self.assertEqual(repr(point), 'Point(x=1, y=2, z=3)')
point.y = 4
self.assertEqual(str(point), 'Point(x=1, y=4, z=3)')
self.assertEqual(repr(point), 'Point(x=1, y=4, z=3)')
def test_equality_and_inequality(self):
p1 = Point(1, 2, 3)
p2 = Point(1, 2, 4)
p3 = Point(1, 2, 3)
self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
self.assertNotEqual(p1, p2)
self.assertEqual(p1, p3)
p3.x, p3.z = p3.z, p3.x
self.assertNotEqual(p1, p3)
self.assertTrue(p1 != p3)
self.assertFalse(p1 == p3)
我遇到的问题是,当我使用打印格式的“ 点”时,在 str 函数中抛出了断言错误:
AssertionError:'在0x7fbd8850b190处的point.Point对象'!='Point(x = 1,y = 2,z = 3)'
但是当我使用其他任何东西时,它都会被打印出来。例如,假设我使用 points 代替了 Point :
'points(x = 1,y = 2,z = 3)'!='Point(x = 1,y = 2,z = 3)'
为什么会发生这种情况,我该如何解决?
答案 0 :(得分:5)
发生错误的地方
self.assertEqual(repr(point), 'Point(x=1, y=2, z=3)')
由于您仅在__str__
上定义了__Point__
方法,因此__repr__
仍然是内置方法,结果类似"point.Point object at 0x7fbd8850b190"
。要解决此问题,请定义__repr__
中的Point
。
在定义__repr__
方法时,python会将其用作__str__
的默认方法,但反之则无济于事。
对于您的代码示例(不是那么少),仍然会导致
错误self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
这是因为此行不会测试表示形式是否相等,而是测试对象的相等性。由于您实例化了Point
两次,因此assertEqual
的第一个参数实际上与第二个参数不同,即使它们都是Point
的实例,并且即使它们在它们的值上相等也是如此。实例变量。
您可以将这些对象理解为“双胞胎”或“克隆”之类的东西:即使它们的所有属性都相同,它们仍然具有不同的“身份”。
如果我们想将“ twins”视为“ equal”,Python允许我们定义Python用于检查对象是否相等的相等关系。我们可以通过实现__eq__
方法来定义它。您最可能想要的东西是:
class Point:
def __init__(x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return f"Point(x={self.x}, y={self.y}, z={self.z})"
def __eq__(self, other):
return self.__repr__() == other.__repr__()
阅读有关Python的“魔术方法”的介绍,例如https://rszalski.github.io/magicmethods/
可能是一个好主意。答案 1 :(得分:1)
就python 3而言,您有两个失败的测试。
======================================================================
FAIL: test_equality_and_inequality (test_point.PointTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/josef/tmp/deleteme/test_point.py", line 29, in test_equality_and_inequality
self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
AssertionError: <point.Point object at 0x7f7a20cff050> != <point.Point object at 0x7f7a20cff090>
之所以发生这种情况,是因为声明一个新对象的返回是具有唯一ID的对象本身。评估Point(1, 2, 3)
会返回诸如<point.Point object at 0x7f7a20cff050>
之类的唯一事物,而不是类本身。因此,如果实例化一个类的两个实例,则它们必然是不同的。
======================================================================
FAIL: test_string_representation (test_point.PointTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/josef/tmp/deleteme/test_point.py", line 19, in test_string_representation
self.assertEqual(repr(point), 'Point(x=1, y=2, z=3)')
AssertionError: '<point.Point object at 0x7f7a20d75f90>' != 'Point(x=1, y=2, z=3)'
- <point.Point object at 0x7f7a20d75f90>
+ Point(x=1, y=2, z=3)
Python类可以具有__str__
方法和__repr__
方法。前者主要用于返回对象的字符串表示形式,因此,如果将其显示给人类,则看起来有些不错。我认为后者使用较少(我仍然通常会对其进行定义),但据我所知应该启用“对象到表示到对象”往返;以这样的方式显示实例,从理论上讲,您可以eval()
以字符串表示形式并忠实地再现对象。
您的类定义没有__repr__
,因此测试当然会失败。有时候(有时值很大)如果我很懒,我会这样做:
def __str__(self):
return self.__repr__()