【Python学习】面向对象

1.初识对象

1.1 生活中数据的组织

比如,我们要统计学生的信息
在这里插入图片描述

1. 2 程序中数据的组织

student_1 = {
    "学号" : "111",
    "姓名" : "张三",
    "性别" : "男",
    "年龄" : "19"
}

student_2 = {
    "学号" : "222",
    "姓名" : "李四",
    "性别" : "男",
    "年龄" : "18"
}
#......

# 每次都要重复创建字典

思考:
没次的操作都是重复的

如果程序中也和生活中一样
• 可以设计表格
• 可以将设计的表格打印出来
• 可以将打印好的表格供人填写内容
那么数据的组织就非常方便了。

1.3 使用对象组织数据

在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的。

  1. 在程序中设计表格,我们称之为:设计类( class )
class Student:
#这些定义的变量成为成员变量
    #记录年龄
    id = None
    #记录性别
    name = None
    #记录性别
    sex = None
    #记录年龄
    age = None
  1. 在程序中打印生产表格,我们称之为:创建对象
#使用上述创建的类来创建对象

student_1 = Student()

student_2 = Student()

#数据怎么填入呢?

  1. 在程序中填写表格,我们称之为:对象属性赋值
# 对student_1 赋值
student_1.id = "111"
student_1.name = "张三"
student_1.sex = "男"
student_1.age = 19

# 对student_2 赋值
student_2.id = "222"
student_2.name = "李四"
student_2.sex = "男"
student_2.age = 18

1.4进行对比

在程序中:

设计表格,称之为:设计类(class)
打印表格,称之为:创建对象
填写表格,称之为:对象属性赋值

2. 成员方法

2.1 类的定义和使用

在上一节中,我们简单了解到可以使用类去封装属性,并基于类创建出一个个的对象来使用。
现在我们来看看类的使用语法:
在这里插入图片描述

2.2 成员变量和成员方法

2.2.1 成员变量

class Student:
    #成员变量 年龄
    id = None
    #成员变量 性别
    name = None
    #成员变量 别
    sex = None
    #成员变量 年龄
    age = None

    #成员方法  self必填
    def Print(self):
        print(f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}")

可以看出,类中:
不仅可以定义属性用来记录数据也可以定义函数,用来记录行为

其中:
类中定义的属性(变量),我们称之为:成员变量
类中定义的行为(函数),我们称之为:成员方法

2.2.2 成员方法的定义语法

在类中定义成员方法和定义函数基本一致,但仍有细微区别:

#只是多加一个self, 其余参数和往常函数一样
def Fun(self, 形参1....,形参N):
    #方法体


可以看到,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的。它用来表示类对象自身的意思。当我们使用类对象调用方法的是,self会自动被python传入在方法内部,想要访问类的成员变量,必须使用self

2.2.3 self 的作用

注意:

  • self关键字,尽管在参数列表中,但是传参的时候可以忽略它。
  • 表示类对象本身的意思
  • 只有通过self,成员方法才能访问类的成员变量
  • self出现在形参列表中,但是不占用参数位置,无需理会
class Student:
    #成员变量 年龄
    id = None
    #成员变量 姓名
    name = None
    #成员变量 性别
    sex = None
    #成员变量 年龄
    age = None

    #成员方法
    def Print(self):
        print(f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}")


#创建一个对象
student_1 = Student()

# 对student_1 赋值
student_1.id = "111"
student_1.name = "张三"
student_1.sex = "男"
student_1.age = 19

#不需要传参 self
student_1.Print()

3. 类和对象

3.1 面向过程

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

拿做饭举例:
在这里插入图片描述
在这里插入图片描述

3.2 面向对象

Python是面向对象的,关注的是对象将一件事情拆分成不同的对象,靠对象之间的交互完成。
在这里插入图片描述
上述过程一共有四个对象:人,菜, 锅,火
整个主要过程是:人,菜, 锅,火 四个对象交互完成的,人不需要关注机器人是怎么洗菜,开火的
在这里插入图片描述

4.构造方法

4.1 属性成员变量的赋值

#创建一个对象
student_1 = Student()

# 对student_1 赋值
student_1.id = "111"
student_1.name = "张三"
student_1.sex = "男"
student_1.age = 19

上面代码中,为对象的属性赋值需要依次进行,略显繁琐。
有没有更加高效的方式,能够一行代码就完成呢?

