面向对象是最有效的软件编写方法之一。在本章中,你将编写一些类并创建其实例。你将指定可在实例中存储什么信息,定义可对这些实例执行哪些操作。你还将编写一些类来扩展既有类的功能,让相似的类能够高效地共享代码。你还将把自己编写的类存储在模块中,并在自己的程序文件中导入其他程序员编写的类。
1. 创建和使用类 使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类Dog。
1.1创建Dog类 1 2 3 4 5 6 7 8 9 10 11 12 class Dog (): '''dog class dog 类''' def __init__ (self, name, age ): '''init name, age 初始化name,age''' self.name = name self.age = age def sit (self ): '''sit when be ordered 被命令时蹲下''' print (self.name.title() + " is now sitting." ) def roll_over (self ): '''roll_over when be ordered 被命令时蹲下''' print (self.name.title() + " rolled over!" )
方法_init _()是一个特殊的方法,每当你根据Dog类创建新实例时,Python会自动运行它。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。
1.2根据类创建实例 创建实例:
1 my_dog = Dog('willie' , 6 )
调用属性:
1 2 3 4 5 print ("My dog's name is " + my_dog.name.title() + "." )print ("My dog is " + str (my_dog.age) + " years old." ) My dog’s name is Willie. My dog is 6 years old.
调用方法:
1 2 3 4 5 my_dog.sit() my_dog.roll_over() Willie is now sitting. Willie rolled over!
2. 使用类和实例 类编写好后,你的大部分时 间都将花在使用根据类创建的实例上。你需要执行的一个重要任务是修改 实例的属性。你可以直接修改实例的属性,也可以编写方法以特定的方式 进行修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Car (): """一次模拟汽车的简单尝试""" def __init__ (self, make, model, year ): """初始化描述汽车的属性""" self.make = make self.model = model self.year = year self.odometer_reading = 10 def get_descriptive_name (self ): """返回整洁的描性信息""" long_name = str (self.year) + ' ' + self.make + ' ' + self.model return long_name.title() def update_year (self, year ): """将年份修为指定的值""" self.year = year def increment_odometer (self, miles ): """将里程读数增加指定的量""" self.odometer_reading += miles def fill_gas_tank (self ): """加满油箱""" print ("This car has been filled!" ) my_new_car = Car('audi' , 'a4' , 2016 )print (my_new_car.get_descriptive_name()) my_new_car.year = 2019 print (my_new_car.get_descriptive_name()) my_new_car.update_year(2021 )print (my_new_car.get_descriptive_name()) my_new_car.increment_odometer(100 )print (my_new_car.odometer_reading) my_new_car.fill_gas_tank()
3. 继承 编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
1 2 isinstance (对象,类) issubclass (子类,父类)
3.1子类的方法_init _() 创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法_init _() 需要父类施以援手。
1 2 3 4 5 6 7 8 9 class ElectricCar (Car ): """电动汽车的独特之处""" def __init__ (self, make, model, year ): """初始化父类的属性""" super ().__init__(make, model, year) my_tesla = ElectricCar('tesla' , 'model s' , 2016 )print (my_tesla.get_descriptive_name())
3.2重写父类的方法 对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名 。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法 。
1 2 3 4 5 6 7 8 9 10 11 12 class ElectricCar (Car ): """电动汽车的独特之处""" def __init__ (self, make, model, year ): """初始化父类的属性""" super ().__init__(make, model, year) def fill_gas_tank (self ): """电动汽车没有油箱""" print ("This car doesn't need a gas tank!" ) my_tesla = ElectricCar('tesla' , 'model s' , 2016 ) my_tesla.fill_gas_tank()
3.3将实例用作属性 使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Battery (): """一次模拟电动汽车电瓶的简单尝试""" 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() def fill_gas_tank (self ): """电动汽车没有油箱""" print ("This car doesn't need a gas tank!" ) my_tesla = ElectricCar('tesla' , 'model s' , 2016 ) my_tesla.battery.describe_battery()
4. 导入类 1 2 3 4 5 6 7 8 from car import Carfrom car import Car, ElectricCarimport carfrom car import *
5. 类方法与实例方法 上述介绍的方法调用都为实例方法,实例方法 需要一个特定的对象实例。类方法 的使用不需要特定的实例对象。
1 2 3 4 5 6 7 8 9 10 11 12 class Point : def __init__ (self, x, y ): self.x = x self.y = y @classmethod def zero (cls ): return cls(0 , 0 ) def draw (self ): print (f"Point ({self.x} , {self.y} )" ) point = Point.zero()
6. magic methods python magic methods
是一个很好magic methods指南。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Point : def __init__ (self, x, y ): self.x = x self.y = y def __eq__ (self, other ): return self.x == other.x and self.y == other.y def __gt__ (self, other ): return self.x > other.x and self.y > other.y def __add__ (self, other ): return Point(self.x + other.x, self.y + other.y) point = Point(1 , 2 ) other = Point(1 , 2 )print (point == other) print (point > other) combined = point + otherprint (combined.x, combined.y)
7. 创建自定义容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class TagCloud : def __init__ (self ): self.tags = {} def add (self, tag ): self.tags[tag] = self.tags.get(tag, 0 ) + 1 def __getitem__ (self, tag ): return self.tags.get(tag, 0 ) def __setitem__ (self, tag, count ): self.tags[tag] = count def __len__ (self ): return len (self.tags) def __iter__ (self ): return iter (self.tags) cloud = TagCloud() cloud.add("python" ) cloud.add("python" ) cloud.add("python" )print (cloud.tags)
8. 私有成员 1 2 3 4 5 self.__tags print (cloud.__dict__) print (cloud._TagCloud__tags)
9. 特性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Product : def __init__ (self, price ): self.__price = price def get_price (self ): return self.__price def set_price (self, value ): if value < 0 : raise ValueError("Price cannot be negative." ) self.__price = value product = Product(-50 ) class Product : def __init__ (self, price ): self.set_price(price) def get_price (self ): return self.__price def set_price (self, value ): if value < 0 : raise ValueError("Price cannot be negative." ) self.__price = value price = property (get_price, set_price) class Product : def __init__ (self, price ): self.price = price @property def price (self ): return self.__price @price.setter def price (self, value ): if value < 0 : raise ValueError("Price cannot be negative." ) self.__price = value product = Product(-50 )
10. 抽象基类(abstract base class)
抽象基类不能被实例化。
子类必须实现父类中的抽象方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from abc import ABC, abstractmethodclass InvalidOperationError (Exception ): pass class Stream (ABC ): def __init__ (self ): self.opened = False def open (self ): if self.opened: raise InvalidOperationError("Stream is already opened." ) self.opened = True def close (self ): if not self.opened: raise InvalidOperationError("Stream is already closed." ) self.opened = False @abstractmethod def read (self ): pass class FileStream (Stream ): def read (self ): print ("Reading data from a file." )class NetworkStream (Stream ): def read (self ): print ("Reading data from a network." ) class MemoryStream (Stream ): pass stream = Stream() stream = MemoryStream()
Python标准库 Python标准库 是一组模块,安装的Python都包含它。你现在对类的工作原 理已有大致的了解,可以开始使用其他程序员编写好的模块了。可使用标准库中的任何函数和类,为此只需在程序开头包含一条简单的import语句。