解析Python面向对象:从小白到面向对象大师的蜕变之路

news2025/2/25 17:21:25

文章目录

  • 一 类和对象的概念
  • 二 类的认识
    • 2.1 类的定义和使用语法
    • 2.2 成员变量和成员方法
  • 三 类和对象
    • 3.1 类和对象的关系
    • 3.2 构造方法
    • 3.3 魔术方法概述(内置类方法)
    • 3.4 内置方法详解
  • 四 面向对象三大特性
    • 4.1 封装
      • 4.1.1 封装的理解
      • 4.1.2 私有成员变量和方法
      • 4.1.3 封装练习案例
    • 4.2 继承
      • 4.2.1 基础语法
      • 4.2.2 pass关键字
      • 4.2.3 多继承注意事项
      • 4.2.4 复写
      • 4.2.5 调用父类同名成员
    • 4.3 类型注解
      • 4.3.1 变量的类型注解
      • 4.3.2 函数(方法)的类型注解
      • 4.2.3 Optional和Union类型
      • 4.2.4 自定义类型
      • 4.2.5 补充:PEP 484中定义的语法规则
    • 五 多态
      • 5.1 多态概念
    • 5.2 抽象类(接口)
  • 六 进阶内容
    • 使用对象组织数据
      • 1. 创建自定义类
      • 2. 数据结构的封装
      • 3. 组合和关联
      • 4. 继承和多态

一 类和对象的概念

  • Python 是一种面向对象的编程语言,它将数据和方法封装到对象中,使得代码更加模块化和易于维护。这意味着几乎所有的数据都是对象,并且所有的操作都是通过调用对象的方法来完成的。

类和对象的基本概念:

  • 类(Class):类是对象的模板或蓝图,它定义了对象应该有的属性和方法。在类中,可以定义初始化方法 __init__ 和其他方法,以及属性。

  • 对象(Object):对象是类的实例,它是根据类的定义创建的。每个对象都有自己的属性和方法,但是这些属性和方法都是根据类的定义来的。

    # 1. 设计类
    class Student:
    	name=None;
    # 2. 创建对象
    stu_1=Student()
    stu_2=Student()
    # 3. 对象属性赋值
    stu_1.name="熊二"
    stu_2.name=	"翠花"
    

二 类的认识

2.1 类的定义和使用语法

  • 类(class)是一种用于创建对象(instances)的蓝图或模板。对象是类的实例,通过类可以定义对象的属性和方法。
  • 使用class是关键字定义类
    • 类的属性,即定义在类中的变量(成员变量)
    • 类的行为,即定义在类中的函数(成员方法)
      在这里插入图片描述
  • 类的定义语法
    # 定义一个类
    class 类名:
    	类的属性
    	类的方法
    
  • 创建类对象的语法
    对象名称=类名称()
    

2.2 成员变量和成员方法

  • 类中定义的属性(变量)——成员变量
  • 类中定义的行为(函数)——成员方法
    # 定义一个带有成员方法的类
    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_hi2("哎哟不错哟")
    
  • 在类中定义成员方法和定义函数基本一致,但仍有细微区别:
    def 方法名(self,形参1,...,形参n):
    	方法体
    
  • 在方法定义的参数列表中,有一个:self关键字。self关键字是成员方法定义的时候,必须填写的,用来表示类对象自身的意思
  • 当使用类对象调用方法的是,self会自动被python传入在方法内部,想要访问类的成员变量,必须使用self

  • self关键字,尽管在参数列表中,但是传参的时候可以忽略它。
    stu = Student()
    stu.name = "周杰轮"
    stu.say_hi2("哎哟不错哟")
    

三 类和对象

3.1 类和对象的关系

  • 显示世界的事务和类
    在这里插入图片描述

  • 现实世界的事物也有属性和行为,类也有属性和行为。使用程序中的类,可以完美的描述现实世界的事物

  • 创建类对象的语法

    对象名称=类名称()
    
  • 类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作这种套路,称之为:面向对象编程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 构造方法

  • Python类可以使用:__init__()方法,称之为构造方法。
    • 在创建类对象(构造类)的时候,会自动执行。
    • 在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用。
  • 在构造方法内定义成员变量,需要使用self关键字。原因:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。
  • 演示
# 演示使用构造方法对成员变量进行赋值
# 构造方法的名称:__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("周杰轮", 31, "18500006666")

