Python的类与对象、构造方法、类与对象三大特性封装、继承和多态、类型注解

 类与对象

1.Python的对象

 使用对象组织数据

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

  1. 在程序中设计表格,我们称之为:设计类(class) class Student: name None #记录学生姓名

  2. 在程序中打印生产表格,我们称之为:创建对象 #基于类创建对象 stu_1 Student() stu_2 Student()

  3. 在程序中填写表格,我们称之为:对象属性赋值 stu_1.name="张三"#为学生1对象赋予名称属性值 stu_2.name="李四"#为学生2对象赋予名称属性值

# 设计一个类(设计一张登记表)
class Student:
    name = None # 记录学生姓名
    gender = None # 记录学生性别
    nationality = None # 记录学生国籍
    native_place = None # 记录学生籍贯
    age = None # 记录学生年龄
# 创建一个对象
stu_1 = Student()
# 对象属性进行赋值
stu_1.name = "张三"
stu_1.gender = "男"
stu_1.nationality = "中国"
stu_1.native_place = "浙江省"
stu_1.age = 20
# 获取对象中记录的数据信息
print(stu_1.name)
print(stu_1.gender)
print(stu_1.nationality)
print(stu_1.native_place)
print(stu_1.age)

输出结果为:

张三
男
中国
浙江省
20

总结

  1. 生活中或是程序中,我们都可以使用设计表格、生产表格、填写表格的形式组织数据

  2. 进行对比,在程序中:

    设计表格,称之为:设计类(class)

    打印表格,称之为:创建对象

    填写表格,称之为:对象属性赋值

2.成员方法

类的定义和使用

在上一节中,我们简单了解到可以使用类去封装属性,并基于类创建出一个个的对象来使用。现在我们来看看类的使用语法: class 类名称:

类的属性

类的行为

  1. class是关键字,表示要定义类了

  2. 类的属性,即定义在类中的变量(成员变量)

  3. 类的行为,即定义在类中的函数(成员方法)

  4. 创建类对象的语法:对象 = 类名称()

可以使用类的具体对象去调用类内部提供的函数,需要调用self关键字

只有通过self,成员方法才能访问类的成员变量。

self关键字,尽管在参数列表中,但是传参的时候可以忽略它。

class Student:
    name = None
    def say_hi(self):
        print("Hello大家好")
​
    def say_hi2(self, msg):
        print(f"He1lo大家好,{msg}")
​
stu Student()
stu.say_hi()#调用的时候无需传参
stU.s8yh12("很高兴认识大家") #调用的时候,需要传msg参数

可以看到,在传入参数的时候,self是透明的,可以不用理会它。

可以看到,在传入参数的时候,self是透明的,可以不用理会它。

class Student:
    name = None
    def say_hi(self):
        print(f"大家好,我是{self.name},希望大家多多关照")
    def say_hi2(self, msg):
        print(f"大家好,我是{self.name},{msg}")
​
stu = Student()
stu.name = "张三"
stu.say_hi()
​
stu2 = Student()
stu2.name = "李四"
stu2.say_hi()
​
stu3 = Student()
stu3.name = "王五"
stu3.say_hi2("我是python大佬")

3.类与对象

我们现实中的事物可以归结为两个方面:属性和行为

基于类创建对象

实际上它的概念和C++的类与对象,是差不多的

如下设计一个闹钟类

class Clock:
    id = None # 序列化
    price = None # 价格
    def ring(self):
        import winsound
        winsound.Beep(2000, 3000)
# 构建两个闹钟对象并让其工作
clock1 = Clock()
clock1.id = "003032"
clock1.price = 19.99
print(f"闹钟ID:{clock1.id},价格:{clock1.price}")
clock1.ring()
​
clock2 = Clock()
clock2.id = "003033"
clock2.price = 19.99
print(f"闹钟ID:{clock2.id},价格:{clock2.price}")
clock2.ring()

4.构造方法

属性(成员变量)的赋值

class Student:
    name = None # 名称
    age = None # 年龄
    tel = None # 手机号
    