答:当然可以

  • Python类可以使用:init()方法,称之为构造方法。
  • init 两旁是 两个下划线 " _ "
  • 构造方法也是成员方法,不要忘记在参数列表中提供:self

可以实现:

  1. 在创建类对象(构造类)的时候,会自动执行
  2. 在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用
class Student:

# 成员变量可以省略不写
    #成员变量 年龄
    id = None
    #成员变量 姓名
    name = None
    #成员变量 性别
    sex = None
    #成员变量 年龄
    age = None

    # 构造方法
    def __init__(self,id , name, sex, age):
        self.id = id
        self.name = name
        self.sex = sex
        self.age = age

    #成员方法
    def Print(self):
        print(f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}")


#创建对象,同时赋值
student_1 = Student("111", "张三", "男", 19)

student_2 = Student("222", "李四", "男", 18)
  • 在构造方法内定义成员变量,需要使用self关键字
  # 构造方法
    def __init__(self,id , name, sex, age):
        self.id = id  #成员变量 年龄
        self.name = name  #成员变量 姓名
        self.sex = sex   #成员变量 性别
        self.age = age   #成员变量 年龄

这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。

5. 其他内置方法

上文学习的__init__ 构造方法,是Python类内置的方法之一。
这些内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法
在这里插入图片描述

class Student:

    # 构造方法
    def __init__(self,id , name, sex, age):
        self.id = id  #成员变量 年龄
        self.name = name  #成员变量 姓名
        self.sex = sex   #成员变量 性别
        self.age = age   #成员变量 年龄

   # 返回f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}字符串
    def __str__(self):
        return f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}"

   # 年龄大于、小于比较
    def __lt__(self,other):
        return self.age < other.age

   # 年龄大于等于、小于等于比较
    def __le__(self,other):
        return self.age <= other.age

   # 年龄等于比较
    def __eq__(self,other):
        return self.age == other.age


#创建对象,同时赋值
student_1 = Student("111", "张三", "男", 19)

student_2 = Student("222", "李四", "男", 18)

# 自动调用__str__(self)
#不实现__str__ 打印的是地址
print(student_1)
print(student_2)

# 自动调用__lt__(self,other)
#不实现__lt__ 比较的是地址
print(student_1 < student_2)

# 自动调用__le__(self,other)
#不实现__le__ 比较的是地址
print(student_1 >= student_2)

# 自动调用__eq__(self,other)
#不实现__eq__ 比较的是地址
print(student_1 == student_2)

6. 封装

6.1 面向对象的三大特性

面向对象编程,是许多编程语言都支持的一种编程思想。

简单理解是:基于模板(类)去创建实体(对象),使用对象完成功能开发。

面向对象包含3大主要特性:

  1. 封装
  2. 继承
  3. 多态

6.2 封装

封装表示的是,将现实世界事物的:
属性
行为

封装到类中,描述为:
成员变量
成员方法

从而完成程序对现实世界事物的描述

在这里插入图片描述

6.3 私有成员

  • 什么是私有成员?
  • 答:现实事物有部分属性和行为是不公开对使用者开放的。同样在类中描述属性和方法的时候也需要达到这个要求,就需要定义私有成员了。私有成员只能在成员方法内使用

类中提供了私有成员的形式来支持:
1.私有成员变量
2.私有成员方法

定义私有成员的方式非常简单,只需要:
1.私有成员变量:变量名以__开头(2个下划线)
2.私有成员方法:方法名以__开头(2个下划线)
3.即可完成私有成员的设置

class Student:
     #私有成员变量
    __id = None
    __name = None
    __sex = None
    __age = None

   # 构造方法
   def __init__(self, id, name, sex, age):
       self.id = id  # 成员变量 年龄
       self.name = name  # 成员变量 姓名
       self.sex = sex  # 成员变量 性别
       self.age = age  # 成员变量 年龄
  
  # 私有成员方法
   def __Print(self):
        print(f"学号{self.id}, 姓名{self.name}, 性别{self.sex}, 年龄{self.age}")

6.4 使用私有成员

错误用法:

class Student:
    # 私有成员变量
    __id = None
    __name = None
    __sex = None
    __age = None

    # 这样的构造方法是错误的
    # 私有变量无法赋值,也无法获取值,会报错


    def __init__(self, id, name, sex, age):
        self.__id = id  # 成员变量 年龄
        self.__name = name  # 成员变量 姓名
        self.__sex = sex  # 成员变量 性别
        self.__age = age  # 成员变量 年龄


    # 私有成员方法
    def __Print(self):
        print(f"学号{self.__id}, 姓名{self.__name}, 性别{self.__sex}, 年龄{self.__age}")