3.3 魔术方法概述(内置类方法)

  • 在Python的类中,有一些特殊的内置方法(也称为魔术方法或双下划线方法),它们允许自定义类的行为,使其能够与Python的内置功能(如运算符、迭代等)进行交互。
  • 常见的Python类内置方法的列表:
方法名描述
__init__(self, ...)初始化方法,创建对象时自动调用。
__str__(self)返回对象的可打印字符串表示。
__repr__(self)返回对象的官方字符串表示,通常用于重新创建对象。
__len__(self)返回对象的长度。
__getitem__(self, key)当使用索引访问对象的元素时调用。
__setitem__(self, key, value)当使用索引赋值给对象的元素时调用。
__delitem__(self, key)当使用del obj[key]删除对象的元素时调用。
__iter__(self)返回一个可迭代对象,使对象可以被用于for循环。
__next__(self)在迭代对象时,每次调用next()函数时调用。
__eq__(self, other)当使用==运算符比较两个对象时调用。
__lt__(self, other)当使用<运算符比较两个对象时调用。
__gt__(self, other)当使用>运算符比较两个对象时调用。
__add__(self, other)当使用+运算符进行对象相加时调用。
__sub__(self, other)当使用-运算符进行对象相减时调用。
__mul__(self, other)当使用*运算符进行对象相乘时调用。
__divmod__(self, other)当使用divmod()函数进行对象除法和取余运算时调用。
__enter__(self)用于定义对象在with语句中的上下文管理行为。
__exit__(self, exc_type, exc_value, traceback)用于定义对象在with语句中的上下文管理行为。
  • 这些内置方法可以通过在类中实现相应的函数来自定义类的行为,使其与Python的内置功能进行交互。

3.4 内置方法详解

  • 在Python中定义一个类时,可以通过实现特定的内置方法来自定义类的行为。
  1. __init__(self, ...): 初始化方法,在创建对象时自动调用。用于初始化对象的属性。

示例:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Alice", 25)
print(person.name)  # 输出: Alice
print(person.age)   # 输出: 25
  1. __str__(self): 返回对象的可打印字符串表示。

示例:

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
    
    def __str__(self):
        return f"Book: {self.title} by {self.author}"

book = Book("The Great Gatsby", "F. Scott Fitzgerald")
print(book)  # 输出: Book: The Great Gatsby by F. Scott Fitzgerald
  1. __repr__(self): 返回对象的官方字符串表示,通常用于重新创建对象。

示例:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

point = Point(3, 5)
print(repr(point))  # 输出: Point(3, 5)
  1. __len__(self): 返回对象的长度。

示例:

class MyList:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):
        return len(self.items)

my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list))  # 输出: 5
  1. __getitem__(self, key): 当使用索引访问对象的元素时调用。

示例:

class MyList:
    def __init__(self, items):
        self.items = items
    
    def __getitem__(self, index):
        return self.items[index]

my_list = MyList([10, 20, 30])
print(my_list[1])  # 输出: 20
  1. __setitem__(self, key, value): 当使用索引赋值给对象的元素时调用。

示例:

class MyList:
    def __init__(self, items):
        self.items = items
    
    def __setitem__(self, index, value):
        self.items[index] = value

my_list = MyList([1, 2, 3])
my_list[1] = 10
print(my_list.items)  # 输出: [1, 10, 3]
  1. __delitem__(self, key): 当使用del obj[key]删除对象的元素时调用。

示例:

class MyList:
    def __init__(self, items):
        self.items = items
    
    def __delitem__(self, index):
        del self.items[index]

my_list = MyList([1, 2, 3])
del my_list[1]
print(my_list.items)  # 输出: [1, 3]
  1. __iter__(self): 返回一个可迭代对象,使对象可以被用于for循环。

示例:

class MyRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        value = self.start
        self.start += 1
        return value

my_range = MyRange(1, 4)
for num in my_range:
    print(num)  # 输出: 1 2 3
  1. __eq__(self, other): 当使用==运算符比较两个对象时调用。

示例:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

point1 = Point(3, 5)
point2 = Point(3, 5)
print(point1 == point2)  # 输出: True
  1. __lt__(self, other): 当使用<运算符比较两个对象时调用。

示例:

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    def __lt__(self, other):
        return self.radius < other.radius