student1 = Student()
student1.name = "张三"
student1.age = 20
student1.tel = "18012340000"
​
student2 = Student()
student2.name = "李四"
student2.age = 18
student2.tel = "18112340000"

上方的代码,为对象的属性赋值需要依次进行,略显繁琐。

这时候我们就引出了构造方法

Python类可以使用:__ init __ ()方法,称之为构造法

可以实现:

  1. 在创建对象(构造类)的时候,会自动执行

  2. 在创建对象(构造类)的时候,将传入参数自动传递给__ init __方法使用

语法形式

class Student:
    name = None
    age = None
    tel = None
    def __init__(self, name, age, tel):
        self.name = name
        self.age = age
        self.tel = tel
        print("Student类创建了一个对象")
stu = Student("张三",20,"18012340000")
print(stu.name)
print(stu.age)
print(stu.tel)

5.其它内置方法

魔术方法

上文学习的__init__构造方法,是Python类内置的方法之一。

这些内置的类方法,各自有各自的特殊功能,这些内置方法我们称之为:魔术方法

__str__字符串方法

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    # __str__魔术方法
    def __str__(self):
        return f"Student类对象,name:{self.name},age:{self.age}"
        
stu = Student("张三",20)
print(stu)
print(str(stu))

__lt__小于符号比较方法

直接对2个对象进行比较是不可以的,但是在类中实现_t方法,即可闻时完成:小于符号和大于符号2种比较

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __lt__(self, other):
        return self.age < other.age
​
stu1 = Student("张三",20)
stu2 = Student("李四",21)
print(stu1 < stu2) # 结果:True
print(stu1 > stu2) # 结果:False

__le__小于等于比较符号方法

魔术方法:le可用于:<=、>=两种比较运算符上。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __le__(self, other):
        return self.age < other.age
​
stu1 = Student("张三",20)
stu2 = Student("李四",21)
print(stu1 <= stu2) # 结果:True
print(stu1 >= stu2) # 结果:False

__eq__等于符号比较

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __le__(self, other):
        return self.age < other.age
​
stu1 = Student("张三",20)
stu2 = Student("李四",21)
print(stu1 == stu2) # 结果:False
print(stu1 == stu2) # 结果:False

面向对象的三大特性

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

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

面向对象包含3大主要特性:封装、继承、多态

6.封装

现实生活中,很多事物或者行为,对用户实际上有隐藏的属性和行为。

私有成员

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

定义私有成员的方法也异常简单:

  1. 私有成员变量:变量名以__开头(两个下划线)

  2. 私有成员方法:方法名以__开头(两个下划线)

通过上述两步操作,就可以完成对私有成员的设置。

案例

class Phone:
    IMEI = None # 序列号
    producer = None # 厂商
    
    __current_voltage = 1 # 当前电压 私有成员
    
    def __keep_single_core(self):
        print("让CPU以单核模式运行以节省电量") # 私有成员方法
        
    def call_by_5G(self):
        if self.__current_voltage >= 1:
            print("5G通话已开启")
        else:
            self.__keep_single_core()
            print("电量不足,无法使用5G通话")
        
phone = Phone()
phone.call_by_5G()

设计带有私有成员的手机

设计一个手机类,内部包含:

私有成员变量:is_5G_enable,类型bool,True表示开启5g,False表示关闭5g

私有成员方法:_ _ check_5g(),会判断私有成员_ _ is _ 5g_enable的值

若为True,打印输出:5g开启

若为False,打印输出:5g关闭,使用4g网络

公开成员方法:call_by._ 5g(),调用它会执行

调用私有成员方法:_ _check_5g(),判断5g网络状态

打印输出:正在通话中

运行结果:5g关闭,使用4g网络,正在通话中

class Phone:
    __is_5G_enable = False
    # 提供私有成员方法:__check_5G()
    def __check_5G(self):
        if self.__is_5G_enable:
            print("5G开启")
        else:
            print("5G关闭,使用4G网络")
    # 公开成员方法:call_by_5G()
    def call_by_5G(self):
        self.__check_5G()
        print("正在通话中")
phone = Phone()
phone.call_by_5G()

7.继承

