面向对象编程
- 除了之前的字符串,数字,列表,元组和字典等内建对象类型,Python还支持创建自己的对象。
- 作为一门面向对象编程的语言,把面对对象编程的过程叫做面对对象编程(oop : Object Oriented Programming)
类,就是用来描述具有相同属性和方法的对象的集合;类定义了集合中每个对象共有的属性和方法,对象是类的实例
类的定义与使用
class MyClass(): # class ClassName(object):
i = 123 # <statement-1>
def f(self): # .
return 'hello world' # <statement-N>
a = MyClass() # 类的实例化
print(a.i) # obj.name 类属性(变量)的引用
print(a.f()) # obj.method() 类方法的引用
class关键字 + 类的名字 + (object)括号内可不写 + :
类包含属性(i)与方法(f)。
在类中定义方法的形式核函数差不多,但不称为函数。方法的调用需要绑定在特定对象上,而函数不需要
在类中定义方法时,第一个参数必须是 self !
类的构造法 & 访问权限
构造法
class MyClass():
i = 123
def __init__(self,name): # 初始化方法(构造法):所有实例化对象都必须满足此格式。即:除自身(self)外,还应带有一个参数(name)
self.name = name # 通过 obj.name 的方式引用类的name属性
def f(self): # 通过 obj.method() 的方式引用类的方法
return 'hello,' + self.name
a = MyClass('p') # 所有的实例对象都必须满足此类格式,即括号内还有一个对应name的参数
print(a.f()) # hello,p
- __ init__是类中的一个特殊方法,在对象实例化时自动调用;
- __ init__的意思是初始化(initialization),若在定义类时,不显示的定义一个构造法,则程序会默认调用一个无参数的 __ init__()方法;
- 一个类中可以定义多个构造法,但实例化只会调用最后定义个构造法,建议一个类只定义一个构造函数。
访问权限
- 在类中定义的非构造方法可以调用类中构造法的实例变量属性,即self.实例变量名(self.name ; self.score)通过此方法可以在类的外部轻易修改内部属性;
class Student(object):
def __init__(self,name,score):
self.name = name
self.score = score
def info(self):
print(f'学生:{self.name};分数:{self.score}')
stu_1 = Student('David','95')
stu_1.info()
stu_1.score = '100'
stu_1.info()
学生:David;分数:95
学生:David;分数:100
- 若要让内部属性不被外部访问,可在属性名称加两个下划线(__name, __slef),实例的变量(属性)如果以 __开头,就会变成私有变量(private),外部无法直接访问
class Student(object):
def __init__(self,name,score):
self.__name = name # 构造类Student 的私有变量 name
self.__score = score # 构造类Student 的私有变量 score
def info(self): # 定义类Student 的info()方法,可以查询实例的名字,对应分数
print(f'学生:{self.__name};分数:{self.__score}')
stu_1 = Student('David','95')# stu_1作为类Student的一个实例
stu_1.info() # 通过类内部的info()方法间接访问了 name 和 score
stu_1.__score # 直接访问类Student的私有属性score,报错
结果如下
学生:David;分数:95
Traceback (most recent call last):
File "C:/Users/Administrator/PycharmProjects/untitled/venv/文本练习.py", line 148, in <module>
stu_1.__score
AttributeError: 'Student' object has no attribute '__score'
- 若要访问或修改类中的私有属性(变量),可以通过定义方法来实现
class Student(object):
def __init__(self,name,score):
self.__name = name
self.__score = score
def info(self):
print(f'学生:{self.__name};分数:{self.__score}')
def setscore(self,score): # 定义一个专门修改类Student私有属性(变量)的方法
self.__score = score
stu_1 = Student('David','95')
sti_1.info()
stu_1.setscore('20')
stu_1.info()
学生:David;分数:95
学生:David;分数:20
类的继承
继承完全可以理解为类之间的类型和子类型的关系;继承的最大好处是子类将获得父类的全部非私有属性(变量),方法
class DerivedClassName(BaseClassName): # 从BaseClassName类中定义一个DerivedClassName子类
< statements-1 >
.
.
< statements-N >
- 在继承中,子类不会自动调用父类的构造法(__ init__()),需要在子类的构造方中单独调用;
- 在调用父类的方法时需要加上父类的类名前缀,并带上self参数;
- 在Python中,方法的调用机制是从子类到父类,如果在子类中找不到对应方法,便会在父类中查找
多态
- 当子类和父类存在相同的方法时,在代码运行时总是执行子类的方法,称之为多态
- 在继承关系中,如果一个实例的数据类型是某个子类,那他的数据类型也可以看做父类。
class Animal(): # 定义父类 Animal
def __init__(self): # 无参构造法
pass
def run(self): # 定义父类的run()方法
print('Animal is running')
class Dog(Animal): # 定义子类Dog
def __init__(self):
Animal.__init__(self) # 调用父类的无参构造法,写法格式留意带上self参数
def run(self): # 定义子类的run()方法
print('Dog is running')
class Cat(Animal): # 定义子类Cat
def __init__(self):
Animal.__init__(self)
def run(self): # 定义子类的run()方法
print('Cat is running')
doggy = Dog() # 将变量doggy实例化,它属于dog类,肯定也是Animal类
catty = Cat()
doggy.run() # 当子类与父类存在相同的方法时,永远执行子类的方法,若子类没有对应方法,才会在父类中寻找
catty.run()
Dog is running
Cat is running
多态的意义在于:
对于一个变量,我们只需要知道它是哪个父类类型,无需确切知道它从属哪个子类,就能放心调用父类中存在的方法,具体调用的方法作用于哪个子类对象,由运行时该对象的确切类型决定
多重继承
多重继承就是拥有多个父类
class DerivedClassName(Base1,Base2,Base3...):
< statements-1 >
.
.
< statements-N >
需要注意括号内父类的顺序,若父类中有相同的方法名,在子类使用时未指定,Python会从左至右搜索(含子类)
例:
现在有如下四种动物:Dog , Bat , Parrot , Ostrich
按照哺乳类 Mammal , 鸟类 Bird分类
按照会飞 Flyable , 会跑 Runnable 分类
class Animal(): # 定义父类 Animal
pass
class Mammal(Animal):
pass
class Bird(Animal):
pass
class Runnable(Animal):
pass
class Flyable(Animal):
pass
class Dog(Mammal,Runnable): # 定义子类Dog
pass
class bat(Mammal,Flyable):
pass