circle1 = Circle(5)
circle2 = Circle(8)
print(circle1 < circle2)  # 输出: True
  1. __gt__(self, other): 当使用>运算符比较两个对象时调用。

示例:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def __gt__(self, other):
        return self.width * self.height > other.width * other.height

rectangle1 = Rectangle(4, 6)
rectangle2 = Rectangle(3, 8)
print(rectangle1 > rectangle2)  # 输出: False
  1. __add__(self, other): 当使用+运算符进行对象相加时调用。

示例:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        new_x = self.x + other.x
        new_y = self.y + other.y
        return Vector(new_x, new_y)

vector1 = Vector(2, 3)
vector2 = Vector(4, 1)
result = vector1 + vector2
print(result.x, result.y)  # 输出: 6 4
  1. __sub__(self, other): 当使用-运算符进行对象相减时调用。

示例:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __sub__(self, other):
        new_x = self.x - other.x
        new_y = self.y - other.y
        return Point(new_x, new_y)

point1 = Point(5, 8)
point2 = Point(3, 4)
result = point1 - point2
print

(result.x, result.y)  # 输出: 2 4
  1. __mul__(self, other): 当使用*运算符进行对象相乘时调用。

示例:

class ComplexNumber:
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag
    
    def __mul__(self, other):
        new_real = self.real * other.real - self.imag * other.imag
        new_imag = self.real * other.imag + self.imag * other.real
        return ComplexNumber(new_real, new_imag)

complex1 = ComplexNumber(3, 2)
complex2 = ComplexNumber(1, 4)
result = complex1 * complex2
print(result.real, result.imag)  # 输出: -5 14
  1. __divmod__(self, other): 当使用divmod()函数进行对象除法和取余运算时调用。

示例:

class CustomNumber:
    def __init__(self, value):
        self.value = value
    
    def __divmod__(self, other):
        quotient = self.value // other.value
        remainder = self.value % other.value
        return quotient, remainder

num1 = CustomNumber(20)
num2 = CustomNumber(3)
quotient, remainder = divmod(num1, num2)
print(quotient, remainder)  # 输出: 6 2
  1. __enter__(self)__exit__(self, exc_type, exc_value, traceback): 用于定义对象在with语句中的上下文管理行为。

示例:

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_value, traceback):
        self.file.close()

with FileManager("example.txt", "r") as file:
    content = file.read()
    print(content)
# 文件在退出上下文后自动关闭

四 面向对象三大特性

  • 面向对象编程,是许多编程语言都支持的一种编程思想。
  • 简单理解:基于模板(类)去创建实体(对象),使用对象完成功能开发。

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

  • 封装
  • 继承
  • 多态

4.1 封装

4.1.1 封装的理解

在这里插入图片描述

  • 封装:将现实世界事物的属性和方法,封装到类中描述为成员变量、成员方法,从而完成程序对现实世界事物的描述。
  • 封装会对用户隐藏属性和方法
    在这里插入图片描述
  • 类中提供了私有成员的形式来支持隐藏属性和方法:私有成员变量、私有成员方法

4.1.2 私有成员变量和方法

定义私有成员的方式非常简单,只需要:

  • 私有成员变量:变量名以__开头(2个下划线)
  • 私有成员方法:方法名以__开头(2个下划线)
# 定义一个类,内含私有成员变量和私有成员方法
class Phone:
	# 私有成员变量
    __current_voltage = 0.5        # 当前手机运行电压

	# 私有成员方法
    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()
  • 私有方法无法直接被类对象使用
  • 私有变量无法赋值,也无法获取值
  • 私有成员无法被类对象使用,但是可以被其它的成员使用。
    在这里插入图片描述

4.1.3 封装练习案例

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

  • 私有成员变量:__is_5g_enable,类型bool,True表示开启5g,False表示关闭5g
  • 私有成员方法:__check_5g(),会判断私有成员__is_5g_enable的值
    • 若为True,打印输出:5g开启
    • 若为False,打印输出:5g关闭,使用4g网络
  • 公开成员方法:call_by_5g(),调用它会执行
    • 调用私有成员方法:__check_5g(),判断5g网络状态
    • 打印输出:正在通话中
      运行结果:
      在这里插入图片描述
# 设计一个类,用来描述手机
class Phone:
    # 提供私有成员变量:__is_5g_enable
    __is_5g_enable = False # 5g状态


    # 提供私有成员方法:__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()