1.单继承

一个子类继承单个父类

class 类名(父类名):
    类内容体
# 演示单继承
class Phone:
    IMEI = None # 序列号
    producer = "HM" # 厂商
    def call_by_4G(self):
        print("4G通话")
        
class Phone2023(Phone):
    face_id = "10001"
    def call_by_5G(self):
        print("2023年新功能:5G通话")
        
phone = Phone2023()
print(phone.producer)
phone.call_by_4G()
phone.call_by_5G()

2.多继承

一个子类继承多个父类

class Phone:
    IMEI = None # 序列号
    producer = "HM" # 厂商
    def call_by_4G(self):
        print("4G通话")
​
class NFCReader:
    nfc_type = "第五代"
    producer = "HM"
    def read_card(self):
        print("NFC读卡")
    def write_card(self):
        print("NFC写卡")
        
class RemoteControl:
    rc_type = "红外遥控"
    def control(self):
        print("红外遥控开启")
​
class MyPhone(Phone, NFCReader, RemoteControl):
    pass
​
phone = MyPhone()
phone.call_by_4G()
phone.read_card()
phone.write_card()
phone.control()
print(phone.producer)

多继承中,如果父类有同名方法或属性。先继承的优先级高于后继承。

3.复写

子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。

即:在子类中重新定义同名的属性或方法即可。

class Phone:
    IMEI = None  # 序列号
    producer = "ITCAST"  # 厂商
​
    def call_by_5G(self):
        print("5G通话")
​
# 定义子类,复写父类成员
class MyPhone(Phone):
    producer = "ITHEMA"  # 复写子类的成员属性
​
    def call_by_5G(self):
        print("开启CPU单核模式,确保通话的时候省电")
        print("使用5G网络进行通话")
        print("关闭CPU单核模式,确保性能")
​
phone = MyPhone()
phone.call_by_5G()
print(phone.producer)

4.调用父类同名成员

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

如果需要使用被复写的父类的成员,需要特殊的调用方式:

方式一

调用父类成员

使用成员变量:父类名.成员变量

使用成员方法:父类名.成员方法(self)

方法二

使用super()调用父类成员

使用成员变量:super().成员变量

使用成员方法:super().成员方法()

class Phone:
    IMEI = None  # 序列号
    producer = "ITCAST"  # 厂商
​
    def call_by_5G(self):
        print("5G通话")
​
# 定义子类,复写父类成员
class MyPhone(Phone):
    producer = "ITHEMA"  # 复写子类的成员属性
​
    def call_by_5G(self):
        print("开启CPU单核模式,确保通话的时候省电")
        # 方法一
        print(f"父类的厂商是:{Phone.producer}")
        Phone.call_by_5G(self)
        # 方法二
        print(f"父类的厂商是:{super().producer}")
        super().call_by_5G()
        
        print("关闭CPU单核模式,确保性能")
​
phone = MyPhone()
phone.call_by_5G()
print(phone.producer)

8.类型注解

1.变量的类型注解

为什么需要类型注解?

在pycharm中编写代码,我们经常能够见到提示,提供一些可能选择的选项。

 这是因为pycharm确定这个对象的类型

又或者当我们调用方法的时候,进行传参的时候(快捷键ctrl+p跳出提示)

 会提示我们要传入两个参数进去,这是有内置模块random的方法提示的类型。这就引出了pycharm的类型注解。

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

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

主要功能:

  1. 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示

  2. 帮助开发者自身对变量进行类型注释(备注)

类型注解支持

  1. 变量的类型注解

  2. 函数(方法)形参列表和返回值的类型注解

类型注解的语法

为变量设置类型注解

基础语法:变量:类型

基础容器类型注解:

var_1: int = 10
var_2: float = 3.1415926
var_3: bool = True
var_4: str = "itheima"

容器类型详细注解:

my_list: list[int] = [1, 2, 3]
my_tuple: tuple[str, int, bool] = ("itheima", 666, True)
my_set: set[int] = {1, 2, 3}
my_dict: dict[str, int] = {"itheima": 666}

注意:

