一:创建类(首字母大写)
class Dog(object):
""" 模拟小狗"""
def __init__(self,name,age):
"""初始化属性name和age"""
self.name = name
self.age = age
def sit(self):
"""小狗蹲下"""
print(self.name.title() + " is sitting.")
def roll_over(self):
"""小狗打滚"""
print(self.name.title() + " rolled over")
my_dog = Dog('willie',6)
your_dog = Dog('lucy',3)
print("My dog'name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old")
my_dog.sit()
print("\nYour dog'name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old")
your_dog.roll_over()
>>>My dog'name is Willie.
>>>My dog is 6 years old
>>>Willie is sitting.
>>>Your dog'name is Lucy.
>>>Your dog is 3 years old
>>>Lucy rolled over
1.1方法__init__()
- 类中的函数称为方法。有关函数的一切都适用于方法,就目前而言,唯一重要的差别是调用方法的方式。
- 方法__init__() 是一个特殊的方法,每当你根据Dog 类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,旨在避免Python默认方法与普通方法发生名称冲突。
- 方法__init__() 包含三个形参:self 、name 和age 。在这个方法的定义中,形参self 必不可少,还必须位于其他形参的前面。
为何必须在方法定义中包含形参self 呢?
因为Python调用这个__init__() 方法来创建Dog 实例时,将自动传入实参self 。每个与类相关联的方法调用都自动传递实参self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建Dog 实例时,Python将调用Dog 类的方法__init__() 。我们将通过实参向Dog()传递名字和年龄;self 会自动传递,因此我们不需要传递它。每当我们根据Dog 类创建实例时,都只需给最后两个形参提供值。
Dog 类还定义了另外两个方法:sit() 和roll_over()。它们只有一个形参self 。
1.2创建实例
my_dog = Dog('willie',6)
遇到这行代码时,Python使用实参'willie' 和6调用Dog 类中的方法__init__() 。方法__init__() 创建一个表示特定小狗的示例,并使用提供的值来设置属性name 和age 。方法__init__() 并未显式地包含return 语句,但Python自动返回一个表示这条小狗的实例。将这个实例存储在变量my_dog 中。
1.3访问属性
my_dog.name
二:使用类和实例
class Car(object):
"""模拟小汽车"""
def __init__(self,make,model,year):
"""描述汽车属性"""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""返回描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
my_new_car = Car('audi','a4','2019')
print(my_new_car.get_descriptive_name())
>>>2019 Audi A4
2.1给属性指定默认值
类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。有些情况下,可在方法__init__() 内指定初始值,且无需为它提供这个属性初始值的形参。
下面添加一个名为odometer_reading的属性,其初始值总是为0:
class Car(object):
def __init__(self,make,model,year):
"""描述汽车属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):...
def read_odometer(self):
"""汽车里程信息打印"""
print("This car has " + str(self.odometer_reading) + " miles.")
my_new_car = Car('audi','a4','2019')
my_new_car.read_odometer()
>>>This car has 0 miles.
2.2修改属性的值
2.2.1:直接修改
class Car(object):...
my_new_car = Car('audi','a4','2019')
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 22
my_new_car.read_odometer()
>>>2019 Audi A4
>>>This car has 22 miles.
2.2.2:通过方法修改属性的值
无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新。
class Car(object):
def __init__(self,make,model,year):...
def get_descriptive_name(self):...
def read_odometer(self):...
def update_odometer(self,mileage):
"""将里程表读数设为指定值"""
self.odometer_reading = mileage
my_new_car = Car('audi','a4','2019')
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(65)
my_new_car.read_odometer()
>>>2019 Audi A4
>>>This car has 65 miles.
2.2.3:通过方法对属性的值进行递增
class Car(object):
def __init__(self, make, model, year):...
def get_descriptive_name(self):...
def read_odometer(self):...
def update_odometer(self,mileage):...
def increment_odometer(self,miles):
"""将里程表读取数增加指定的量"""
self.odometer_reading += miles
my_new_car = Car('audi', 'a4', '2019')
my_new_car.update_odometer(23450)
my_new_car.read_odometer()
my_new_car.increment_odometer(100)
my_new_car.read_odometer()
>>>This car has 23450 miles.
>>>This car has 23550 miles.
三:继承
一个类继承另一个类时,它将自动获得另一个类的所有属性和方法。原有的类称为父类 ,而新类称为子类 。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
3.1子类的方法__init__()
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。
class Car(object):
def __init__(self, make, model, year):...
def get_descriptive_name(self):...
def read_odometer(self):...
def update_odometer(self,mileage):...
def increment_odometer(self,miles):...
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类的属性"""
super().__init__(make,model,year)
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
>>>2019 Tesla Model S
创建子类时,父类必须包含在当前文件中,且位于子类前面。
定义子类时,必须在括号内指定父类的名称。
类ElectricCar中方法__init__() 接受创建Car实例所需的信息。
super() 是一个特殊函数,帮助Python将父类和子类关联起来。父类也称为超类(superclass)
super().__init__(make,model,year)
这行代码让Python调用ElectricCar的父类的方法__init__(),让ElectricCar 实例包含父类的所有属性。
my_tesla = ElectricCar('tesla', 'model s', 2019)
这行代码调用ElectricCar 类中定义的方法__init__(),后者让Python调用父类Car中定义的方法__init__() 。
3.2给子类定义方法和属性
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类的属性,初始化电动车特有的属性"""
super().__init__(make, model, year)
self.battery_size = 70
def describe_battery(self):
print("This car has a " + str(self.battery_size) + "-kWh battery")
my_tesla = ElectricCar('tesla', 'model s', 2019)
my_tesla.describe_battery()
>>>This car has a 70-kWh battery
3.3重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个与要重写的父类方法同名的方法。Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
假设Car类中有一个名为fill_gas_tank() 的方法,你可以重写它:
class ElectricCar(Car):...
def fill_gas_tank(self):
print("No gas tank")
Python将忽略Car类中的方法fill_gas_tank() ,转而运行上述代码。子类去父类糟粕取父类精华。
3.4将实例用作属性
不断给ElectricCar类添加细节时,会发现其中包含很多专门针对汽车电瓶的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为Battery的类中,并将一个Battery实例用作ElectricCar类的一个属性:
class Car(object):...
class Battery(object):
"""模拟电动汽车电瓶"""
def __init__(self,battery_size=70):
"""初始化电瓶特性"""
self.battery_size = battery_size
def describe_battery(self):
print("This car has a " + str(self.battery_size) + "-kWh battery.")
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类的属性,初始化电动车特有的属性"""
super().__init__(make, model, year)
self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2019)
my_tesla.battery.describe_battery()
>>>This car has a 70-kWh battery.
self.battery = Battery()
此处添加了一个名为self.battery的属性。这行代码让Python创建一个新的Battery实例(由于没有指定尺寸,因此battery_size为默认值70),并将该实例存储在属性self.battery中。每当方法__init__() 被调用时,都将执行该操作;因此现在每个ElectricCar 实例都包含一个自动创建的Battery实例。
my_tesla.battery.describe_battery()
这行代码让Python在实例my_tesla中查找属性battery,并对存储在该属性中的Battery实例调用方法describe_battery() 。
3.5语句摘录
解决问题从较高的逻辑层面(而不是语法层面)考虑。你考虑的不是Python,而是如何使用代码来表示实物。到达这种境界后,你经常会发现,现实世界的建模方法并没有对错之分。有些方法的效率更高,但要找出效率最高的表示法,需要经过一定的实践。只要代码像你希望的那样运行,就说明你做得很好!即便你发现自己不得不多次尝试使用不同的方法来重写类,也不必气馁;要编写出高效、准确的代码,都得经过这样的过程。