在打印功能中使用类名

时间:2019-12-04 08:32:13

标签: python

新手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)'

为什么会发生这种情况,我该如何解决?

2 个答案:

答案 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__()