Chapter 9
类
- 例子(适用于Python3)
class Dog():
"""一次模拟小狗的简单尝试"""
def __init__(self, name, age):
"""初始化属性name与age"""
self.name = name
self.age = age
self.height = 0
def sit(self):
"""模拟小狗蹲下"""
print(self.name.title() + " is now sitting.")
def roll_over(self):
"""模拟小狗打滚儿"""
print(self.name.title() + " is rolling over!")
my_dog = Dog('willie', 5)
print("My dog's name is " + my_dog.name + ", and he is " +
str(my_dog.age) + " years old.")
my_dog.sit()
my_dog.roll_over()
注意:
1.class Dog()
Python中,根据约定,首字母大写的名称指的是类。
2.__init__
类似于C++中的构造函数。为了与其他函数区分,其名称__init__
不可改变,且前后分别有两个下划线
。每次用Dog
类实例化时,都会自动运行这个函数。另外,Python的类中的函数,被称为方法
。
3.self
相当于C++中的this
,只不过C++中是隐性的,Python中是显性的。Python的类中,所有方法的形参都有self
,不能省略
。 另外,在每个方法中,self
还必须位于其他形参的前面。不过,它的传递会自动完成。因此,我们在传入参数时直接忽略它就好。
4.self.name
以self
为前缀的变量,可以在类的所有方法中使用。我们还可以通过类的任意实例来访问它们。我们把像这样可以用实例访问的变量,成为属性
。注意,类中的每个属性都应该有初始值,即使它是0或空字符串。在方法__init__()
中指定初始值是可行的。如果对某个属性这样做了,就无须包含相应形参,例如,本例中的self.height
。
5.my_dog = Dog('willie', 5)
此时,会自动调用__init__
方法。该方法虽然没有显式地写上return
,但会自动返回一个实例。
6.my_dog.sit()
创建实例后,我们就可以使用句点来调用类中的任意方法。需要注意,调用方法时,一定要写上后面的括号()
,否则会出现意料之外的结果(例如,<bound method ElecDog.battery_info of <__main__.ElecDog object at 0x101d5c908>>
)。
- 修改属性的值
直接修改属性的值
class Dog():
--snip--
--snip--
my_dog.name = "Lucky"
#注意:可以修改任何属性的值,即使它们曾经出现在__init__的形参里。
通过方法修改属性的值
class Dog():
--snip--
def change_name(self, new_name):
self.name = new_name
--snip--
my_dog.change_name("Lucky")
- 继承
class Dog():
"""一次模拟小狗的简单尝试"""
def __init__(self, name, age):
"""初始化属性name与age"""
self.name = name
self.age = age
self.height = 0
def sit(self):
"""模拟小狗蹲下"""
print(self.name.title() + " is now sitting.")
def roll_over(self):
"""模拟小狗打滚儿"""
print(self.name.title() + " is rolling over!")
class ElecDog(Dog):
"""继承Dog()类的电子狗类"""
def __init__(self, name, elec_age, battery_size):
"""还要初始化父类"""
super().__init__(name, elec_age)
self.battery = battery_size
def battery_info(self):
"""返回电池容量"""
return(self.battery)
my_e_dog = ElecDog("Lucky", 5, 10000)
print("My dog's name is " + my_e_dog.name + ", and he is " +
str(my_e_dog.age) + " years old.")
my_e_dog.sit()
my_e_dog.roll_over()
print("Battery size is " + str(my_e_dog.battery_info()) + ".")
注意:
1. 创建子类时,父类必须在当前文件
中,而且位于子类的前面。
2.ElecDog(Dog)
定义子类时,必须在括号里指明父类的名称。
3.siper().__init_(name, elec_age)
其中,super()
是一个特殊的函数,将子类与父类连接起来。这行代码让子类调用父类的方法__init__()
,用子类的形参初始化父类,让子类包含父类的所有属性。因为父类也被称为超类superclass
,该函数因此得名。
4.self.battery = battery_size
先初始化父类的属性,而后才初始化子类特有的属性。
5. 对于父类中的方法,如果它不符合子类的需求,子类可以将其重写。只需写一个同名方法即可。这样,实例化子类时,Python就不会考虑父类方法,而是只看子类定义中的相应方法。
- 将实例用作属性。类似于,C++中,将类作为另一个类的成员。
# class Dog():
# """一次模拟小狗的简单尝试"""
# def __init__(self, name, age):
# """初始化属性name与age"""
# self.name = name
# self.age = age
# self.height = 0
# def sit(self):
# """模拟小狗蹲下"""
# print(self.name.title() + " is now sitting.")
# def roll_over(self):
# """模拟小狗打滚儿"""
# print(self.name.title() + " is rolling over!")
class Battery():
"""对电池的简单模拟"""
def __init__(self, battery_size=10000):
"""初始化"""
self.size = battery_size
def show_size(self):
"""显示电池容量"""
return self.size
class ElecDog(Dog):
"""继承Dog()类的电子狗类"""
def __init__(self, name, elec_age, battery_size):
"""还要初始化父类"""
super().__init__(name, elec_age)
self.battery = Battery(battery_size)
# my_e_dog = ElecDog("Lucky", 5, 9999)
# print("My dog's name is " + my_e_dog.name + ", and he is " +
# str(my_e_dog.age) + " years old.")
# my_e_dog.sit()
# my_e_dog.roll_over()
print("Battery size is " + str(my_e_dog.battery.show_size()) + ".")
- 导入类
导入单个类
注意,当我们需要实例化一个子类的时候,只需要把子类和父类放在同一个文件里,再只导入子类即可。如果子类和父类在两个不同的文件中,则需要都导入进来(两个import
)。
from car import Elec_car
从一个模块中导入多个类
用逗号隔开。
from car import Car, Elec_car
导入整个模块
倘若如此,则使用其中的每一个类的时候,都应该用句点。这样也能避免重名带来的一些问题。
import car
导入模块中的所有类
使用星号。但是,不推荐这种方式,原因与不推荐导入一个模块中的所有函数的原因类似。
from car import *
- Python标准库。下面的例子中,展示了利用标准库来实现记录了键-值对添加顺序的字典的方法。
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() + ".")
另外,模块random
包含以各种方式生成随机数的函数。其中的randint(int_1, int_2)
返回满足int_1 <= x <= int_2
的整数。
from random import randint
print( randint(1, 6) )
- 规范
注意:
类名
采用驼峰命名法。即,类名中,每个单词的首字母都大写,并且不使用下划线。
实例名
和模块名
采用小写,并且单词之间使用下划线。
每个类都要有文档字符串
,对类的功能进行简单描述。每个模块也要有,对其中包含了什么类进行简单描述。
在类中,用一个空行
区分方法。在模块中,用两个空格区分类。
先导入标准库中的模块,再导入自己编写的模块。两者之间,用一个空行隔开。