1、摘要
面向对象编程 是最有效的软件编写方法之一。在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来建立对象。编写类时,你定义一大类对象都有的通用行为。基于类建立对象 时,每一个对象都自动具有这种通用行为,而后可根据须要赋予每一个对象独特的个性。使用面向对象编程可模拟现实情景,其逼真程度达到了令你惊讶的地步。根据类来建立对象被称为实例化 ,这让你可以使用类的实例。
2、建立和使用类
使用类几乎能够模拟任何东西。
下面来编写一个表示小狗的简单类Dog ——它表示的不是特定的小狗,而是任何小狗。对于大多数宠物狗,咱们都知道些什么呢?它们都有名字和年龄;咱们还知道,大多数小狗还会蹲下和打滚。因为大多数小狗都具有上述两项信息(名字和年龄)和两种行为(蹲下和打滚),咱们的Dog 类将包含它们。这个类让Python知道如何建立表示小狗的对象。编写这个类后,咱们将使用它来建立表示特定小狗的实例。
复制代码
class Dog():
"""一次模拟小狗的简单尝试"""
def __init__(self, name, age):
"""初始化属性name和age"""
self.name = name
self.age = age
def sit(self):
"""模拟小狗被命令时蹲下"""
print(self.name.title() + " is now sitting.")
def roll_over(self):
"""模拟小狗被命令时打滚"""
print(self.name.title() + " rolled over!")
复制代码
__init__() 是一个特殊的方法,每当你根据Dog 类建立新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突
咱们将方法__init__() 定义成了包含三个形参:self 、name 和age 。在这个方法的定义中,形参self 必不可少,还必须位于其余形参的前面。为什么必须在方法定义中包含形参self 呢?由于Python调用这个__init__() 方法来建立Dog 实例时,将自动传入实参self 。每一个与类相关联的方法调用都自动传递实参self ,它是一个指向实例自己的引用,让实例可以访问类中的属性和方法。咱们建立Dog 实例时,Python将调用Dog 类的方法__init__()
咱们将经过实参向Dog() 传递名字和年龄;self 会自动传递,所以咱们不须要传递它。每当咱们根据Dog 类建立实例时,都只需给最后两个形参(name 和age )提供值
处定义的两个变量都有前缀self 。以self 为前缀的变量均可供类中的全部方法使用,咱们还能够经过类的任何实例来访问这些变量。self.name = name 获取存储在形参name 中的值,并将其存储到变量name 中,而后该变量被关联到当前建立的实例。self.age = age 的做用与此相似。像这样可经过实例访问的变量称为属性
Dog 类还定义了另外两个方法:sit() 和roll_over(),因为这些方法不须要额外的信息,如名字或年龄,所以它们只有一个形参self 。咱们后面将建立的实例可以访问这些方法,换句话说,它们都会蹲下和打滚。当前,sit() 和roll_over() 所作的有限,它们只是打印一条消息,指出小狗正蹲下或打滚。但能够扩展这些方法以模拟实际状况:若是这个类包含在一个计算机游戏中,这些方法将包含建立小狗蹲下和打滚动画效果的代码。若是这个类是用于控制机器狗的,这些方法将引导机器狗作出蹲下和打滚的动做
根据类建立实例:
class Dog():
--snip--
my_dog = Dog('willie', 6)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
咱们让Python建立一条名字为'willie' 、年龄为6 的小狗。遇到这行代码时,Python使用实参'willie' 和6 调用Dog 类中的方法__init__() 。方法__init__() 建立一个表示特定小狗的示例,并使用咱们提供的值来设置属性name 和age 。方法__init__() 并未显式地包含return 语句,但Python自动返回一个表示这条小狗的实例。咱们将这个实例存储在变量my_dog 中。在这里,命名约定颇有用:咱们一般能够认为首字母大写的名称(如Dog )指的是类,而小写的名称(如my_dog )指的是根据类建立的实例
访问属性:
要访问实例的属性,可以使用句点表示法,以下代码来访问my_dog 的属性name 的值:
my_dog.name
句点表示法在Python中很经常使用,这种语法演示了Python如何获悉属性的值。在这里,Python先找到实例my_dog ,再查找与这个实例相关联的属性name 。在Dog 类中引用这个属性时,使用的是self.name 。咱们使用一样的方法来获取属性age 的值。在前面的第1条print 语句中,my_dog.name.title() 将my_dog 的属性name 的值'willie' 改成首字母大写的;在第2条print 语句中,str(my_dog.age) 将my_dog 的属性age 的值6 转换为字符串。输出是有关my_dog 的摘要:
My dog's name is Willie.
My dog is 6 years old.
调用方法:
根据Dog 类建立实例后,就可使用句点表示法来调用Dog 类中定义的任何方法
复制代码
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
复制代码
要调用方法,可指定实例的名称(这里是my_dog )和要调用的方法,并用句点分隔它们。遇到代码my_dog.sit() 时,Python在类Dog 中查找方法sit() 并运行其代码。Python以一样的方式解读代码my_dog.roll_over()
Willie is now sitting.
Willie rolled over!
在命名上,若是给属性和方法指定了合适的描述性名称,如name 、age 、sit() 和roll_over() ,即使是从未见过的代码块,咱们也可以轻松地推断出它是作什么的
建立多个实例:
复制代码
class Dog():
--snip--
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit()
print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()
复制代码
就算咱们给第二条小狗指定一样的名字和年龄,Python依然会根据Dog 类建立另外一个实例。你可按需求根据一个类建立任意数量的实例,条件是将每一个实例都存储在不一样的变量中,或占用列表或字典的不一样位置。
3、使用类和实例
你可使用类来模拟现实世界中的不少情景。类编写好后,你的大部分时间都将花在使用根据类建立的实例上。你须要执行的一个重要任务是修改实例的属性。你能够直接修改实例的属性,也能够编写方法以特定的方式进行修改。
复制代码
class Car():
"""一次模拟汽车的简单尝试"""
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', 2016)
print(my_new_car.get_descriptive_name())
复制代码
定义了方法__init__() 。与前面的Dog 类中同样,这个方法的第一个形参为self ;咱们还在这个方法中包含了另外三个形参:make 、model 和year 。方法__init__() 接受这些形参的值,并将它们存储在根据这个类建立的实例的属性中。建立新的Car 实例时,咱们须要指定其制造商、型号和生产年份
定义了一个名为get_descriptive_name() 的方法,它使用属性year 、make 和model 建立一个对汽车进行描述的字符串,让咱们无需分别打印每一个属性的值。为在这个方法中访问属性的值,咱们使用了self.make 、self.model 和self.year 。
咱们根据Car 类建立了一个实例,并将其存储到变量my_new_car中。接下来,咱们调用方法get_descriptive_name() ,指出咱们拥有的是一辆什么样的汽车:
2016 Audi A4
给属性指定默认值:
复制代码
class Car():
def __init__(self, make,www.michenggw.com model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
--snip--
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has " + str(self.odometer_reading) + " miles on it.")
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
复制代码
当Python调用方法__init__() 来建立新实例时,将像前一个示例同样以属性的方式存储制造商、型号和生产年份。接下来,Python将建立一个名为odometer_reading 的属性,并将其初始值设置为0。
咱们还定义了一个名为read_odometer() 的方法,它让你可以轻松地获悉汽车的里程。一开始汽车的里程为0:
2016 Audi A4
This car has 0 miles on it.
修改属性的值:
能够以三种不一样的方式修改属性的值:直接经过实例进行修改;经过方法进行设置;经过方法进行递增(增长特定的值)
直接修改属性的值:
复制代码
class Car():
--snip--
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer(www.dasheng178.com)
复制代码
咱们使用句点表示法来直接访问并设置汽车的属性odometer_reading 。这行代码让Python在实例my_new_car 中找到属性odometer_reading ,并将该属性的值设置为23:
2016 Audi A4
This car has 23 miles on it.
经过方法修改属性的值:
若是有替你更新属性的方法,将大有裨益。这样,你就无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新
复制代码
class Car():
--snip--
def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
复制代码
添加了方法update_odometer() 。这个方法接受一个里程值,并将其存储到self.odometer_reading 中。
咱们调用了update_odometer() ,并向它提供了实参23(该实参对应于方法定义中的形参mileage)。它将里程表读数设置为23;而方法read_odometer() 打印该读数:
2016 Audi A4
This car has 23 miles on it.
再看一个例子:
复制代码
class Car():
--snip--
def update_odometer(self, mileage):
"""
将里程表读数设置为指定的值
禁止将里程表读数往回调
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
复制代码
update_odometer() 在修改属性前检查指定的读数是否合理。若是新指定的里程(mileage )大于或等于原来的里程(self.odometer_reading ),就将里程表读数改成新指定的里程
不然就发出警告,指出不能将里程表往回拨
经过方法对属性的值进行递增:
复制代码
class Car():
--snip--
def update_odometer(self, mileage):
--snip--
def increment_odometer(self, miles):
"""将里程表读数增长指定的量"""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
复制代码
新增的方法increment_odometer() 接受一个单位为英里的数字,并将其加入到self.odometer_reading 中。
咱们建立了一辆二手车my_used_car,调用方法update_odometer() 并传入23500 ,将这辆二手车的里程表读数设置为23 500。
咱们调用increment_odometer()并传入100 ,以增长从购买到登记期间行驶的100英里:
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
你能够轻松地修改这个方法,以禁止增量为负值,从而防止有人利用它来回拨里程表。
注意:你可使用相似于上面的方法来控制用户修改属性值(如里程表读数)的方式,但可以访问程序的人均可以经过直接访问属性来将里程表修改成任何值。要确保安全,除了进行相似于前面的基本检查外,还需特别注意细节。
4、继承
编写类时,并不是老是要从空白开始。若是你要编写的类是另外一个现成类的特殊版本,可以使用继承 。一个类继承 另外一个类时,它将自动得到另外一个类的全部属性和方法;原有的类称为父类 ,而新类称为子类 。子类继承了其父类的全部属性和方法,同时还能够定义本身的属性和方法。
子类的方法__init__():
复制代码
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(www.yigouyule2.cn self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
self.odometer_reading += miles
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())
复制代码
首先是Car 类的代码。建立子类时,父类必须包含在当前文件中,且位于子类前面
定义了子类ElectricCar 。定义子类时,必须在括号内指定父类的名称。方法__init__() 接受建立Car 实例所需的信息
super() 是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar 的父类的方法__init__() ,让ElectricCar 实例包含父类的全部属性。父类也称为超类 (superclass),名称super所以而得名
为测试继承是否可以正确地发挥做用,咱们尝试建立一辆电动汽车ElectricCar 类的一个实例,但提供的信息与建立普通汽车时相同,并将其存储在变量my_tesla 中。这行代码调用ElectricCar 类中定义的方法__init__() ,后者让Python调用父类Car 中定义的方法__init__() 。咱们提供了实参'tesla' 、'models' 和2016
除方法__init__() 外,电动汽车没有其余特有的属性和方法。当前,咱们只想确认电动汽车具有普通汽车的行为:
2016 Tesla Model S
给子类定义属性和方法:
复制代码
class Car():
--snip--
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
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(www.078881.cn/'tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
复制代码
添加了新属性self.battery_size ,并设置其初始值(如70 )。根据ElectricCar 类建立的全部实例都将包含这个属性,但全部Car 实例都不包含它。
添加了一个名为describe_battery() 的方法,它打印有关电瓶的信息。咱们调用这个方法时,将看到一条电动汽车特有的描述:
2016 Tesla Model S
This car has a 70-kWh battery.
对于ElectricCar 类的特殊化程度没有任何限制。模拟电动汽车时,你能够根据所需的准确程度添加任意数量的属性和方法。若是一个属性或方法是任何汽车都有的,而不是电动汽车特有的,就应将其加入到Car 类而不是ElectricCar 类中。这样,使用Car 类的人将得到相应的功能,而ElectricCar 类只包含处理电动汽车特有属性和行为的代码
重写父类的方法:
对于父类的方法,只要它不符合子类模拟的实物的行为,均可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。假设Car 类有一个名为fill_gas_tank() 的方法,它对全电动汽车来讲毫无心义,所以你可能想重写它。下面演示了一种重写方式:
def ElectricCar(Car):
--snip--
def fill_gas_tank():
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank!")
如今,若是有人对电动汽车调用方法fill_gas_tank() ,Python将忽略Car 类中的方法fill_gas_tank() ,转而运行上述代码。使用继承时,可以让子类保留从父类那里继承而来的精华,并剔除不须要的糟粕。
将实例用做属性:
使用代码模拟实物时,你可能会发现本身给类添加的细节愈来愈多:属性和方法清单以及文件都愈来愈长。在这种状况下,可能须要将类的一部分做为一个独立的类提取出来。你能够将大型类拆分红多个协同工做的小类。
例如,不断给ElectricCar 类添加细节时,咱们可能会发现其中包含不少专门针对汽车电瓶的属性和方法。在这种状况下,咱们可将这些属性和方法提取出来,放到另外一个名为Battery 的类中,并将一个Battery 实例用做ElectricCar 类的一个属性:
复制代码
class Car():
--snip--
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()
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
复制代码
定义了一个名为Battery 的新类,它没有继承任何类,__init__() 除self 外,还有另外一个形参battery_size 。这个形参是可选的:若是没有给它提供值,电瓶容量将被设置为70。方法describe_battery() 也移到了这个类中
在ElectricCar 类中,咱们添加了一个名为self.battery 的属性,这行代码让Python建立一个新的Battery 实例(因为没有指定尺寸,所以为默认值70 ),并将该实例存储在属性self.battery 中。每当方法__init__() 被调用时,都将执行该操做;所以如今每一个ElectricCar 实例都包含一个自动建立的Battery 实例。
咱们建立一辆电动汽车,并将其存储在变量my_tesla 中。要描述电瓶时,须要使用电动汽车的属性battery :
my_tesla.battery.describe_battery()
这行代码让Python在实例my_tesla 中查找属性battery ,并对存储在该属性中的Battery 实例调用方法describe_battery()
执行结果为:
2016 Tesla Model S
This car has a 70-kWh battery.
这看似作了不少额外的工做,但如今咱们想多详细地描述电瓶均可以,且不会致使ElectricCar 类混乱不堪。下面再给Battery 类添加一个方法,它根据电瓶容量报告汽车的续航里程:
复制代码
class Car():
--snip--
class Battery():
--snip--
def get_range(self www.feifanyule.cn/):
"""打印一条消息,指出电瓶的续航里程"""
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
--snip--
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
复制代码
新增的方法get_range() 作了一些简单的分析:若是电瓶的容量为70kWh,它就将续航里程设置为240英里;若是容量为85kWh,就将续航里程设置为270英里,而后报告这个值。为使用这个方法,咱们也经过汽车的属性battery 来调用它
输出指出了汽车的续航里程(这取决于电瓶的容量):
执行结果为:
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
模拟较复杂的物件(如电动汽车)时,须要解决一些有趣的问题。续航里程是电瓶的属性仍是汽车的属性呢?若是咱们只需描述一辆汽车,那么将方法get_range() 放在Battery 类中也许是合适的;但若是要描述一家汽车制造商的整个产品线,也许应该将方法get_range() 移到ElectricCar 类中。在这种状况下,get_range() 依然根据电瓶容量来肯定续航里程,但报告的是一款汽车的续航里程。咱们也能够这样作:将方法get_range() 还留在Battery 类中,但向它传递一个参数,如car_model ;在这种状况下,方法get_range() 将根据电瓶容量和汽车型号报告续航里程。这让你进入了程序员的另外一个境界:解决上述问题时,你从较高的逻辑层面(而不是语法层面)考虑;你考虑的不是Python,而是如何使用代码来表示实物。到达这种境界后,你常常会发现,现实世界的建模方法并无对错之分。有些方法的效率更高,但要找出效率最高的表示法,须要通过必定的实践。只要代码像你但愿的那样运行,就说明你作得很好!即使你发现本身不得很少次尝试使用不一样的方法来重写类,也没必要气馁;要编写出高效、准确的代码,都得通过这样的过程。
5、导入类
随着你不断地给类添加功能,文件可能变得很长,即使你妥善地使用了继承亦如此。为遵循Python的整体理念,应让文件尽量整洁。为在这方面提供帮助,Python容许你将类存储在模块中,而后在主程序中导入所需的模块。
建立car.py文件,并写入以下代码:
复制代码
"""一个可用于表示汽车的类"""
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回整洁的描述性名称"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""打印一条消息,指出汽车的里程"""
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
"""
将里程表读数设置为指定的值
拒绝将里程表往回拨
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""将里程表读数增长指定的量"""
self.odometer_reading += miles
复制代码
文件的开头,包含了一个模块级文档字符串,对该模块的内容作了简要的描述。你应为本身建立的每一个模块都编写文档字符串。
from car import Car
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
import 语句让Python打开模块car ,并导入其中的Car 类。这样咱们就可使用Car 类了,就像它是在这个文件中定义的同样。输出与咱们在前面看到的同样:
执行结果为:
2016 Audi A4
This car has 23 miles on it.
虽然同一个模块中的类之间应存在某种相关性,但可根据须要在一个模块中存储任意数量的类。类Battery 和ElectricCar 均可帮助模拟汽车,所以下面将它们都加入模块car.py中:
复制代码
"""一组用于表示燃油汽车和电动汽车的类"""
class Car():
--snip--
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self, battery_size=60):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
def get_range(self):
"""打印一条描述电瓶续航里程的消息"""
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
"""模拟电动汽车的独特之处"""
def __init__(self, make, model, year):
"""
初始化父类的属性,再初始化电动汽车特有的属性
"""
super().__init__(make, model, year)
self.battery = Battery()
复制代码
咱们就能够import ElectricCar类了
复制代码
from car import ElectricCar
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
复制代码
执行结果为:
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
可根据须要在程序文件中导入任意数量的类。若是咱们要在同一个程序中建立普通汽车和电动汽车,就须要将Car 和ElectricCar 类都导入:
复制代码
from car import Car, ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
复制代码
执行结果为:
2016 Volkswagen Beetle
2016 Tesla Roadster
6、导入整个模块
你还能够导入整个模块,再使用句点表示法访问须要的类。这种导入方法很简单,代码也易于阅读。因为建立类实例的代码都包含模块名,所以不会与当前文件使用的任何名称发生冲突。
复制代码
import car
my_beetle = car.Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = car.ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
复制代码
导入了整个car 模块。接下来,使用语法 module_name.class_name 访问须要的类。
导入模块中的全部类:
from module_name import *
不推荐使用这种导入方式,其缘由有二。首先,若是只要看一下文件开头的import 语句,就能清楚地知道程序使用了哪些类,将大有裨益;但这种导入方式没有明确地指出你使用了模块中的哪些类。这种导入方式还可能引起名称方面的困惑。若是你不当心导入了一个与程序文件中其余东西同名的类,将引起难以诊断的错误。这里之因此介绍这种导入方式,是由于虽然不推荐使用这种方式,但你可能会在别人编写的代码中见到它。须要从一个模块中导入不少类时,最好导入整个模块,并使用 module_name.class_name 语法来访问类。这样作时,虽然文件开头并无列出用到的全部类,但你清楚地知道在程序的哪些地方使用了导入的模块;你还避免了导入模块中的每一个类可能引起的名称冲突。
在一个模块中导入另外一个模块:
有时候,须要将类分散到多个模块中,以避免模块太大,或在同一个模块中存储不相关的类。将类存储在多个模块中时,你可能会发现一个模块中的类依赖于另外一个模块中的类。在这种状况下,可在前一个模块中导入必要的类。例如,下面将Car 类存储在一个模块中,并将ElectricCar 和Battery 类存储在另外一个模块中。咱们将第二个模块命名为electric_car.py
car.py
复制代码
"""A class that can be used to represent a car."""
class Car():
"""A simple attempt to represent a car."""
def __init__(self, manufacturer, model, year):
"""Initialize attributes to describe a car."""
self.manufacturer = manufacturer
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
"""
Set the odometer reading to the given value.
Reject the change if it attempts to roll the odometer back.
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
复制代码
electric_car.py
复制代码
"""A set of classes that can be used to represent electric cars."""
from car import Car
class Battery():
"""A simple attempt to model a battery for an electric car."""
def __init__(self, battery_size=60):
"""Initialize the batteery's attributes."""
self.battery_size = battery_size
def describe_battery(self):
"""Print a statement describing the battery size."""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
def get_range(self):
"""Print a statement about the range this battery provides."""
if self.battery_size == 60:
range = 140
elif self.battery_size == 85:
range = 185
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
"""Models aspects of a car, specific to electric vehicles."""
def __init__(self, manufacturer, model, year):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
super().__init__(manufacturer, model, year)
self.battery = Battery()
复制代码
ElectricCar 类须要访问其父类Car ,所以咱们直接将Car 类导入该模块中
复制代码
from car import Car
from electric_car import ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2015)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2015)
print(my_tesla.get_descriptive_name())
复制代码
从模块car 中导入了Car 类,并从模块electric_car 中导入ElectricCar 类。接下来,咱们建立了一辆普通汽车和一辆电动汽车。这两种汽车都得以正确地建立:
2016 Volkswagen Beetle
2016 Tesla Roadster
正如你看到的,在组织大型项目的代码方面,Python提供了不少选项。熟悉全部这些选项很重要,这样你才能肯定哪一种项目组织方式是最佳的,并能理解别人开发的项目。一开始应让代码结构尽量简单。先尽量在一个文件中完成全部的工做,肯定一切都能正确运行后,再将类移到独立的模块中。若是你喜欢模块和文件的交互方式,可在项目开始时就尝试将类存储到模块中。先找出让你可以编写出可行代码的方式,再尝试让代码更为组织有序。
7、Python标准库
Python标准库 是一组模块,安装的Python都包含它。你如今对类的工做原理已有大体的了解,能够开始使用其余程序员编写好的模块了。可以使用标准库中的任何函数和类,为此只需在程序开头包含一条简单的import 语句。下面来看模块collections 中的一个类——OrderedDict
字典让你可以将信息关联起来,但它们不记录你添加键值对的顺序。要建立字典并记录其中的键—值对的添加顺序,可以使用模块collections 中的OrderedDict类。OrderedDict 实例的行为几乎与字典相同,区别只在于记录了键值对的添加顺序。
复制代码
from collections import OrderedDict
favorite_languages = OrderedDict()
favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'
for name, language in favorite_languages.items():
print(name.title() + "'s favorite language is " +
language.title() + ".")
复制代码
从模块collections 中导入了OrderedDict 类而后建立了OrderedDict 类的一个实例,并将其存储到favorite_languages 中。请注意,这里没有使用花括号,而是调用OrderedDict() 来建立一个空的有序字典,并将其存储在favorite_languages 中
接下来,咱们以每次一对的方式添加名字语言对,而后遍历favorite_languages ,将以添加的顺序获取调查结果:
Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Python.
这是一个很不错的类,它兼具列表和字典的主要优势(在将信息关联起来的同时保留原来的顺序)。等你开始对关心的现实情形建模时,可能会发现有序字典正好可以知足需求。随着你对标准库的了解愈来愈深刻,将熟悉大量可帮助你处理常见情形的模块。
8、编码规范
类名应采用驼峰命名法 ,即将类名中的每一个单词的首字母都大写,而不使用下划线。
实例名和模块名都采用小写格式,并在单词之间加上下划线。
对于每一个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每一个模块也都应包含一个文档字符串,对其中的类可用于作什么进行描述。
可以使用空行来组织代码,但不要滥用。在类中,可以使用一个空行来分隔方法;而在模块中,可以使用两个空行来分隔类。
须要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import 语句,再添加一个空行,而后编写导入你本身编写的模块的import 语句。在包含多条import 语句的程序中,这种作法让人更容易明白程序使用的各个模块都来自何方。python