创建和使用类
使用类几乎可以模拟任何东西。下面编写一个表示小狗的简单类Dog:它包含了两项信息(名字和年龄)和两种行为(蹲下和打滚)。根据约定,在Python中,首字母大写的名称指的是类。这个类定义中的括号是空的,因为我们要从空白创建这个类。
class Dog():
'''doc string'''
def __init__(self, name, age):
'''doc string'''
self.name = name
self.age = age
def sit(self):
'''doc string'''
print(self.name.title() +' is now sitting.')
def roll_over(self):
'''doc string'''
print(self.name.title() + ' rolled over!')
方法__init__()
类中的函数称为方法。__init__()是一个特殊的方法,每当你根据Dog类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。
我们将方法__init__()定义成了包含三个形参:self,name和age。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。为何必须在方法中包含形参self呢?因为Python调用这个__init__()方法来创建Dog实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建Dog实例时,Python将自动调用Dog类的方法__init__()。我们将通过实参向Dog()传递名字和年龄;self会自动传递,因此我们不需要传递它。
以self为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。如此例中的age和name属性。
在Python2.7中创建类时,需要做细微的修改——在括号内包含单词object:
class ClassName(object):
根据类创建实例并访问它的属性和方法
class Dog():
'''doc string'''
def __init__(self, name, age):
'''doc string'''
self.name = name
self.age = age
def sit(self):
'''doc string'''
print(self.name.title() +' is now sitting.')
def roll_over(self):
'''doc string'''
print(self.name.title() + ' rolled over!')
my_dog = Dog('honey',6)
your_dog=Dog('shit',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("Your dog's name is " + your_dog.name.title() + '.')
print("Yuur dog is " + str(your_dog.age) + ' years old.')
your_dog.sit()
使用类和实例
你可以实用类来模拟现实生活中很多情景。类编写好后,你的大部分时间都将花在使用根据类创建的实例上。你需要执行的一个重要任务是修改实例的属性。你可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
class Car():
'''doc string'''
def __init__(self,make,model,year):
'''init car's props'''
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
'''return descriptive info'''
long_name=str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
''' doc string '''
print('This car has ' + str(self.odometer_reading) + 'miles on it.')
def update_odometer(self,mileage):
'''doc string'''
if mileage >= self.odometer_reading:
self.odometer_reading=mileage
else:
print("You can't roll back an odometer!")
def increment_olometer(self,miles):
"""doc string """
self.odometer_reading+=miles
my_new_car=Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading=23
my_new_car.update_odometer(88)
my_new_car.read_odometer()
继承
编写类时并非总是从空白开始。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法,同时还可以定义自己的属性和方法。原来的类成为父类,或超类,新类称为子类。
创建子类时,父类必须包含在当前文件中,且位于子类前面;定义子类时,必须在括号内指定父类的名称。super()是一个特殊函数,帮助python将父类和子类联系起来。
下面的例子子类中新定义了属性和方法,并重写了父类的方法increment_olometer
class Car():
'''doc string'''
def __init__(self,make,model,year):
'''init car's props'''
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
'''return descriptive info'''
long_name=str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
''' doc string '''
print('This car has ' + str(self.odometer_reading) + 'miles on it.')
def update_odometer(self,mileage):
'''doc string'''
if mileage >= self.odometer_reading:
self.odometer_reading=mileage
else:
print("You can't roll back an odometer!")
def increment_olometer(self,miles):
"""doc string """
self.odometer_reading+=miles
class Battery():
'''doc string'''
def __init__(self,battery_size=70):
'''doc string'''
self.battery_size=battery_size
def describe_battery(self):
'''print battery size'''
print('This car has a ' + str(self.battery_size) + '-kWh battery.')
class ElectricCar(Car):
'''doc string '''
def __init__(self,make,model,year):
'''init father class' prop'''
super().__init__(make,model,year)
self.battery = Battery()
def increment_olometer(self,miles):
'''override method'''
print('Nothing to do. Just override method.')
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.increment_olometer(22)
python2.7中的继承稍有不同:定义父类时括号内需制定object,子类中super需要两个实参:子类名和对象self。
class Car(object):
'''super class'''
def __init__(self,make,model,year):
--snip--
class ElectricCar(Car):
'''doc string'''
def __init__(self,make,model,year):
super(ElectricCar,self).__init__(make,model,year)
--snip--
随着你不断地给类添加新功能,文件可能变得很长。Python允许你将类存储在模块(文件)中,然后在主程序中导入所需的模块。
导入单个类 from module_name import class_name
导入多个类 from module_name import class_nameA,class_nameB
导入整个模块 import module_name
导入模块中所有类 from module_name import *(不推荐此方式,一是不清楚程序究竟使用了哪些类;二是有可能引发名称冲突,引发难以诊断的错误)
Python标准库
Python标准库是一组模块,安装python都包含它。下面我们来看模块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() + '.')
类编码风格
- 类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
- 对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。
- 可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分割方法;而在模块中,可使用两个空行来分隔类。
- 需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句,再添加一个空行,然后编写导入你自己编写的模块的import语句。