2021-04-15

本文介绍了Python的面向对象编程,包括过程和函数的区别、类和对象的概念、类的设计、初始化方法、封装、继承、多态等核心概念,并通过实例展示了如何定义和使用类、方法以及如何处理对象的生命周期。此外,还讲解了身份运算符、私有属性和方法、多继承以及方法的重写。最后,通过实际案例展示了类的结构和方法的综合运用。
摘要由CSDN通过智能技术生成

PythonDay10

本节内容

  • 过程和函数
  • 类和对象
  • 类的设计
  • 初始化方法
  • 封装
  • 封装案例
  • 身份运算符
  • 继承
  • 方法的重写
  • 多继承
  • 多态
  • 类的结构
  • 方法综合案例

1.过程和函数

过程是早期的一个编程概念;过程类似于函数,只能执行,但没有返回值;

函数不仅能执行,还可以返回结果;

面向过程

  • 把完成某一需求的所有步骤从头到尾逐步实现
  • 根据开发需求,将某些功能独立的代码封装成一个又一个函数
  • 最后完成的代码,就是顺序地调用不同函数

面向对象 相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法

  • 在完成某一需求前,首先确定职责--要做的事情
  • 根据职责确定不同的对象,在对象内部封装不同的方法
  • 最后完成的代码,就是顺序地让不同的对象调用不同的方法

专门应对复杂项目开发,提供固定的套路;注重对象和职责;需要在面向过程的基础上,在学习一些面向对象的语法;

2.类和对象

是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用;

特征被称为属性,行为被称为方法;

类相当于制造飞机的图纸,是一个模板,负责创建对象的;

对象由类创建出来的一个具体存在,可以直接使用;

由哪一个类创建出来的对象,就拥有在哪一个类中定义的:属性和方法;

类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象;

类只有一个,而对象可以有很多个;不同对象之间属性可能各有不同;

类中定义什么属性和方法,对象中就有什么属性和方法;

3.类的设计

在程序开发中,要设计一个类,通常需要满足三个要素:

  • 类名 这类事物的名字,满足大驼峰命令法(CapWords)
  • 属性 这类事物具有什么样的特征
  • 方法 这类事物具有什么样的行为

属性:对对象的特征描述;

方法:对象具有的行为(动词);

4.dir内置函数

使用内置函数dir传入标识符/数据,可以查看对象内的所有属性及方法;

5.定义简单的类

6.面向对象的程序

需求:小猫爱吃鱼,小猫要喝水;

class Cat:
    def eat(self):
        print("小猫吃鱼")
    def drink(self):
        print("小猫喝水")
#创建对象
tom=Cat()
tom.eat()
tom.drink()

7.初始化方法

当使用类名()创建对象时,会自动执行以下操作:

  • 为对象在内存中分配空间---创建对象
  • 为对象的属性设置初始值---初始化方法(init)

_init_方法是对象的内置方法

在初始化方法内部定义属性

在_init_方法内部使用self.属性名=属性的初始值就可以定义属性

定义属性后,再使用Cat类创建的对象,都会拥有该属性

class Cat:
    def __init__(self):
        print("这是一个初始化方法")
        #self.属性名=属性的初始值
        self.name="Tom"
    def eat(self):
        print("%s爱吃鱼"%self.name)
#使用类名()创建对象的时候,会自动调用初始化方法_init_
tom=Cat()
print(tom.name)

如果希望在创建对象的同时,就设置对象的属性,可以对_init_方法进行改造;

把希望设置的属性值,定义成_init_方法的参数

在方法内部使用 self.属性=形参 接收外部传递的参数

在创建对象时,使用 类名(属性1,属性2....)调用

class Cat:
    def __init__(self,new_name):
        print("这是一个初始化方法")
        #self.属性名=属性的初始值
        #self.name="Tom"
        self.name=new_name
    def eat(self):
        print("%s爱吃鱼"%self.name)
#使用类名()创建对象的时候,会自动调用初始化方法_init_
tom=Cat("Tom")
print(tom.name)
lazy_cat=Cat("大懒猫")
lazy_cat.eat()

_del_如果希望在对象被销毁前,会自动调用_del_方法