# 创建对象,同时赋值
# 初始化时可以给私有变量赋值
student = Student("111", "张三", "男", 19)  #不报错

student.__age = 20 #不报错,但是指该令无效,__age的值还是19

#私有变量只能在类中使用
print(student.__age) #报错

# 私有方法无法直接被类对象使用
student.__Print()  # 会报错

正确用法:

class Student:
    # 私有成员变量
    __id = None
    __name = None
    __sex = None
    __age = None

    # 这样的构造方法是错误的
    # 私有变量无法赋值,也无法获取值,会报错


    def __init__(self, id, name, sex, age):
        self.__id = id  # 成员变量 年龄
        self.__name = name  # 成员变量 姓名
        self.__sex = sex  # 成员变量 性别
        self.__age = age  # 成员变量 年龄


    # 私有成员方法
    def __Print(self):
        print(f"学号{self.__id}, 姓名{self.__name}, 性别{self.__sex}, 年龄{self.__age}")

    def mod_age(self,n):
        self.__age = n
        print(self.__age)


# 创建对象,同时赋值
# 初始化时可以给私有变量赋值
student = Student("111", "张三", "男", 19)  #不报错

#student.__age = 20 #不报错,但是改指令无效
student.mod_age(20)

7.继承

继承就是一个类,继承另外一个类的成员变量和成员方法
继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有)

子类构建的类对象,可以
1.有自己的成员变量和成员方法
2.使用父类的成员变量和成员方法

比如,我们要更新一款软件,更新之后的软件会失去之前的功能吗? 当然不会。更新之后的软件会继承之前的某些功能。

语法:

#在括号内填写 父类名
class father(父类1, 父类2,...):
    #类内容体

7.1 单继承

简单的说就是继承单个类(一个父类)


