首页 > 编程语言 >Python面向对象编程

Python面向对象编程

时间:2024-09-20 11:23:17浏览次数:3  
标签:__ name Python self 面向对象编程 print 方法 def

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

相关文章

  • python 比较两个或多个时间,获取最大的时间(最近的时间)
    自定义的公共函数importdate_timedefstr2datetime(date_time,form="%Y-%m-%d%H:%M:%S"):_datetime=datetime.datetime.strptime(date_time,form)ifisinstance(date_time,str)elsedate_timereturn_datetimedefdatetime2str(date_time,form=&q......
  • Python开发深度学习常见安装包 error 解决
    PythonPython是一种广泛使用的高级编程语言,它以其清晰的语法和代码可读性而闻名。Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。由于其简洁性和强大的标准库,Python成为了数据科学、机器学习、网络开发、自动化脚本、科学计算和教育等领域的首选语......
  • Python编程 - 协程
    前言上篇文章主要讲述了python的进程,进程池和进程与线程对比等知识,接下来这篇文章再唠唠python的协程,让我们继续往下看!一、协程的使用python中的协程是一种用于处理并发任务的高效工具,它依赖于asyncio库以及async和await关键字来实现异步编程。协程与传统的多线程或......
  • python, Pycharm开发环境配置!
    1.windows官网下载地址windowspythonDownloadwindowpycharmDownload专业版30天试用,可以下载社区版2.先下载安装python64,32位都可,一般现在都是64位双击安装,勾选Addpython.exetoPATH中如果想自定义安装,点击Customizeinstallation自定义安装,......
  • 掌握Python虚拟环境:隔离项目依赖,提升开发效率的必备指南
    虚拟环境是什么?        虚拟环境是Python中的一个概念,它允许开发者在一个隔离的环境中安装和使用Python包。每个虚拟环境都是一个独立的目录,其中包含特定版本的Python解释器和一系列独立的Python包。我们可以为每个项目创建一个虚拟环境,并为该环境安装所需的特定版......
  • 使用pyenv和venv管理python环境
    1.pyenv与venv的关系pyenv是一个用于管理多个Python版本的工具,主要专注于解决不同项目需要不同Python版本的问题。venv是Python内置的虚拟环境管理工具,主要用于创建隔离的Python环境,帮助避免在不同项目之间发生包依赖冲突。总结:pyenv用于安装Python的多个版本,venv用于隔离......
  • 多线程搜索文件拷贝-Python脚本
    单线程的文件拷贝太折磨人了,所以这里使用多线程的方式去拉满软件效率importosimportshutilimportthreadingimportqueueclassFileItem:"""自定义文件对象类,用于存储文件路径和命名序号"""def__init__(self,path,index):self.path=path......
  • python爬虫连载23
    HTTP协议HTTP协议(HyperTextTransferProtocol超文本传输协议)用于从服务器和客户端传输数据。HTTP请求l HTTP请求永远是客户端发起,服务器端响应。l HTTP请求时无状态的,即这一次的请求和任何其他次请求都没有关系。一次HTTP操作是一次事务。l HTTP请求步骤:1建立客户端和服务......
  • 基于MicroPython的Raspberry Pi Pico控制LED灯闪烁的设计方案
       以下是一个基于MicroPython的RaspberryPiPico控制LED灯闪烁的设计方案:一、硬件准备:1. RaspberryPiPico开发板2. 一个LED灯3. 一个220Ω4. 杜邦线若干。5.3.3V直流电源二、硬件连接:1.将Pico开发板的VSYS连接到3.3V直流电源的正极,开发板的GND引脚连......
  • python+flask计算机毕业设计景区民宿网上预约系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着旅游业的蓬勃发展,景区民宿作为一种融合了当地文化、自然风光与个性化服务的住宿形式,越来越受到游客的青睐。然而,传统民宿预订方式往往......