4.2 继承

在这里插入图片描述

4.2.1 基础语法

  • 继承分为:单继承和多继承
  • 继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有)
# 单继承
class 类名(父类名)
	类内容体
# 多继承
class 类名(父类1,父类2,...,父类N)
	类内容体	
# 演示单继承
class Phone:
    IMEI = None     # 序列号
    producer = "ITCAST" # 厂商


    def call_by_4g(self):
        print("4g通话")


class Phone2022(Phone):
    face_id = "10001"       # 面部识别ID


    def call_by_5g(self):
        print("2022年新功能:5g通话")


phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
  • Python的类之间也支持多继承,即一个类,可以继承多个父类
    在这里插入图片描述
# 演示多继承
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)

4.2.2 pass关键字

  • pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思

pass 的主要用途包括:

  1. 占位符:当在开发过程中正在编写框架或者计划添加代码逻辑但还没有完成时,可以使用 pass 来避免语法错误。

  2. 空函数或类:定义一个函数或类,但是暂时没有需要放入其中的代码。这时可以使用 pass 来定义一个空函数或空类。

示例:

# 占位符示例
if some_condition:
    pass  # 以后填充条件的实际逻辑

# 定义空函数
def empty_function():
    pass  # 暂时没有函数体,之后可能添加逻辑

# 定义空类
class EmptyClass:
    pass  # 暂时没有类的成员,之后可能添加属性和方法

4.2.3 多继承注意事项

  • 多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。即:先继承的保留,后继承的被覆盖
  • 这个概念被称为"方法解析顺序"(Method Resolution Order,简称MRO)。Python使用C3线性化算法来计算MRO,以确定调用同名成员时的优先级。
class A:
    def show(self):
        print("A")

class B:
    def show(self):
        print("B")

class C(A, B):
    pass

class D(B, A):
    pass

obj1 = C()
obj2 = D()

obj1.show()  # 输出: A,因为 A 在 C 的继承列表的左边
obj2.show()  # 输出: B,因为 B 在 D 的继承列表的左边

4.2.4 复写

  • 在面向对象编程中,子类可以通过复写(覆盖)父类的成员(方法或属性)来改变其行为。当子类定义了与父类同名的方法或属性时,子类的成员会覆盖父类的成员,从而在子类的实例中执行子类自己的逻辑。

示例:

class Animal:
    def speak(self):
        print("Animal speaks")

class Dog(Animal):
    def speak(self):
        print("Dog barks")

class Cat(Animal):
    def speak(self):
        print("Cat meows")

animal = Animal()
dog = Dog()
cat = Cat()

animal.speak()  # 输出: Animal speaks
dog.speak()     # 输出: Dog barks
cat.speak()     # 输出: Cat meows

4.2.5 调用父类同名成员

  • 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员。如果需要使用被复写的父类的成员,需要特殊的调用方式:
    方式1:
  • 调用父类成员
    • 使用成员变量:父类名.成员变量
    • 使用成员方法:父类名.成员方法(self)

方式2:

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

以下是一个调用父类方法的示例:

class Vehicle:
    def start(self):
        print("Vehicle started")

class Car(Vehicle):
    def start(self):
        super().start()  # 调用父类方法
        print("Car started")

car = Car()
car.start()

输出:

Vehicle started
Car started

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

  • 当子类复写了父类的成员(方法或属性),在子类内部可以通过 super() 函数来调用父类的同名成员。这是因为子类复写后,父类的成员被覆盖,但如果希望在子类中使用父类的实现,可以使用 super() 来实现这一点。

  • 然而,在子类的类对象直接调用成员时,会调用子类自己复写的成员。这是因为类对象直接访问成员时,不会触发 super() 的机制,而是直接使用类对象中的成员。

示例:

class Animal:
    def speak(self):
        print("Animal speaks")

class Dog(Animal):
    def speak(self):
        print("Dog barks")

class Cat(Animal):
    def speak(self):
        print("Cat meows")

dog = Dog()
cat = Cat()

dog.speak()  # 输出: Dog barks
cat.speak()  # 输出: Cat meows