元组类型设置类型详细注解,需要将每一个元素都标记出来

字典类型设置类型详细注解,需要2个类型,第一个是key,第二个是value

示例

import random
import json
# 基础数据类型注解
var_1: int = 10
var_2: str = "itheima"
var_3: bool = True
​
# 类对象类型注解
class Student:
    pass
stu: Student = Student()
​
# 基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_dict: dict = {"itheima": 666}
​
# 容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[int, str, bool] = (1, "itheima", True)
my_dict: dict[str, int] = {"itheima": 666}
​
# 在注释中进行类型注释
var_4 = random.randint(1, 10) # type: int
var_5 = json.loads({'name': "张三"}) #type: dict
def func():
    return 10
var_6 = func() # type: int
# 类型注解的限制

为变量设置注解,显示的变量定义,一般无需注解:

var_1: int = 10
var_2: str = "itheima"
var_3: bool = True
var_4: Student = Student()

如上,就算不写注解,也明确的知晓变量的类型

一般,无法直接看出变量类型的时候,我们才会添加变量的类型注解。

class Student:
    pass
var_1: int = random.randint(1, 10)
var_2: dict = json.loads(data)
var_3: Student = func()

类型注解并不会真正的对类型做验证和判断。

也就是说,类型注解仅仅时提示性的,不是决定性的。

2.函数和方法类型注解

函数方法的类型注解——形参注解

def func(data):
    data.app

在编写上述的函数(方法),使用形参data的时候,工具没有任何提示

在调用函数(方法),传入参数的时候,工具无法提示参数类型

这是因为我们在定义函数方法的时候没有给形参进行注解

函数(方法)的形参类型注解语法

def 函数方法名(形参: 类型, 形参: 类型):
    pass
def add(x: int, y: int):
    return x + y
def func(data: list):
    pass

函数(方法)的类型返回值注解语法

def 函数方法名(形参: 类型, 形参: 类型) -> 返回值类型:
    pass
def func(data: list) -> list:
    return data

3.Union联合类型注解

Union类型

from typing import Union
    
my_list: list[Union[str, int]] = [1, 2, "itheima", "itcast"]
my_dict: dict[str, Union[str, int]] = {"name":"张三", "age": 31}
        
def func(data: Union[int, str]):
    pass

9.多态

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

class Animal:
    def speak(self):
        pass
    
class Dog(Animal):
    def speak(self):
        print("在狗叫")
        
class Cat(Animal):
    def speak(self):
        print("在猫叫")
        
def make_noise(animal: Animal):
    animal.speak()
    
dog = Dog()
cat = Cat()
make_nosie(dog)
make_nosie(cat)

多态常做用在继承关系上

比如函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作

即,以父类做定义声明,以子类做实际工作,用以获得同一行为和不同状态。

我们马上发现,父类Animal的speak方法,实际上是空实现的形式,也就是

class Animal:
    def speak(self):
        pass

这一块父类的代码,是一个抽象类(也叫接口),它的设计含义是有父类来确定方法,而由子类来决定具体方法的实现。

抽象类:含有抽象方法的类称之为抽象类

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

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

也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法

案例说明

设计一个空调的多态调用:

class AC:
    def cool_wind(self):
        """冷风"""
        pass
    def hot_wind(self):
        """热风"""
        pass
    def swing_l_r(self):
        """左右摆风"""
        pass
    
class Midea_AC(AC):
    def cool_wind(self):
        print("美的空调核心制冷科技")
    def hot_wind(self):
        print("美的空调电热丝加热")
    def swing_l_r(self):
        print("美的空调无风感左右扫风")
​
class Gree_AC(AC):
    def cool_wind(self):
        print("格力空调核心制冷科技")
    def hot_wind(self):
        print("格力空调电热丝加热")
    def swing_l_r(self):
        print("格力空调无风感左右扫风")
        
def make_cool(ac: AC):
    ac.cool_wind()
    
midea_ac = Midea_AC()
gree_ac = Gree_AC()
​
make_cool(midea_ac)
make_cool(gree_ac)

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年5月28日
下一篇 2023年5月28日

相关推荐