Python - 面向对象:类、对象、属性、方法
面向对象概念
面向对象编程
(Object-oriented Programming,简称 OOP),是一种封装代码
的方法面向对象
:将模拟真实世界里的事物(对象 )和描述其特征(属性)的数据和函数代码块(方法)封装到一起(类)
类
:可以理解是一个模板
,通过它可以创建出无数个具体实例对象
:类并不能直接使用,通过类创建出的实例
(对象)才能使用属性
:类中的所有变量
称为属性方法
:类中的所有函数
通常称为方法
类
- 创建类
class
关键字定义类- 类
属性
: 包含在类中的变量
- 类
方法
:包含类中的函数
- 类说明 :在类头之后用字符串可以添加类定义说明
class 类名:
'''
类说明
'''
类属性
类方法
# 创建产品类
class Computer():
def __int__(self):
self.cpu = None
self.radiator = None # 散热
def set_cpu(self, cpu):
self.cpu = cpu
__int__ 和 set_cpu 都是类方法,cpu、radiator为属性
对象
- 创建对象
- 要想使用一个类,必须创建该类的
对象
类的实例化
:创建类对象的过程- 语法格式:
对象名 = 类名(参数,...)
- 类对象使用
- 使用类变量 :
类对象名.变量名
- 使用类方法 :
对象名.方法名(参数)
- 类对象添加删除新的属性
- 添加属性 :
类对象名.新变量名 = 新变量值
- 删除属性 :
del 类对象名.变量名
- 类对象添加新的方法
def 方法名(self , [ parm, ...]):
pass
from types import MethodType # 导入模块
类对象名.方法名 = MethodType(方法名, 对象名) # 将方法和对象绑定
属性
类属性分类
- 在类体中,根据变量定义的
位置不同
,以及定义的方式不同
,类属性又可细分为以下3 种类型
:
- 类体中、所有函数之外:此范围定义的变量,称为
类属性
或类变量
- 类体中,所有函数内部:以
self.变量名
的方式定义的变量,称为实例属性
或实例变量
- 类体中,所有函数内部:以
变量名=变量值
的方式定义的变量,称为局部变量
类属性(类变量)
- 类变量的特点:
- 所有类的实例化对象都
同时共享类变量
,也就是说,类变量在所有实例化对象中是作为公用资源存在的 - 类变量为所有实例化对象共有,可以
通过类名修改类变量的值
,并且修改后,会影响所有的实例化的对象
类对象无法修改类变量的值
,通过类对象对类变量赋值,只会修改自己对象中的变量值
- 示例:
class person :
name = "QWQ" # 类变量 :name
age = 18 # 类变量 :age
def info(self) :
print("%s age is %d"%( self.name, self.age))
jone = person()
jone.info() # 打印 :QWQ age is 18
jack = person()
jack.info() # 打印 :QWQ age is 18
person.name = "WXQ" # 通过类名改变类变量值, 改变了模子里面的值
person.age = 20
jone.info() # 打印 :WXQ age is 20
jack.info() # 打印 :WXQ age is 20
jone.name = "LNL" # 通过类对象改变类变量值
jone.age = 19
jone.info() # 打印 :LNL age is 19 , 对象中类变量发生改变
jack.info() # 打印 :WXQ age is 20 , 类中类变量值不会发生变化
实例变量
- 实例变量指的是在任意类方法内部,以
self.变量名
的方式定义的变量,其特点:
- 只作用于
调用方法的对象
- 实例变量
只能通过对象名访问
,无法通过类名访问 - 通过类对象是
无法修改类变量的值
,更不会影响类的其它实例化对象
- 示例 :
class person :
def __init__(self) -> None:
self.name = "QWQ" # 实例变量
self.age = 18 # 实例变量
def info(self) :
self.tall = 178 # 实例变量
jone = person()
print("%s age is %d"%(jone.name, jone.age)) #打印 :QWQ age is 18,通过对象访问实例变量
# print(person.name) 无法通过类名访问实例变量
# print(jone.tall) 在info方法没用调用前,还不存在tall变量,无法调用
jone.info() # 调用info方法,创建了tall实例变量
print(jone.tall) # 打印 :178
jone.name = "WXQ" # 通过对象修改实例变量
jone.age = 20
jone.tall = 172
print("%s age is %d, tall is %d"%(jone.name, jone.age,jone.tall))
jack = person()
jack.info()
print("%s age is %d, tall is %d"%(jack.name, jack.age,jack.tall)) # 类中实例变量值没有改变
结果:
QWQ age is 18 178 WXQ age is 20, tall is 172 QWQ age is 18, tall is 178
局部变量
- 局部变量直接以
变量名=值
的方式进行定义 - 定义局部变量是为了所在类方法功能的实现,
局部变量只能用于所在函数中
,函数执行完成后,局部变量也会被销毁
class Calculate :
def count(self,money):
sale = 0.8*money # sale 为局部变量
print("优惠后的价格为:",sale)
clang = Calculate()
clang.count(100)
方法
- 方法可分为
类方法
、实例方法
和静态方法
@classmethod
修饰的方法为类方法@staticmethod
修饰的方法为静态方法不用任何修饰
的方法为实例方法
实例方法
- 类中定义的方法默认都是实例方法,不仅如此,类的构造方法等特殊的魔术方法,理论上也属于实例方法
- 实例方法:最少也要包含一个
self
参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定) - 实例方法通常会用
类对象直接调用
class class_name():
def __init__(self) :
pass
def func(self): # 实例方法
pass
object_name = class_name() # 定义对象
object_name.func() # 调用实例方法
class_name.func(object_name) # 类名调用实例方法,需手动给 self 参数传值
类方法
- 类方法和实例方法相似,也要包含一个参数,通常将其命名为
cls
- Python 会自动将
类本身
绑定给cls
参数 - 类方法需要使用
@classmethod
修饰符进行修饰
class class_name():
@classmethod
def func(cls): # 类方法
pass
class_name.func() # 使用类名直接调用类方法
object_name = class_name() # 使用类对象调用类方法
object_name.func()
静态方法
- 静态方法,本质上就是函数,区别在于,
静态方法定义在类这个空间
(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中 - 静态方法
没有类或对象的绑定
,因此静态方法中无法调用任何类属性和类方法 - 使用
@staticmethod
修饰
class person:
@staticmethod
def info(name,add): # 静态方法
print(name,add)
peron.info("QWQ",18) # 使用类名直接调用静态方法
jack = person() # 使用类对象调用静态方法
jack.info("jack",24)
特殊方法
构造方法__init__()
- 构造方法 : 用于创建对象时
初始化赋值
- 第一个参数必须存在且必须为
self
,其它参数个数无限
class class_name :
def __init__(slef, parm1, parm2,...):
# self :新建的对象
slef.parm1 = parm1
slef.parm2 = parm2
创建类实例的静态方法__new__()
- 概念理解
__new__()
创建类的实例化对象时调用,相对于给实例化的对象申请一片内存,如果创建的类中没有写__new__()
,实际上执行时会调用object类中的__new__()
申请返回内存地址,也就是说我们使用的该方法实际是一种重写父类方法
- 特性
- 触发机制 :
__new__()
方法是在类准备将自身实例化时调用执行 __new__()
方法始终都是类的静态方法
,即使没有被加上静态方法装饰器- 需要用
return
返回该类的一个实例对象地址
- 作用
- 用于继承一些
不可变的class
时(比如int, str, tuple), 提供一个自定义这些类的实例化过程的途径
"""
示例1 :
"""
class int_define():
def __init__(self, value) :
self.value = abs(value)
class PositiveInterger_define(int_define):
def __init__(self, value):
super().__init__(value) # 通过super, 调用父类的构造方法
def __repr__(self) -> str:
return str(self.value)
i = PositiveInterger_define(-3)
print(i) # 打印结果为3
"""
示例2:
"""
class PositiveInterger(int) :
def __init__(self, value) :
super().__init__(value) # 同样试图用super()调用父类int的构造方法
def __repr__(self) -> str:
return str(self.value)
i = PositiveInterger(-3) # 程序报错,无法执行
"""
示例3:
"""
class PositiveInterger1(int) :
def __new__(cls, value) : # 通过__new__()才能达到想要的结果
return super().__new__(cls, abs(value))
i = PositiveInterger1(-3)
print(i)
返回实例化对象信息__repr__()
和__str__()
__repr__()
: 类的实例化对象用来做自我介绍
的方法,默认情况下,它会返回当前对象的类名+object at+内存地址
,而如果对该方法进行重写,可以为其制作自定义的自我描述信息__str__()
: 在__str__
方法中添加return+ 打印对象看到内容
,实现打印对象名时自动触发去调用出__str__
里面的内容- 区别 :对于自己编写的类来说,两者基本没有区别
# 示例1 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
QWQ = person("QWQ", 18)
print(QWQ) # 打印 :<__main__.person object at 0x000001F3E8864250>
# 示例2 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self): # 对父类object进行重写
return "{} age is {}".format(self.name, self.age)
QWQ = person("QWQ", 18)
print(QWQ) # 打印 : QWQ age is 18
# 示例3 :
class person():
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self): # 对父类object进行重写
return "{} age is {}".format(self.name, self.age)
QWQ = person("QWQ", 18)
print(QWQ) # 打印 : QWQ age is 18
销毁对象__del__()
垃圾回收
(简称GC)实现函数:如果之前创建的类实例化对象后续不再使用,通过__del__()
函数在适当位置手动将其销毁,释放其占用的内存空间- 语法格式
class class_name:
def __init__(self):
pass
def __del__(self):
pass
c = class_name() # 创建对象
del c # 销毁对象
- 特点
- python的主动回收机制也是通过该方法实现的,因此自己添加的回收方法是重写父类的
__del__()
方法,因此必须显式调用父类的__del__()
方法,这样才能保证在回收子类对象时,其占用的资源能被彻底释放 - Python 采用
自动引用计数
(简称 ARC)的方式实现垃圾回收机制。其核心思想是:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。当对象的的计数器值为 0,则表明没有变量引用对象,即证明程序不再需要它,此时 才会自动调用__del__()
方法将其回收。
列出对象的所有属性__dir__()
- 和内置
dir()
函数一样,__dir__()
方法用于查看对象拥有的所有的属性名和方法名,返回一个包含有所有属性名和方法名的有序列表 dir()
函数的内部实现,其实是在调用参数对象__dir__()
方法的基础上,对该方法返回的属性名和方法名做了排序- 使用
__dir__()
方法和dir()
函数输出的数据是相同,仅仅顺序不同 - 语法格式 :
对象名.__dir__()
查看对象内部所有属性名和属性值组成的字典__dict__
__dict__
属性 : 用于查看类中包含哪些属性- 特点
- 用类名直接调用
__dict__
,会输出该由类中所有类属性组成的字典 - 用类的实例对象调用
__dict__
,会输出由类中所有实例属性组成的字典 - 具有继承关系的父类和子类,通过类名查看类属性,仅查看自己包含的属性,
父类、子类互不影响
- 借助由类实例对象调用
__dict__
属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改
- 语法格式 :
- 类名调用 :
类名.__dict__
- 实例对象调用 :
对象名.__dict__
类属性使用高级方法
- 通过
类对象.属性
的方式访问类中定义的属性的方法,破坏了类的封装原则。正常情况下,类包含的属性应该是隐藏的,只允许通过类提供的方法来间接实现对类属性的访问和操作,因此python提供了许多类属性操作的高级方法 - 破坏封装性的用法
class person :
def __init__(self,name):
self.name = name
# 直接用 对象名.属性 进行操作,破坏了类的封装性
QWQ = person("QWQ")
print(QWQ.name) # 调用属性
QWQ.name = 'LNL' # 修改属性
- 正确做法是类提供的方法来间接实现对类属性的访问和操作
class person :
def __init__(self,name):
self.name = name
def getname(self) : # getter 方法
return self.name
def setname(self, name) : # setter 方法
self.name = name
def delname(self) : # del 方法
self.name = "xxx"
QWQ = person("QWQ")
print(QWQ.getname()) # 调用属性
QWQ.setname('LNL') # 修改属性
QWQ.delname()
property()函数
- 在不破坏类封装原则的基础上,又希望通过
类对象.方法(参数)
的方式来操作属性,python提供了property()
函数 - 语法 :
属性名 = property(fget=None, fset=None, fdel=None, doc=None)
- fget 参数用于指定
获取
该属性值的类方法 - fset 参数用于指定
设置
该属性值的方法 - fdel 参数用于指定
删除
该属性值的方法 - doc 是一个文档字符串,用于
说明
此函数的作用
- 此时该属性必须设置为
私有属性
,即使用__属性名
(前面有 2 个下划线)
class person:
def __init__(self,name): #构造函数
self.__name = name
def setname(self,name) : #设置 name 属性值的函数
self.__name = name
def getname(self): #访问nema属性值的函数
return self.__name
def delname(self) : #删除name属性值的函数
self.__name = "xxx"
name = property(getname, setname, delname, '姓名操作') #为name属性配置property()函数
print(person.name.__doc__) # 调取说明文档的 2 种方式
help(person.name)
QWQ = person("QWQ")
print(QWQ.name) # 调用 getname() 方法
QWQ.name = "LNL" # 调用 setname() 方法
del QWQ.name # 调用 delname() 方法
装饰器
- 既要保护类的封装特性,又要让开发者可以使用
对象.属性
的方式操作操作类属性,除了使用 property() 函数,Python 还提供了@property
装饰器 @property
装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对()
小括号- @property 的语法格式如下:
@property
def 变量名(self)
代码块
- 修改属性的值需要用到
setter
装饰器 :
@变量名.setter
def 变量名(self, value):
代码块
当构造函数__init__()中,属性没有加下划线,此时会先执行setter装饰器的设置函数,利用该特性可以在setter装饰器函数中添加判断条件
- 删除指定属性的值用
deleter
装饰器 :
@变量名.deleter
def 变量名(self):
代码块
- 使用实例 :
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
@area.setter
def area(self, value):
self.__area = value
@area.deleter
def area(self):
self.__area = 0
rect = Rect(30)
print("矩形的面积是:",rect.area) #直接通过方法名来访问 area 方法
rect.area = 90
print("修改后的面积:",rect.area)
del rect.area
print("删除后的area值为:",rect.area)
描述符
- 描述符就是一个类,只不过它定义了另一个类中属性的访问方式, 换句话说,一个类可以将属性管理全权委托给描述符类
- 类里实现了
__get__()
、__set__()
、__delete__()
的方法
__get__
: 用于访问属性,格式:__set__(self, obj, type )
它返回属性的值,若属性不存在、不合法等都可以抛出对应的异常__set__
:将在属性分配操作中调用,格式 :__get__(self, obj, value)
不会返回任何内容__delete__
:控制删除操作,格式 :__delete__(self, obj)
不会返回内容
- 使用案例 :
class Score:
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Score must be integer')
if not 0 <= value <= 100:
raise ValueError('Valid value must be in [0, 100]')
self._score = value
def __get__(self, instance, owner):
return self._score
def __delete__(self):
del self._score
class Student:
math = Score()
chinese = Score()
english = Score()
def __init__(self, name, math, chinese, english):
self.name = name
self.math = math
self.chinese = chinese
self.english = english
def __repr__(self):
return "<Student: {}, math:{}, chinese: {}, english:{}>".format(
self.name, self.math, self.chinese, self.english
)
QWQ = Student("QWQ", 10, 12, 13)
print(QWQ)
面向对象练习
矩形计算器
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def get_area(self):
return self.width * self.height
def get_perimeter(self):
return 2 * (self.width + self.height)
# 创建矩形实例
rect = Rectangle(10, 20)
# 打印面积和周长
print("面积:", rect.get_area())
print("周长:", rect.get_perimeter())
面向对象常见概念理解
面向对象三大特性
- 封装:根据
职责
将属性
和方法
封装
到一个抽象的类
中 - 继承:
实现代码的重用
,相同的代码不需要重复的编写 - 多态:
不同的对象
调用相同的方法,产生不同的执行结果,增加代码的灵活度
封装
公有成员变量和私有成员变量
Python中用成员变量的名字来区分是公有成员变量或者是私有成员变量;Python中,以两个下划线
__(两个下划线)
开头的变量都是私有成员变量,而其余的变量都属于公有成员变量;其中,私有的成员变量只能在类的内部访问,而共有的公有的成员变量可以在类的外部进行访问。
2.2公有方法和私有方法
类的方法是对类行为的封装;类的方法也分为公有方法和私有方法;类的私有方法只能通过对象名(在类内部也就是
self
)在类的内部进行访问。而公有方法可以在类的外部通过对象名进行访问。同样,公有的成员方法和私有的成员方法也是通过名字来区分的,双下划线__(两个下划线)
开头的方法是私有成员方法。
- 私有方法:只能在类的内部进行访问,对象无法访问。
- 私有属性: 提高代码安全性,不允许别人随意修改
class Test(object):
#私有方法
def __test2(self):
print("私有方法,__test2")
#普通方法
def test(self):
print("普通方法test")
#普通方法
def _test1(self):
print("普通方法_test1方法")
#在类内部调用私有方法
#t.__test2()
self.__test2()
t = Test()
t.test()
t._test1()
#t.__test2() #调用时会报错
继承
单继承
单继承概念
子类
拥有
父类的所有
方法和
属性
单继承语法
class 子类(父类):
pass
class Dog(Animal): # 狗继承了动物类的所有方法和属性
pass
单继承示例
子类 继承自
父类
,可以直接享受父类中已经封装好的方法
,不需要再次开发 子类中应该根据职责
,封装子类特有
的属性
和方法
# 不使用继承
class Animal(object):
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")
class Dog():
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")
def bark(self):
print("汪汪叫")
fantong = Dog()
fantong.eat()
fantong.drink()
fantong.run()
fantong.sleep()
fantong.bark()
# 使用继承
class Animal(object):
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")
# 子类拥有父类的所有属性和方法
class Dog(Animal):
def bark(self):
print("汪汪叫")
fantong = Dog()
fantong.eat()
fantong.drink()
fantong.run()
fantong.sleep()
fantong.bark()
多继承
多继承概念
子类可以拥有
多个父类
,并且具有所有父类
的属性
和方法
例如:孩子
会继承自己父亲
和母亲
的特性
多继承语法
class 子类名(父类名1,父类名2..)
pass
多继承示例
class Father:
def swim(self):
print("游泳")
def cook(self):
print("做饭")
def fitness(self):
print("健身")
class Mother:
def shopping(self):
print("购物")
def storytelling(self):
print("讲故事")
class child(Father, Mother):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
child = child()
child.swim()
child.storytelling()
child.cry()
多继承的使用注意事项
如果
不同的父类
中存在同名的方法
,子类对象
在调用方法时,会调用 哪一个父类中的方法呢? 开发时,应该尽量避免这种容易产生混淆的情况!
- 如果父类之间
存在
同名的属性或者方法,应该尽量避免
使用多继承- 改变参数的前后顺序就调用不同的对象方法,
谁在前调用谁的方法
class Father:
def quarrel(self):
print("爸爸吵架")
class Mother:
def quarrel(self):
print("妈妈吵架")
class boy(Father, Mother):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
class girl(Mother, Father):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
boy = boy()
boy.quarrel()
girl = girl()
girl.quarrel()
# 爸爸吵架
# 妈妈吵架
Python中的 MRO -- 方法搜索顺序
Python 中针对
类
提供了一个内置属性__mro__
可以查看方法搜索顺序
,MRO是method resolution order
主要用于在多继承
时判断方法、属性
的调用路径
class Father:
def quarrel(self):
print("爸爸吵架")
class Mother:
def quarrel(self):
print("妈妈吵架")
# 继承了三个类,Father、Mother、还有默认继承的 object
class boy(Father, Mother):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
class girl(Mother, Father):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
# 通过类对象调用,不是实例对象!
print(boy.__mro__)
(<class '__main__.boy'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>)
print(girl.__mro__)
(<class '__main__.girl'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>)
继承的传递性
C类从B类继承,B类又从A类继承。那么C类就具有B类和 A 类的
所有属性和方法
子类
拥有父类
以及父类的父类
中封装的所有
属性
和方法
class Grandpa:
def chess(self):
print("国际象棋")
class Father(Grandpa):
def swim(self):
print("游泳")
def quarrel(self):
print("爸爸吵架")
class Mother:
def quarrel(self):
print("妈妈吵架")
# 继承了三个类,Father、Mother、还有默认继承的 object
class boy(Father, Mother):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
print(boy.__mro__)
(<class '__main__.boy'>, <class '__main__.Father'>, <class '__main__.grandpa'>, <class '__main__.Mother'>, <class 'object'>)
boy = boy()
boy.chess()
Mother
类没有继承Grandma
类,所以boy
类继承Mother
类没有Grandma
的属性和方法
class Grandpa:
def chess(self):
print("国际象棋")
class Grandma:
def embroider(self):
print("刺绣")
class Father(Grandpa):
def swim(self):
print("游泳")
def quarrel(self):
print("爸爸吵架")
class Mother:
def quarrel(self):
print("妈妈吵架")
# 继承了三个类,Father、Mother、还有默认继承的 object
class boy(Father, Mother):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
def cry(self):
print("哭泣")
print(boy.__mro__)
boy = boy()
boy.chess()
boy.embroider()
方法的重写
- 子类 拥有
父类
的所有方法
和属性
- 子类继承自
父类
,可以直接享受
父类中已经封装好的方法,不需要再次开发 应用场景
- 当
父类
的方法实现不能满足
子类需求时,可以对方法进行重写(override)
重写父类方法有两种情况
覆盖
父类的方法- 对父类方法进行
扩展
覆盖父类的方法
如果在开发中,父类的方法实现和子类的方法实现
完全不同
;就可以使用覆盖
的方式,在子类中重新编写
父类的方法实现! 具体的实现方式:就相当于在子类中
定义了一个和父类同名的方法并且实现重写之后
在运行时,只会调用子类中重写的方法
,而不再会调用父类封装的方法
class Grandpa:
def chess(self):
print("中国象棋")
def erhu(self):
print("二胡")
class Father(Grandpa):
def swim(self):
print("游泳")
# 对父类Grandpa的chess方法进行了重写
def chess(self):
print("国际象棋")
father = Father()
# 如果子类中,重写了父类的方法;在使用子类对象调用方法时,会调用子类中重写的方法
father.chess() # 国际象棋
对父类方法进行扩展
如果在开发中,子类的方法实现中
包含
父类的方法实现,父类原本封装的方法实现是
子类方法的一部分,就可以使用扩展
的方式
- 在子类中
重写
父类的方法- 在需要的位置使用
super().父类方法
来调用父类方法的执行,使用super
调用父类的方法:可以直接调用父类方法,不需要通过父类名.父类方法名
的方式调用- 代码其他的位置针对子类的需求,编写
子类特有的代码实现
class Grandpa:
def chess(self):
print("中国象棋")
def erhu(self):
print("二胡")
class Father(Grandpa):
def swim(self):
print("游泳")
# 对父类Grandpa的chess方法进行了重写
def chess(self):
# 使用super().调用原本在父类中封装的方法
super().chess()
# 增加其他子类的代码
print("国际象棋")
father = Father()
father.chess()
多态
概念
多态 不同的 子类对象
调用相同的 父类方法
,产生不同的执行结果
- 多态 可以
增加代码的灵活度
- 以
继承
和重写父类方法
为前提 - 是调用方法的技巧,
不会影响
到类的内部设计
多态案例的演练
需求:
- 在
Dog
类中封装方法game
- 普通狗只是简单的玩耍
- 定义
XiaoTianDog
继承自Dog,并且重写game
方法
- 哮天犬需要在天上玩耍
- 定义
Person
类,并且封装一个和狗玩
的方法
- 在方法内部,直接让
狗对象
调用game
方法
class Dog:
def __init__(self, name):
self.name = name
def game(self):
print("%s 玩皮球" % self.name)
class XiaoTianQuan(Dog):
def game(self):
print("%s 哮天犬飞到天上玩耍" % self.name)
class Person:
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("%s和%s在玩游戏" % (self.name, dog.name))
dog.game()
# 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
doudou = Dog("doudou")
xiaoming = Person("xiaoming")
xiaoming.game_with_dog(doudou)
标签:__,name,Python,self,面向对象编程,print,方法,def
From: https://blog.51cto.com/zane/12063288