Python 类 - 使用实例作为属性

Python Classes - Using Instances AS Attributes

我目前 learning/working 在 Python 3.10.2 中使用 classes 撰写本文。我想要实现的是创建一个 class 实例,它是另一个 class.

中的一个属性

下面是我一直在编写的一些代码,以帮助证明我的观点。

class Vehicle():
    """To model a basic vehicle"""
    def __init__(self, name, max_speed, millage):
        """Initiate class variables"""
        self.name = name
        self.max_speed = max_speed
        self.millage = millage
        self.tyre = Tyre()

    def vehicle_details(self):
        """display vehicle details"""
        return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "

class Tyre():
    """A class specific for vehicle tyres"""
    def __init__(self, size=16, pressure=36):
        self.size = size
        self.pressure = pressure

    def tyre_details(self):
        """Print tyre details."""
        print(f'Tyre size: {self.size} inches.')
        print(f"Tyre pressure {self.pressure} PSI.")

Vehicle class 中,我添加 Tyre() 作为属性。

现在这段代码确实有效,我可以通过我的 Vehicle 实例调用 Tyre 方法,但只有当我将预先确定的值分配给 sizepressure Tyre class.

是否有:

  1. 一种无需在 Tyre class?

    中分配预定值即可实现此目的的方法

    如果我没有分配预定值,这是我收到的回溯:

    TypeError: __init__() missing 2 required positional arguments: 'size' and 'pressure'
    
  2. 如果我无法删除预定值,我在调用此 class 及其方法时覆盖预定值的简单方法?

  1. A way I can achieve this without having to allocate the pre-determined values within the Tyre class?

一个可能的解决方案是在初始化 Vehicle:

时传递 Tyre 的参数
class Vehicle:

    def __init__(self, name, max_speed, millage, tyre_size=16, tyre_pressure=36):
        """Initiate class variables"""
        self.name = name
        self.max_speed = max_speed
        self.millage = millage
        self.tyre = Tyre(size=tyre_size, pressure=tyre_pressure)
  1. An easy way for me to overwrite the pre-determined values when calling this class and its methods if I am unable to remove the pre-determined values?

您可以不使用任何 pre-determined 值,要求明确提供它们:

class Tyre:

    def __init__(self, size, pressure):
        # ...

如果没有传递任何值,将引发异常。只有当你真的想要时,你才应该依赖 pre-determined 值。而不是总是依赖一组特定的 pre-determined 值。

一般来说,当您很少需要与默认值不同的值时,我建议只使用 pre-determined 值。例如,如果您有 User class,您可能总是会使用不同的 username。没有明显的默认值。另一方面,当你有一个 Vehicle class 时,在大多数情况下它会有 4 个门,但有时可能会有所不同(可能是 5 个),所以你可以将 4 作为默认值并进行更改当你需要的时候。

您可以在创建 Tyre class 的实例时设置参数。 pre-determined 值仅在未传入参数时使用,因此如果您执行 self.tyre = Tyre(size goes here, pressure goes here),它不会使用 pre-determined 值。

几乎有无数种方法可以“解决”这个问题,但我会介绍一些。

None 是“正确的”,所有这些都涉及权衡,随着时间的推移,您将了解哪些地方有意义。

传递参数

class Vehicle():
    """To model a basic vehicle"""
    def __init__(self, name, max_speed, millage, tyre_size, tyre_pressure):
        """Initiate class variables"""
        self.name = name
        self.max_speed = max_speed
        self.millage = millage
        self.tyre = Tyre(tyre_size, tyre_pressure)

    def vehicle_details(self):
        """display vehicle details"""
        return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "


class Tyre():
    """A class specific for vehicle tyres"""
    def __init__(self, size, pressure):
        self.size = size
        self.pressure = pressure

    def tyre_details(self):
        """Print tyre details."""
        print(f'Tyre size: {self.size} inches.')
        print(f"Tyre pressure {self.pressure} PSI.")

v1 = Vehicle("VehicleName", 120, 50_000, 16, 36)
# Or, with named arguments
v2 = Vehicle(
    name = "VehicleName", 
    max_speed = 120, 
    millage = 50_000, 
    tyre_size = 16, 
    typre_pressure = 36
)

在这里,您只是将 Tyre 构造函数的参数从 Vehicle 构造函数传递给 Tyre 的构造函数。如果每次构造 Vehicle 时您都会知道 Tyre 规范,这很好。如果没有,您可能需要其他选择。

Tyre实例作为参数构造Vehicle

class Vehicle():
    """To model a basic vehicle"""
    def __init__(self, name, max_speed, millage, tyre):
        """Initiate class variables"""
        self.name = name
        self.max_speed = max_speed
        self.millage = millage
        self.tyre = tyre

    def vehicle_details(self):
        """display vehicle details"""
        return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "


class Tyre():
    """A class specific for vehicle tyres"""
    def __init__(self, size, pressure):
        self.size = size
        self.pressure = pressure

    def tyre_details(self):
        """Print tyre details."""
        print(f'Tyre size: {self.size} inches.')
        print(f"Tyre pressure {self.pressure} PSI.")


v = Vehicle(
    name = "VehicleName", 
    max_speed = 120, 
    millage = 50_000, 
    tyre = Tyre(16, 36)
)

与前一个选项类似,但在前一个选项中,每个 Vehicle 都有自己的 Tyre 实例。您可以在这里“分享”Tyre 个对象。在这种情况下可能没什么大不了的,但要记住一些事情,尤其是当您处理更大或更复杂的对象时 and/or 共享成为一种好处。

共享 Tyre 个实例可能如下所示:

standard_tyre = Tyre(16, 36)

v1 = Vehicle(
    name = "VehicleOne", 
    max_speed = 120, 
    millage = 50_000, 
    tyre = standard_tyre,
)
v2 = Vehicle(
    name = "VehicleTwo", 
    max_speed = 140, 
    millage = 20_000, 
    tyre = standard_tyre,
)

稍后在构造函数之外设置轮胎

class Vehicle():
    """To model a basic vehicle"""
    def __init__(self, name, max_speed, millage):
        """Initiate class variables"""
        self.name = name
        self.max_speed = max_speed
        self.millage = millage
        self.tyre = None

    def vehicle_details(self):
        """display vehicle details"""
        return f"\nName: {self.name.title()}, Max speed: {self.max_speed}MPH, Millage: {self.millage} "


class Tyre():
    """A class specific for vehicle tyres"""
    def __init__(self, size, pressure):
        self.size = size
        self.pressure = pressure

    def tyre_details(self):
        """Print tyre details."""
        print(f'Tyre size: {self.size} inches.')
        print(f"Tyre pressure {self.pressure} PSI.")


v = Vehicle(
    name = "VehicleName", 
    max_speed = 120, 
    millage = 50_000, 
)
v.tyre = Tyre(16,36)

也许您在创建 Vehicle 时不知道 Tyre 的具体细节,但您仍然想要一个 Vehicle 实例。

  1. 我 运行 在你的代码之后添加了以下代码,它对我来说工作正常。
veh = Vehicle('Volkswagen', 200, 10)
print(veh.tyre.tyre_details())

输出:

Tyre size: 16 inches.
Tyre pressure 36 PSI.
  1. 通过车辆实例覆盖轮胎尺寸和压力:
veh.tyre.size = 17
veh.tyre.pressure = 38
print(veh.tyre.tyre_details())

输出

Tyre size: 17 inches.
Tyre pressure 38 PSI.

可能是您错误地访问了轮胎实例。