# 类对象调用
Dog.speak()  # 输出: Dog barks
Cat.speak()  # 输出: Cat meows
  • 通过实例(对象)调用 speak() 方法时,会根据对象的类型调用相应的方法。但是,当您通过类对象直接调用 speak() 方法时,将会根据类对象的定义来调用方法,而不会触发 super() 机制。这导致了子类自己复写的方法被调用。

4.3 类型注解

  • Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。
  • 类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。它不会影响程序的实际执行,但可以提供更好的代码可读性、静态分析和类型检查。
  • 类型注解使用PEP 484中定义的语法规则
    主要功能:
  • 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
  • 帮助开发者自身对变量进行类型注释

支持:

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

4.3.1 变量的类型注解

基础语法:

变量: 类型
  • 类型注解的一些常见用法:
  1. 变量注解
    x: int = 5
    name: str = "Alice"
    
  2. 容器类型注解
    • 元组类型设置类型详细注解,需要将每一个元素都标记出来
    • 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
    # 基础容器类型注解
    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}
    
  3. 在注释中添加类型注解
    # 在注释中进行类型注解
    var_1 = random.randint(1, 10)   # type: int
    var_2 = json.loads('{"name": "zhangsan"}')  # type: dict[str, str]
    def func():
        return 10
    var_3 = func()  # type: int
    
    • 尽管这种方式在早期版本的Python中是一种常见的做法,但它并不是官方推荐的类型注解方式,因为它不会被类型检查工具如mypy等识别和解析。官方推荐的类型注解方式是使用PEP 484中定义的语法规则。
  • 官方推荐的类型注解方式
    from typing import Dict
    
    var_1: int = random.randint(1, 10)
    var_2: Dict[str, str] = json.loads('{"name": "zhangsan"}')
    
    def func() -> int:
        return 10
    
    var_3: int = func()
    

4.3.2 函数(方法)的类型注解

  • 函数和方法的形参类型注解语法:
    def 函数方法名(形参名:类型,形参名:类型)
    	内容体
    
  • 函数(方法)的返回值类型注解的语法
def 函数方法名(形参名:类型,形参名:类型)->返回值类型
	内容体

  • 演示:
  1. 函数参数注解
def greet(name: str) :
    print f"Hello, {name}"
  1. 函数返回值注解
def add(a: int, b: int) -> int:
    return a + b
  1. 复杂数据类型注解
from typing import List, Tuple

def process_data(data: List[Tuple[str, int]]) -> List[str]:
    result = [f"{name}: {value}" for name, value in data]
    return result

4.2.3 Optional和Union类型

  • Optional 和 Union 是用于类型注解中表示可选值或多种可能类型的重要工具
    • Optional用于表示一个值可以是特定类型,也可以是None。这在函数参数和返回值注解中特别有用,因为它允许参数可以是指定的类型,也可以是None。
    • 使用Union[类型, ......, 类型]可以定义联合类型注解
    • Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用。
  1. Optional类型:表示可选的类型。
    • age参数可以是int类型,也可以是None
from typing import Optional

def print_age(age: Optional[int]) -> None:
    if age is not None:
        print(f"Age: {age}")
  1. Optional和Union类型:表示多种可能的类型。