生命周期

  • 一个对象从调用类名()创建,生命周期开始
  • 一个对象的_del_方法一旦被调用,生命周期结束
  • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
class Cat():
    def __init__(self,new_name):
        self.name=new_name
        print("%s 来了"%self.name)
    def __del__(self):
        print("%s 我去了"%self.name)
#tom是一个全局变量
tom=Cat("Tom")
print(tom.name)
#del可以删除一个对象
del tom
print("-"*50)

_str_方法必须返回一个字符串,能够打印自定义内容;

class Cat():
    def __init__(self,new_name):
        self.name=new_name
        print("%s 来了"%self.name)
    def __del__(self):
        print("%s 我去了"%self.name)
    def __str__(self):
        #必须返回一个字符串
        return "我是小猫[%s]"%self.name
#tom是一个全局变量
tom=Cat("Tom")
print(tom)

8.封装

封装是面向对象编程的一大特点;

面向对象编程的第一步是将属性和方法封装到一个抽象的类中,外界使用类创建对象,然后让对象调用方法;

对象方法的细节都被封装在类的内部;

同一个类创建的多个对象之间,属性互不干扰的;

class Person:
    def __init__(self,name,weight):
        #self.属性=形参
        self.name=name
        self.weight=weight
    def __str__(self):
        return "我的名字叫%s 体重是%.2f公斤"%(self.name,self.weight)
    def run(self):
        print("%s爱跑步"%self.name)
        self.weight-=0.5
    def eat(self):
        print("%s是吃货"%self.name)
        self.weight+=1
xiaoming=Person("小明",75.0)
xiaoming.run()
xiaoming.eat()
print(xiaoming)

在对象方法内部,是可以直接访问对象的属性的;

# data: 2021-04-18
class HouseItem:
    def __init__(self,name,area):
        self.name=name
        self.area=area
    def __str__(self):
        return "[%s]占地%.2f"%(self.name,self.area)


class House:
    def __init__(self,house_type,area):
        self.house_type=house_type
        self.area=area
        #剩余面积
        self.free_area=area
        #家具名称列表
        self.item_list=[]
    def __str__(self):
        #Python能够自动将一对括号内部的代码拼接在一起
        return ("户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s")\
               %(self.house_type,self.area,
                 self.free_area,self.item_list)
    def add_item(self,item):
        print("要添加%s"%item)
        #判断家具的面积
        if item.area>self.free_area:
            print("%s面积太大,无法添加"%item.name)
            return
        #将家具的名称添加到列表中
        self.item_list.append(item.name)
        #计算剩余面积
        self.free_area-=item.area
                
#创建家具
bed=HouseItem("席梦思",4)
chest=HouseItem("衣柜",2)
table=HouseItem("餐桌",1.5)
print(bed)
print(chest)
print(table)
#创建房子对象
my_home=House("两室一厅",80)
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)

一个对象的属性可以是另一个类创建的对象

需求

枪类

  • 士兵许三多有一把AK47
  • 士兵可以开火
  • 枪能够发射子弹
  • 枪可以装填子弹--增加子弹数量

士兵类

假设每个新兵都没有枪

定义没有初始值的属性

定义属性时,如果不知道设置什么初始值,可以设置为None;

None关键字表示什么都没有

表示一个空对象,没有方法和属性,是一个特殊的常量;

可以将None赋值给任何一个变量;

# data: 2021-05-04
class Gun:
    def __init__(self,model):
        #枪的型号
        self.model=model
        #子弹的数量
        self.bullet_count=0
    def add_bullet(self,count):
        self.bullet_count+=count
    def shoot(self):
        #判断子弹数量
        if self.bullet_count<=0:
            print("[%s]没有子弹了"%self.model)
            return
        #发射子弹,数量减少
        self.bullet_count-=1
        print("[%s]突突突...[%d]"%(self.model,self.bullet_count))

class Soldier:
    def __init__(self,name):
        #定义新兵的姓名
        self.name=name
        #枪-新兵没有枪
        self.gun=None
    def fire(self):
        #判断士兵是否有枪
        if self.gun is None:
            print("[%s]没有枪"%self.name)
            return
        #高喊口号
        print("冲啊...[%s]"%self.name)
        #装填子弹
        self.gun.add_bullet(50)
        #发射子弹
        self.gun.shoot()