```python
# 父类
class Father:
    a = None

    def Fun_1(self):
        print("父类")
        self.a = 1
        print(self.a)


#子类
class Brother(Father):
    b = None
    def Fun_2(self):
        print("子类")
        self.b = 2

        #使用父类的成员变量
        print(Father.a)
        #使用父类的成员方法 要传参self
        Father.Fun_1(self)


test = Brother()
#调用自己的成员方法
test.Fun_2()

#调用父类的成员方法
test.Fun_1()

7.2 多继承

Python的类之间也支持多继承,即一个类可以继承多个父类

class Father_1:
    def Fun_1(self):
        print("父类一")


class Father_2:
    def Fun_2(self):
        print("父类二")

class Brother(Father_1, Father_2):
    def Fun_3(self):
        print("子类")

        
test = Brother()
# 调用父类一
test.Fun_1()
# 调用父类二
test.Fun_2()
# 调用子类
test.Fun_3()

多个父类中,如果有同名的成员怎么办呢?

答:多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。
即:先继承的保留,后继承的被覆盖

class Father_1:
    def Fun(self):
        print("父类一")


class Father_2:
    def Fun(self):
        print("父类二")

class Brother(Father_1, Father_2):
    def Fun_1(self):
        print("子类")


test = Brother()
# 调用父类的成员 ,调用的是父类一
test.Fun()

7.3 复写父类成员

子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写
即:在子类中重新定义同名的属性或方法即可。

一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员

class Father_1:
    def Fun(self):
        print("父类一")


class Father_2:
    def Fun(self):
        print("父类二")

class Brother(Father_1, Father_2):
    def Fun(self):
        print("子类")


test = Brother()
# 调用和父类的一样成员方法 ,调用的是自己的
test.Fun()

7.4 调用父类同名成员

一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类的成员,需要特殊的调用方式:

  • 方式1:
    调用父类成员
    使用成员变量:父类名.成员变量
    使用成员方法:父类名.成员方法(self)

  • 方式2:
    使用super()调用父类成员
    使用成员变量:super().成员变量
    使用成员方法:super().成员方法()

只能在子类内调用父类的同名成员。
子类的类对象直接调用 会调用子类复写的成员

class Father:
    n = 1
    def Fun(self):
        print("父类")


class Brother(Father):
    def Fun(self):
        print("子类")
        print()

        #方式一调父类成员
        print(Father.n)
        Father.Fun(self)
        print()

        #方法二调用父类成员
        print(super().n)
        super().Fun()



test = Brother()
test.Fun()

8. 类型注解

Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。

类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。

主要功能
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示,帮助开发者自身对变量进行类型注释

支持
变量的类型注解
函数(方法)形参列表和返回值的类型注解

8.1 变量类型注解

  1. 语法一: 变量名 : 类型


#变量类型注解
a :int = 1
b :float = 1.0
c :str = "1234"
d :bool = True

#类对象类型注解
class Test:
    pass

test :Test = Test()
  1. 语法二: type: 类型

#变量类型注解
a  = 1      # type: int
b  = 1.0    # type: float
c = "1234"  # type: str
d  = True   # type: bool

#类对象类型注解
class Test:
    pass

test = Test()  # type: Test

一般,无法直接看出变量类型之时会添加变量的类型注解

  1. 类型注解的限制

类型注解主要功能在于:
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
帮助开发者自身对变量进行类型注释(备注)

并不会真正的对类型做验证和判断。
也就是,类型注解仅仅是提示性的,不是决定性的

在这里插入图片描述

如上图,是不会报错的哦。

8.2 函数和方法的形参类型注解:

如图所示:
在调用函数(方法),将输入参数的时候,工具没有任何提示(下图)
在这里插入图片描述

在定义函数(方法)的时候,给形参进行注解(下图)
在这里插入图片描述

函数和方法的形参类型注解语法:

def 函数(方法)(形参 :类型, 形参 :类型,........) -> 返回值类型 :
    #...

样例:
在这里插入图片描述

8.3 Union类型

上面的注释是单个的,给大家看一个列表的注释:

my_list :list[int] = [1, 2, 3, 4]

my_dict :dict[str,int] = {"age" :19, "id" : 1234}

如果我们的 my_list 里面还有其他类型就还需要在相应位置加入相应的类型,这样的话是不是就变得复杂了?有没有解决方法呢?

答:有,Union类型

Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用。

使用Union[类型, …, 类型] 可以定义联合类型注解

#导包
from typing import Union

#                    多个类型                多个类型
my_list :list[ Union[int, float] ]= [1, 2, 3, 4.0, 5.0]

#             str 配多个类型          
my_dict :dict[str,Union[int, str]] = {"age" :19, "id" : 1234, "name" : "张三"}

9. 多态

9.1 多态

多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。

如何理解?

答:比如,老师布置一个任务,同学们用不同的方法解决了这个任务

class homework:
    def English(self):
        pass

#同学接收到作业后开始写
class student_1(homework):
    def English(self):
        print("student_1 英语的方法")

#同学接收到作业后开始写
class student_2(homework):
    def English(self):
        print("student_2 英语的方法")

#同样的行为(函数),传入不同的对象,得到不同的状态
#展示出学生的作业
def Fun(student : homework):
    student.English()


#创建对象
stu_1 = student_1()
stu_2 = student_2()

#调用函数
Fun(stu_1)
Fun(stu_2)

在这里插入图片描述

9.2 抽象类(接口)

细心的同学可能发现了,父类 homework 的 English 方法,是空实现
在这里插入图片描述

这种设计的含义是:
父类用来确定有哪些方法
具体的方法实现,由子类自行决定

这种写法,就叫做抽象类(也可以称之为接口)

抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法

9.3 抽象类的作用

多用于做顶层设计(设计标准),以便子类做具体实现

对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法
并配合多态使用,获得不同的工作状态

  1. 抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现。(下列代码)
class homework:
    #语文
    def Chinses(self):
        pass
   #数学
    def Math(self):
        pass
   #英语
    def English(self):
        pass


class student_1(homework):
    def Chinese(self):
        print("student_1 语文的方法")

    def Math(self):
        print("student_1 数学的方法")

    def English(self):
        print("student_1 英语的方法")


class student_2(homework):
    def Chinese(self):
        print("student_2 语文的方法")

    def Math(self):
        print("student_2 数学的方法")

    def English(self):
        print("student_2 英语的方法")
  1. 多态,完成抽象的父类设计(设计标准)和 具体的子类实现(实现标准),下列代码
#语文
def Fun_Chinese(student : homework):
    student.Chinese()
    
#数学
def Fun_Math(student : homework):
    student.Math()

#英语
def Fun_English(student : homework):
    student.English()


#创建对象
stu_1 = student_1()
stu_2 = student_2()

#每位同学的语文
Fun_Chinese(stu_1)
Fun_Chinese(stu_2)

#每位同学的数学
Fun_Math(stu_1)
Fun_Math(stu_2)

#每位同学的英语
Fun_English(stu_1)
Fun_English(stu_2)
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值