Python类__init__方法中参数与非参数变量的差异及疑问
关于Python类中__init__参数与实例属性的区别解析
先看你给出的三段代码:
Block №1
class Car: def __init__(self, make, model, year, odometer_reading): self.make = make self.model = model self.year = year self.odometer_reading = odometer_reading
Block №2
class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year self.odometer_reading = 0
Block №3
class Car: def __init__(self, make, model, year, odometer_reading = 0): self.make = make self.model = model self.year = year self.odometer_reading = odometer_reading
一、__init__括号内的参数和直接赋值的实例属性的区别
不止是默认值的问题,核心差异在灵活性和初始化逻辑:
- 当
odometer_reading在__init__括号内时(比如Block1),它是必填参数——创建实例时必须传入对应的值,否则会报错。这种方式强制要求初始化时就确定这个属性的值,适合必须在创建时明确的属性。 - 不在括号内直接赋值(比如Block2),这个属性的初始值是固定死的,创建实例时没法直接传入自定义值,只能在实例创建完成后再修改
car.odometer_reading。这种方式适合初始值固定、不需要在创建时自定义的属性。
除此之外还有两点差异:
- 参数传递可控性:括号内的参数可以利用Python的位置/关键字参数规则灵活传递,而直接赋值的属性完全由类内部逻辑决定,外部创建时无法干预。
- 代码可读性:括号内的参数能直观告诉使用者,这个类初始化时需要哪些数据;直接赋值的属性则隐藏了初始化逻辑,使用者得查看类内部代码才知道存在这个属性。
二、Block №2和Block №3的区别
这两种写法的核心差异是初始化时是否允许自定义属性值:
- Block2的
odometer_reading初始值固定为0,创建实例时你没法在Car()里传入这个值,只能之后手动修改,比如my_car = Car('Toyota', 'Camry', 2023)之后再执行my_car.odometer_reading = 500。 - Block3的
odometer_reading是带默认值的可选参数,创建实例时可选择传值或不传:- 不传则用默认值0:
my_car = Car('Toyota', 'Camry', 2023) - 传值则用你传入的值:
my_car = Car('Toyota', 'Camry', 2023, 500)或者用关键字参数my_car = Car('Toyota', 'Camry', 2023, odometer_reading=500)
- 不传则用默认值0:
另外,Block3的写法更贴合Python"显式优于隐式"的原则,使用者不用看类内部代码,就能知道这个属性可以自定义初始值;而Block2的写法则隐藏了这个可能性。
内容的提问来源于stack exchange,提问作者Malpertui
相关产品推荐
相关产品推荐