#创建枪对象
ak47=Gun("AK47")
#创建许三多
xusanduo=Soldier("许三多")
xusanduo.gun=ak47
xusanduo.fire()
print(xusanduo.gun)

9.身份运算符

身份运算符用于比较两个对象的内存地址是否一致--是否是对同一个对象的引用;

is:is是判断两个标志符是不是引用同一个对象  x is y,类似id(x)==id(y)

is not:is not是判断两个标志符是不是引用不同对象  x is not y,类似id(a)!=id(b)

is与==区别:

is用于判断两个变量引用对象是否为同一个

==用于判断引用变量的值是否相等

a=[1,2,3]
b=[1,2,3]
print(b is a)
print(b==a)

10.私有属性和私有方法

定义方式

在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法;

class Women:
    def __init__(self,name):
        self.name=name
        self.__age=18
    def __secret(self):
        #在对象的方法内部,是可以访问对象的私有属性的
        print("%s年龄是%d"%(self.name,self.__age))

xiaofang=Women("小芳")

#私有属性在外界不能够被直接访问
#print(xiaofang.__age)
print(xiaofang._Women__age)
#私有方法,同样不允许在外界直接访问
#xiaofang.__secret()
xiaofang._Women__secret()

11.继承

继承实现代码的重用,相同的代码不需要重复编写;

继承:子类拥有父类的所有方法和属性;

继承的语法

class 类名(父类名):
       pass
class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")
    def sleep(self):
        print("睡")

class Dog(Animal):
    def bark(self):
        print("汪汪汪")

class XiaoTianQuan(Dog):
    def fly(self):
        print("飞")

wangcai=Dog()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()
xtq=XiaoTianQuan()
xtq.fly()
xtq.bark()
xtq.eat()

子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发;

子类中应该根据职责,封装子类特有的属性和方法;

专业术语

  • Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承
  • Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生

C类从B类继承,B类又从A类继承

那么C类就具有B类和A类的所有属性和方法;

12.方法的重写

重写父类方法有两种情况:覆盖父类的方法;对父类方法进行扩展。

覆盖父类方法:具体实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现;

#覆盖父类的方法
class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")
    def sleep(self):
        print("睡")

class Dog(Animal):
    def bark(self):
        print("汪汪汪")

class XiaoTianQuan(Dog):
    def fly(self):
        print("飞")
    def bark(self):
        print("叫的很厉害")

xtq=XiaoTianQuan()
#如果子类中,重写父类的方法
#在使用子类对象调用方法时,会调用子类中重写的方法
xtq.bark()

对父类方法进行扩展:在子类中重写父类的方法,在需要的位置使用super().父类方法来调用父类方法的执行,代码其它的位置针对子类的需求,编写子类特有的代码实现;

关于super:是一个特殊的类,super()就是使用super类创建出来的对象,最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现。

class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")
    def sleep(self):
        print("睡")

class Dog(Animal):
    def bark(self):
        print("汪汪汪")

class XiaoTianQuan(Dog):
    def fly(self):
        print("飞")
    def bark(self):
        #针对子类特有需求编写代码
        print("神一样叫唤")
        #使用super().调用原本在父类中封装的方法
        super().bark()
        #增加其他子类的代码
        print("-----")
xtq=XiaoTianQuan()
#如果子类中,重写父类的方法
#在使用子类对象调用方法时,会调用子类中重写的方法
xtq.bark()

子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法;

子类对象可以通过父类的公有方法间接访问到私有属性或私有方法;

class A:
    def __init__(self):
        self.num1=100
        self.__num2=200
    def __test(self):
        print("私有方法%d%d"%(self.num1,self.__num2))
    def test(self):
        print("父类的公有方法")
        self.__test()

class B(A):
    def demo(self):
        #在子类的对象方法中,不能访问父类的私有属性
        #print("访问父类私有属性%d"%self.__num2)

        #在子类的对象方法中,不能调用父类的私有方法
        #self.__test()

        #访问父类的公有属性
        print("子类方法%d"%self.num1)

        #调用父类的公有方法
        self.test()