from typing import Union
def combine(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
    return a + b

4.2.4 自定义类型

  • NewType 是 Python 的 typing 模块中的一个工具,用于创建新的、独特的类型别名。它用于为现有的基本数据类型创建更具有语义的新类型,以提高代码的可读性和类型检查。

在实际使用中,NewType 并不会引入新的数据结构或运行时类型检查,它只是为了在类型注解中提供更多的语义信息,以及帮助类型检查工具识别不同的类型别名。

  • 以下是使用 NewType 来自定义新的类型别名的示例:

    from typing import NewType
    
    # 使用 NewType 创建 UserId 类型
    UserId = NewType('UserId', int)
    
    def get_user_name(user_id: UserId) -> str:
        return f"User {user_id}"
    
    • 在这个例子中,通过 NewType 创建了一个新的类型 UserId,它是一个整数 (int) 的别名。尽管 UserId 在类型注解中使用起来与 int 类型一样,但它有助于代码的可读性和类型检查。类型检查工具会将 UserId 视为不同于普通 int 的类型,从而提高了代码的安全性和可维护性。
  • 注意,NewType 不会在运行时引入额外的开销,因为它只是在类型注解中添加了更多的信息。在类型检查工具中,它可以帮助捕获一些潜在的类型错误。

4.2.5 补充:PEP 484中定义的语法规则

PEP 484定义了Python中类型注解的语法规则。以下是一些重要的语法规则和概念:

  1. 基本类型注解:使用内置的基本数据类型来进行注解,如intfloatstr等。

    x: int = 5
    name: str = "Alice"
    
  2. 复杂数据类型注解:使用typing模块中的类型来注解复杂数据类型,如ListTupleDict等。

    from typing import List, Tuple
    
    def process_data(data: List[Tuple[str, int]]) -> List[str]:
        result = [f"{name}: {value}" for name, value in data]
        return result
    
  3. 函数参数和返回值注解:使用->箭头表示函数的返回值类型注解。

    def add(a: int, b: int) -> int:
        return a + b
    
  4. Optional 和 Union 类型:使用Optional表示一个可选的类型,使用Union表示多种可能的类型。

    from typing import Optional, Union
    
    def print_age(age: Optional[int]) -> None:
        if age is not None:
            print(f"Age: {age}")
    
    def combine(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
        return a + b
    
  5. Type Aliases(类型别名):使用TypeVar来创建泛型类型参数,使用NewType来创建自定义的类型别名。

    from typing import TypeVar, NewType
    
    T = TypeVar('T')
    
    def repeat_item(item: T, times: int) -> List[T]:
        return [item] * times
    
    UserId = NewType('UserId', int)
    
  • PEP 484中定义的一些基本语法规则,允许你为变量、函数参数和返回值添加类型注解,从而提高代码的可读性和可维护性。
  • 类型注解并不会影响程序的实际执行,但可以在编辑器、IDE和类型检查工具中提供更好的代码分析和错误检测。

五 多态

5.1 多态概念

在这里插入图片描述

  • 多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
  • 多态常作用在继承关系上。比如:函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作。即:以父类做定义声明,以子类做实际工作,用以获得同一行为, 不同状态
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对象"""
    animal.speak()


# 演示多态,使用2个子类对象来调用函数
dog = Dog()
cat = Cat()

make_noise(dog) # "汪汪汪"
make_noise(cat) # "喵喵喵"

5.2 抽象类(接口)

  • 父类Animal的speak方法,是空实现
    这种设计的含义是:
    • 父类用来确定有哪些方法
  • 具体的方法实现,由子类自行决定
  • 这种写法,就叫做抽象类(也可以称之为接口)

抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(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)

六 进阶内容

使用对象组织数据

  • 在Python中,使用对象来组织数据,以便更好地管理和操作复杂的信息。对象允许将相关数据和方法封装在一起,使得代码更加模块化、可维护和可扩展。

1. 创建自定义类

  • 通过创建自定义类,定义一个新的数据类型,以适应应用程序的需求。这个类可以包含属性和方法,用于描述和操作该数据类型。
class Student:
    def __init__(self, name, age, grade):
        self.name = name
        self.age = age
        self.grade = grade
    
    def get_info(self):
        return f"Name: {self.name}, Age: {self.age}, Grade: {self.grade}"

# 创建学生对象
student1 = Student("Alice", 16, "10th")
student2 = Student("Bob", 17, "11th")

# 访问对象的属性和方法
print(student1.get_info())  # 输出: Name: Alice, Age: 16, Grade: 10th
print(student2.get_info())  # 输出: Name: Bob, Age: 17, Grade: 11th

2. 数据结构的封装

使用对象来封装复杂的数据结构,例如列表、字典或其他对象,以创建更有结构的数据模型。

class ShoppingCart:
    def __init__(self):
        self.items = []

    def add_item(self, item):
        self.items.append(item)
    
    def calculate_total(self):
        total = 0
        for item in self.items:
            total += item['price']
        return total

# 创建购物车对象
cart = ShoppingCart()

# 添加商品
cart.add_item({'name': 'Apple', 'price': 1})
cart.add_item({'name': 'Banana', 'price': 0.5})

# 计算总价
total_price = cart.calculate_total()
print(f"Total Price: ${total_price}")

3. 组合和关联

  • 将不同类型的对象组合起来,以表示更复杂的概念和关系。例如,一个学校对象可以包含多个学生对象。
class School:
    def __init__(self, name):
        self.name = name
        self.students = []

    def add_student(self, student):
        self.students.append(student)
    
    def get_student_names(self):
        return [student.name for student in self.students]

# 创建学校对象
school = School("ABC School")

# 添加学生
school.add_student(student1)
school.add_student(student2)

# 获取学生姓名列表
student_names = school.get_student_names()
print(f"Student Names: {student_names}")

4. 继承和多态

  • 通过继承和多态性,创建一个类层次结构,其中不同的类可以共享一些相似的属性和方法,并在需要时实现特定的行为。
class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

# 创建动物对象
dog = Dog()
cat = Cat()

# 调用不同的 speak 方法
print(dog.speak())  # 输出: Woof!
print(cat.speak())  # 输出: Meow!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/863057.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

致谢丨感谢有你,JumpServer开源项目九周年致谢名单

2014年到2023年&#xff0c;JumpServer开源项目已经走过了九年的时间。感谢以下社区贡献者对JumpServer项目的帮助和支持。 因为有你&#xff0c;一切才能成真。 JumpServer开源项目贡献者奖杯将于近日邮寄到以上贡献者手中&#xff0c;同时JumpServer开源项目组还准备了一份小…

2023年计算机科学与信息技术国际会议(ECCSIT 2023)

会议简介 Brief Introduction 2023年计算机科学与信息技术国际会议(ECCSIT 2023) 会议时间&#xff1a;2023年12月15日-17日 召开地点&#xff1a;中国北海 大会官网&#xff1a;www.eccsit.org 2023年计算机科学与信息技术国际会议(ECCSIT 2023)由国际电气、电子与能源工程协会…

Redis_哨兵模式

9. 哨兵模式 9.1 简介 当主库宕机&#xff0c;在从库中选择一个&#xff0c;切换为主库。 问题: 主库是否真正宕机?哪一个从库可以作为主库使用?如何实现将新的主库的信息通过给从库和客户端&#xff1f; 9.2 基本流程 哨兵主要任务&#xff1a; 监控选择主库通知 会有…

100个Java工具类之42:序列化工具类Apache之SerializationUtils

序列化工具类Apache之 org.apache.commons.lang3.SerializationUtils 众所周知&#xff1a;Java中序列化是指&#xff0c;将Java对象转换为可存储传输的字节序列的过程。 序列化作用&#xff1a; 1、网络传输&#xff1a;网络可以传输字节化的java对象 2、数据安全&#xf…

jQuery EasyUI datagrid 无记录时,增加“暂无数据“提示

我们只需要在onLoadSuccess中添加如下代码&#xff1a; if (data.total 0) {var body $(this).data().datagrid.dc.body2;body.find(table tbody).append(<tr><td width" body.width() " style"height: 35px; text-align: center;"><h…

20230811导出Redmi Note12Pro 5G手机的录音机APP的录音

20230811导出Redmi Note12Pro 5G手机的录音机APP的录音 2023/8/11 10:54 redmi note12 pro 录音文件 位置 貌似必须导出录音&#xff0c;录音的源文件不知道存储到哪里了&#xff01; 参考资料&#xff1a; https://jingyan.baidu.com/article/b87fe19e9aa79b1319356842.html 红…

以数据为中心的标记语言--yaml

&#x1f600;前言 本篇博文是关于以数据为中心的配置文件yaml的说明和应用&#xff0c;希望能够帮助到您&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&…

2023年电赛---运动目标控制与自动追踪系统(E题)—— 视觉部分

文章目录 一、前言二、视觉部分2.1&#xff1a;k210识别激光点2.2&#xff1a;k210识别方框和4个角点 三、总结 一、前言 &#x1f337;此次电赛我负责的部分主要是视觉&#xff0c;所以我着重和详细讲解一下视觉部分&#xff0c;不止限于此次电赛&#xff0c;而是从这次电赛视…

canfestival_主站发送同步对象触发主站PDO发送

1.入口处 2.开启定时器 3.调用定时器函数 4.切换到初始化状态&#xff0c;自动切换到预操作状态&#xff0c;最后进入操作状态 看到在预操作状态下&#xff0c;进行了通信状态的切换&#xff0c;调用相应的函数&#xff0c;如下&#xff1a; 5.调用开启SYNC的函数 查找对象字典…

让机器人懂得人类“常识”,3D语义地图能做到吗?

机器人需要一张保姆级地图。 随着机器人的智能化技术不断迭代&#xff0c;对于复杂的行为决策、人机交互等任务仅感知环境的空间几何信息已无法满足要求&#xff0c;它需要让机器人能够像人一样&#xff0c;懂得环境中的物体类别及其位置&#xff0c;即环境的语义信息。以扫地机…

字节跳动基于火山引擎DataLeap的一站式数据治理架构实践

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 在7月22日举行的 ArchSummit 全球架构师峰会&#xff08;深圳站&#xff09;上&#xff0c;来自火山引擎DataLeap的技术专家为大家带来了字节跳动基于火山引擎DataL…

day16:static、final、常量(static final)、

一、static 特点&#xff1a;属于类 、存储在方法去、只有一份或者只执行一次、随类运行执行 可以修饰静态变量 、静态方法 、静态代码块 静态变量能否继承&#xff1f; 静态变量属于类&#xff0c;是共享的资源&#xff0c;不认为是被继承的 静态变量不可以定义在静态方法中…

数据库数据恢复-Oracle数据库数据恢复案例

数据库数据恢复环境&#xff1a; Oracle数据库ASM磁盘组有4块成员盘。 数据库故障&分析&#xff1a; Oracle数据库ASM磁盘组掉线 &#xff0c;ASM实例无法挂载&#xff0c;用户联系我们要求恢复oracle数据库。 数据库数据恢复工程师拿到磁盘后&#xff0c;先将所有磁盘以只…

批量翻译多个文件夹,让你的文件管理更智能高效!

大家好&#xff01;对于经常需要管理大量文件夹的你来说&#xff0c;每次手动逐个改名实在是一项繁琐且易出错的工作。现在&#xff0c;我们为你带来一款强大的文件夹批量改名工具&#xff0c;让你能够轻松实现多个文件夹的批量翻译&#xff0c;让你的文件管理更智能高效 第一…

学会烟感监控有多重要?办公楼真的有必要吗?

随着城市化和建筑规模的不断扩大&#xff0c;火灾风险也日益凸显。为了保障员工和财产的安全&#xff0c;以及及时应对潜在的火灾威胁&#xff0c;办公楼需要采取积极的预防措施。 因此&#xff0c;在这一背景下&#xff0c;安装有效的烟感监控系统变得至关重要。 客户案例 ​…

AI抢饭碗!多部由Midjourney+Runway,制作的电影火了!丨IDCF

ChatGPT等生成式AI正在重塑各个行业的工作模式&#xff0c;尤其是影视领域。最近&#xff0c;多部由MidjourneyRunway生成式AI制作的电影预告片在社交平台上火了。 一部名叫的《芭本海默》的电影从对白、场景、人物、切镜完全由生成式AI制作完成并受到了用户的好评。该片结合了…

PHP 之房贷计算器、组合贷

一、等额本金 // &#xff08;等额本金&#xff09; //$loanAmount>贷款金额 //$loanPeriod>贷款年限 //$interestRate>贷款利息 function calculateEqualPrincipalPayment($loanAmount, $loanPeriod, $interestRate) {$monthlyPrincipal $loanAmount / ($loanPerio…

C#引用Web Service 类型方法,添加搜索本地服务器Web Service 接口调用方法

首先保证现在网络能调用web service接口&#xff0c;右键项目添加服务引用 ![![在这里插入图片描述](https://img-blog.csdnimg.cn/555ba4fa5e2a418f8f85539a9406bcd6.png) 点击高级 添加web服务 输入搜索的服务器接口&#xff0c;选中你要添加调用的方法即可 添加完成调用方…

性能优化-react阻止子组件重渲染

因为父组件的状态变更会触发子组件的渲染&#xff0c;可以用shouldComponentUpdate或memo来阻止。下面就来介绍这两种方法。 类组件-shouldComponentUpdate 注&#xff1a;变化需要在render中打印&#xff0c;在component中检测不到 核心代码: 子组件中用shouldComponentUpda…

[保研/考研机试] KY87 鸡兔同笼 北京大学复试上机题 C++实现

描述 一个笼子里面关了鸡和兔子&#xff08;鸡有2只脚&#xff0c;兔子有4只脚&#xff0c;没有例外&#xff09;。已经知道了笼子里面脚的总数a&#xff0c;问笼子里面至少有多少只动物&#xff0c;至多有多少只动物。 输入描述&#xff1a; 每组测试数据占1行&#xff0c;…