b=B()
b.demo()
print(b.num1)
b.test()

13.多继承

子类可以拥有多个父类,并且具有所有父类的属性和方法;

class 子类名(父类名1,父类名2...):
    pass
class A:
    def test(self):
        print("test方法")
class B:
    def demo(self):
        print("demo方法")
class C(A,B):
    """多继承可以让子类对象,同时具有多个父类的属性和方法"""
    pass

c=C()
c.test()
c.demo()

MRO--方法搜索顺序

针对类提供一个内置属性__mro__可以查看方法搜索顺序

MRO是method resolution order,主要用于在多继承时判断方法,属性的调用路径;

print(C.__mro__)

14.多态

不同的子类对象调用相同的父类方法,产生不同的执行结果;

多态可以增加代码的灵活度;以继承和重写父类方法为前提;是调用方法的技巧,不会影响到类的内部设计;

class Dog(object):
    def __init__(self,name):
        self.name=name
    def game(self):
        print("%s蹦蹦跳跳"%self.name)
class XiaoTianDog(Dog):
    def game(self):
        print("%s飞到天上玩耍"%self.name)
class Person(object):
    def __init__(self,name):
        self.name=name
    def game_with_dog(self,dog):
        print("%s和%s快乐玩耍"%(self.name,dog.name))
        dog.game()
#创建狗对象
wangcai=Dog("旺财")
feitianwangcai=XiaoTianDog("飞天旺财")
#创建人对象
xiaoming=Person("小明")
#调用和狗玩的方法
xiaoming.game_with_dog(wangcai)
xiaoming.game_with_dog(feitianwangcai)

15.类的结构

  • 使用面向对象开发,第一步是设计类;
  • 使用类名()创建对象,创建对象的动作有两步:在内存中为对象分配空间;调用初始化方法__init__为对象初始化。
  • 对象创建后,内存中就有了一个对象的实实在在的存在---案例;

创建出来的对象叫做类的实例;创建对象的动作叫做实例化;对象的属性叫做实例属性;对象调用的方法叫做实例方法;

类是一个特殊的对象,Python中一切皆对象;

class Tool(object):
    #使用赋值语句,定义类属性,记录创建工具对象的总数
    count=0
    def __init__(self,name):
        self.name=name
        Tool.count+=1

#创建工具对象
tool1=Tool("斧头")
tool2=Tool("榔头")
tool3=Tool("水桶")
print(Tool.count)

访问类属性有两种方式:类名.类属性对象.类属性(不推荐)

如果使用对象.类属性=值赋值语句,只会给对象添加一个属性,而不会影响到类属性的值;

类方法就是针对类对象定义的方法;类属性就是针对类对象定义的属性;

类方法的定义

@classmethod
def 类方法名(cls)
    pass
class Tool(object):
    count=0
    @classmethod
    def show_tool_count(cls):
        print("工具数量%d"%cls.count)
    def __init__(self,name):
        self.name=name
        Tool.count+=1

tool1=Tool("斧头")
tool2=Tool("榔头")
Tool.show_tool_count()

静态方法

@staticmethod
def 静态方法():
    pass
class Dog(object):
    @staticmethod
    def run():
        #不访问实例属性/方法
        print("小狗要跑")

#调用静态方法--不需要创建对象
Dog.run()

16.方法综合案例

class Game(object):
    top_score=0
    def __init__(self,player_name):
        self.player_name=player_name
    @staticmethod
    def show_help():
        print("帮助信息:hello!")
    @classmethod
    def show_top_score(cls):
        print("历史记录最高:%d"%cls.top_score)
    def start_game(self):
        print("%s开始游戏"%self.player_name)
#1.查看游戏帮助信息
Game.show_help()
#2.查看历史最高分
Game.show_top_score()
#3.创建游戏对象
game=Game("小明")
game.start_game()

小结:实例方法--方法内部需要访问实例属性;实例方法内部可以使用类名.访问类属性

类方法--方法内部只需要访问类属性;

静态方法--方法内部,不需要访问实例属性和类属性;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值