本篇内容
函数部分
– 不定长参数的扩展补充
– 匿名函数 lambda
面向对象
函数
不定长参数补充-函数调用时的拆包
# 定义一个名为my_sum的函数,可以接收任意数量的位置参数和关键字参数
def my_sum(*args, **kwargs):
num = 0 # 初始化变量num,用于保存求和的结果
# 遍历所有位置参数,并累加到num中
for i in args:
num += i
# 遍历所有关键字参数的值,并累加到num中
# kwargs是一个字典,所以使用.values()来获取所有的值
for j in kwargs.values():
num += j
print(num) # 打印出求和的结果
'''
需求说明:
我们有一个列表my_list和一个字典my_dict,需要使用my_sum函数来计算它们中所有数字的和。
'''
# 定义一个列表my_list,包含四个整数
my_list = [1, 2, 3, 4]
# 定义一个字典my_dict,键是字母,值是对应的整数
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# 使用my_sum函数求和
# 下面的调用展示了如何将列表和字典中的数据传递给my_sum函数
# 直接传递位置参数(这里为了演示,没有使用my_list,而是直接写了数字)
# my_sum(1, 2, 3, 4) # 输出: 10
# 直接传递关键字参数(这里为了演示,没有使用my_dict,而是直接写了关键字参数)
# my_sum(a=1, b=2, c=3, d=4) # 输出: 10
# 如果想将列表(或元组)中的数据分别作为位置参数传递给函数,需要使用*进行拆包操作
# *my_list会将my_list中的每个元素分别作为位置参数传递给my_sum函数
# my_sum(*my_list) # 输出: 10,等同于my_sum(1, 2, 3, 4)
# 如果想将字典中的数据作为关键字参数传递给函数,需要使用**进行拆包操作
# **my_dict会将my_dict中的每个键值对作为关键字参数传递给my_sum函数
my_sum(**my_dict) # 输出: 10,等同于my_sum(a=1, b=2, c=3, d=4)
匿名函数
匿名函数:
就是使用 lambda 关键字定义的函数,一般称为使用def 关键字定义的函数为,标准函数
匿名函数只能书写一行代码,匿名函数返回值不需要return,一行代码(表达式)的结果就是返回值。
使用场景:
作为函数的参数,这个函数比较简单,只使用一次,没有必要使用def
语法:
lambda 参数: 一行代码 # 这一行代码,称为是表达式
# 匿名函数一般不需要我们主动的调用, 一般作为函数的参数使用的
# 我们在学习阶段为了查看匿名函数定义的是否正确,可以调用
# 1, 在定义的时候 ,将匿名函数的引用保存到一个变量中
变量 = lambda 参数: 一行代码
# 2. 使用变量进行调用
变量()
# 简单的加法函数
add = lambda x, y: x + y
print(add(2, 3)) # 输出: 5
# 无参数的匿名函数
greet = lambda: "Hello, World!"
print(greet()) # 输出: Hello, World!
案例
# 1. 无参数返回值的函数
def func1():
# 打印字符串 'hello world'
print('hello world')
# 调用func1函数,将会打印 'hello world'
func1()
# 使用lambda表达式定义一个匿名函数,该函数没有参数,执行时打印 'hello world'
func11 = lambda: print('hello world')
# 调用匿名函数func11,将会打印 'hello world'
func11()
# 2. 无参数有返回值的函数
def func2():
# 返回整数 10
return 10
# 调用func2函数,并打印返回值,将会打印 10
print(func2())
# 使用lambda表达式定义一个匿名函数,该函数没有参数,返回整数 10
func22 = lambda: 10
# 调用匿名函数func22,并打印返回值,将会打印 10
print(func22())
# 3. 有参数无返回值的函数
def my_sum(a, b):
# 打印参数a和b的和
print(a + b)
# 调用my_sum函数,传入参数1和2,将会打印它们的和 3
my_sum(1, 2)
# 使用lambda表达式定义一个匿名函数,该函数接受两个参数a和b,打印它们的和
my_sum11 = lambda a, b: print(a + b)
# 调用匿名函数my_sum11,传入参数10和20,将会打印它们的和 30
my_sum11(10, 20)
# 4. 有参数有返回值的函数
def func4(a, b):
# 返回参数a和b的和
return a + b
# 调用func4函数,传入参数1和2,并打印返回值,将会打印它们的和 3
print(func4(1, 2))
# 使用lambda表达式定义一个匿名函数,该函数接受两个参数a和b,返回它们的和
func44 = lambda a, b: a + b
# 调用匿名函数func44,传入参数10和20,并打印返回值,将会打印它们的和 30
print(func44(10, 20))
练习
- 定义一个匿名函数可以求两个数的乘积
- 定义一个匿名函数,参数为字典,返回字典中键为 age 的值
# 1. 定义一个匿名函数,可以求两个数的乘积(需要两个参数)
# lambda a, b: a * b 表示定义一个匿名函数,接受两个参数a和b,返回它们的乘积
func1 = lambda a, b: a * b
# 调用func1函数,传入参数1和2,打印它们的乘积,将会打印 2
print(func1(1, 2))
# 再次调用func1函数,传入参数3和2,打印它们的乘积,将会打印 6
print(func1(3, 2))
# 2. 定义一个匿名函数,参数为一个字典,返回字典中键为'age'的值
# lambda x: x.get('age') 表示定义一个匿名函数,接受一个参数x(预期为字典),返回x中键为'age'的值
func2 = lambda x: x.get('age')
# 另一个匿名函数,功能与func2相同,但是使用了字典的索引操作来获取'age'的值
# lambda x: x['age'] 表示定义一个匿名函数,接受一个参数x(预期为字典),返回x中键为'age'的值
func3 = lambda x: x['age']
# 定义一个字典my_dict,包含'name'和'age'两个键值对
my_dict = {'name': '张三', 'age': 18}
# 调用func2函数,传入my_dict作为参数,打印返回的'age'的值,将会打印 18
print(func2(my_dict))
# 调用func3函数,传入my_dict作为参数,打印返回的'age'的值,将会打印 18
print(func3(my_dict))
匿名函数作为函数的参数-列表中的字典排序
# 定义一个包含多个字典的列表,每个字典代表一个用户,包含用户的姓名和年龄
user_list = [
{"name": "zhangsan", "age": 18}, # 用户张三,年龄18
{"name": "lisi", "age": 19}, # 用户李四,年龄19
{"name": "wangwu", "age": 17}, # 用户王五,年龄17
]
# 列表排序示例:
# 如果列表中的元素都是数字,可以直接使用 sort() 方法进行排序
# 例如:
# numbers = [3, 1, 4, 1, 5, 9]
# numbers.sort() # 升序排序,结果为 [1, 1, 3, 4, 5, 9]
# numbers.sort(reverse=True) # 降序排序,结果为 [9, 5, 4, 3, 1, 1]
# 但是对于列表中的元素都是字典的情况,想要根据字典中的某个键的值进行排序,需要提供一个排序的关键字参数 key
# 例如,如果我们想要根据用户的年龄进行排序:
# 按年龄升序排序
user_list.sort(key=lambda user: user['age']) # 升序排序,结果为 [{'name': 'wangwu', 'age': 17}, {'name': 'zhangsan', 'age': 18}, {'name': 'lisi', 'age': 19}]
# 如果想要按照年龄降序排序,可以设置 sort 方法的 reverse 参数为 True
user_list.sort(key=lambda user: user['age'], reverse=True) # 降序排序,结果为 [{'name': 'lisi', 'age': 19}, {'name': 'zhangsan', 'age': 18}, {'name': 'wangwu', 'age': 17}]
# 打印排序后的列表
print(user_list)
# 定义一个函数,用于获取字典中的'age'值,这个函数将作为排序的关键字参数
def get_value(x):
return x['age'] # 返回传入字典x的'age'键对应的值
# 使用sort方法对user_list进行排序
# key参数指定了一个函数,这个函数会被应用到列表的每个元素上
# 在这里,我们传入了get_value函数,所以列表将根据每个字典的'age'值进行排序
user_list.sort(key=get_value)
# 打印排序后的用户列表
print(user_list)
字符串比大小
大于号(>
) 和 小于号(<
)
ASCII 码(American Standard Code for Information Interchange,美国信息交换标准代码)是一种基于拉丁字母的字符编码标准,用于在计算机和其他设备中表示文本。ASCII 码使用 7 位二进制数(即 0 到 127 的十进制数)来表示字符,包括:
- 大小写英文字母(A-Z, a-z)
- 数字(0-9)
- 标点符号(如
!
,,
,.
等) - 控制字符(如换行符、退格符等)
字符比大小,是比较字符对应的 ASCII 码值
A < Z < a < z
ord(字符) # 获取字符对应的 ASCII 的值
chr(ASCII 值) # 获取对应的 字符
字符串比大小:
对应下标位置字符的大小, 直到比出大小, 如果全部比完了, 还没有比出大小,就是相等
面向对象
基本的介绍
面向对象是一个编成思想(写代码的套路)
编程思想:
1. 面向过程:面向过程是一种以 过程(函数) 为核心的编程思想。它将程序看作一系列步骤的集合,通过调用函数来完成任务。
2. 面向对象:面向对象是一种以 对象 为核心的编程思想。它将程序看作一系列对象的集合,每个对象包含数据(属性)和操作数据的方法。
以上两种都属于写代码的方法,最终目的都是为了将代码写出来,只不过过程和思考方式不太一样
- 面向过程
– 关注的是 具体步骤的实现,所有功能都自己书写
– 亲历亲为
– 定义一个个函数,最终按照顺序调用函数 - 面向对象
– 关注的是结果,谁(哪个对象)能帮我做这件事
– 偷懒
– 找一个对象(),让对象去做这件事
类和对象
面向对象的核心思想是 找一个对象去帮忙处理事情,在程序代码中,对象是由 类 创建的
类和对象,是面向对象编程思想中重要的两个概念
- 类
– 抽象的概念,对多个特征和行为相同或者相似事物的统称
– 泛指的(指代多个,而不是具体的一个) - 对象
– 具体存在的一个事物,看得见摸得着
– 特指的(指代一个)
苹果 —— 》类
红苹果——》类
张三嘴里正在吃的那个苹果——》对象
类的组成
- 类名(给这多个事物起一个名字,在代码中,满足大驼峰命名法(每个单词的首字母大写))
- 属性(事物的特征,即有什么,一般书写中的名词)
- 方法(事物的行为,即做什么事,一般是动词)
类的抽象(类的设计)
类的抽象,其实就是找到类的类名,属性 和 方法
例如:
类名: 人类(Person, People)属性: 名字(name), 年龄(age), 身高(height)方法: 跑步(run) 吃(eat)
类名: 狗类(Dog)属性: 颜色(color) , 名字(name)方法: 汪汪叫 (bark), 摇尾巴(shake)
面向代码的步骤
- 定义类,在定义类之前先设计类
- 创建对象,使用第一步定义的类创建对象
- 通过对象调用方法
面向对象基本代码的书写
1.定义类
萧定一简单的类,不包含属性,在python中定义类需要使用关键字 class
方法:
方法的本质是在类中定义的函数,只不过第一个参数是 self
class 类型:
# 在缩进中书写的内容,都是类中的代码
def 方法名(self): # 就是一个方法
pass
2.创建对象
创建对象是使用 类名()进行创建
即:
类名()
# 创建一个对象,这个对象在后续不能使用
# 创建的对象想要在后续的代码中继续使用,需要使用一个变量,将这个对象保存起来
变量 = 类名()
# 这个变量中保存的是对象的地址,一般可以成为这个变量的对象
# 一个类可以创建对各对象,只要出现 类名() 就是创建了一个对象,每个对象的地址是不一样的
3.调用方法
对象.方法名()
列表.sort()
列表.append()
4.案例实现
需求:小猫爱吃鱼,小猫要喝水
类名:猫类 cat
属性:暂无
方法:吃鱼(eat) 喝水(drink)
'''
需求:小猫爱吃鱼,小猫要喝水,定义不带属性的类
'''
# 定义一个名为cat的类,不带任何属性
class cat:
# 定义一个名为eat的方法,表示小猫吃鱼的行为
def eat(self):
print('小猫爱吃鱼') # 运行此方法会打印出'小猫爱吃鱼'
# 定义一个名为drink的方法,表示小猫喝水的行为
def drink(self):
print('小猫要喝水') # 运行此方法会打印出'小猫要喝水'
# 创建一个cat类的实例对象,名为blue_cat
blue_cat = cat()
# 通过blue_cat对象调用eat方法
blue_cat.eat() # 运行结果:小猫爱吃鱼
# 通过blue_cat对象调用drink方法
blue_cat.drink() # 运行结果:小猫要喝水
# 创建另一个cat类的实例,名为black_cat
black_cat = cat()
# 通过black_cat对象调用eat方法
black_cat.eat() # 运行结果:小猫爱吃鱼
# 通过black_cat对象调用drink方法
black_cat.drink() # 运行结果:小猫要喝水
# 创建一个cat类的实例,但是没有给它赋值给任何变量
cat() # 是,创建了一个临时对象
a = black_cat # 不是,并没有创建对象
b = cat # 不是,没有创建对象
self的说明
# 定义一个名为cat的类,表示小猫
class cat:
# 定义一个名为eat的方法,表示小猫吃鱼的行为
def eat(self):
print('小猫爱吃鱼') # 当调用此方法时,会打印出'小猫爱吃鱼'
# 创建一个cat类的实例,名为black_cat
black_cat = cat()
# 通过black_cat对象调用eat方法
black_cat.eat() # 运行结果:小猫爱吃鱼
- 从函数的语法上讲,self 是形参,就可以是任意的变量名,只不过我们习惯将这个形参写作self
self
虽然看起来是类方法中的一个普通形参,但在调用方法时,Python 解释器会自动将调用该方法的对象作为实参传递给self
,因此self
的本质就是调用方法的对象本身。- 当我们通过一个对象调用类的方法时,Python 会自动将这个对象的引用传递给方法的第一个参数(通常是
self
),因此self
就是这个对象的引用。换句话说,self
和调用方法的对象是同一个东西。 - 在 Python 中,
self
是类方法中的一个局部变量,而直接创建的对象(比如obj = MyClass()
)通常是全局变量。
"""
需求:小猫爱吃鱼,小猫要喝水, 定义不带属性的类
"""
class cat():
# 定义一个名为eat的方法,表示小猫吃鱼的行为
def eat(self):
# 打印当前对象的内存地址和字符串'self'
print(f'{id(self)},self') # 运行结果示例: 140289177749280,self
# 打印'小猫爱吃鱼'
print('小猫爱吃鱼') # 运行结果: 小猫爱吃鱼
# 创建一个cat类的实例,名为blue_cat
blue_cat = cat()
# 打印blue_cat对象的内存地址和字符串'blue_cat'
print(f'{id(blue_cat)},blue_cat') # 运行结果示例: 140289177749280,blue_cat
# 通过blue_cat对象调用eat方法
# 解释器会将blue_cat对象作为参数传递给eat方法中的self
blue_cat.eat()
# 运行结果:
# 140289177749280,self
# 小猫爱吃鱼
print('-' * 30)
# 创建另一个cat类的实例,名为black_cat
black_cat = cat()
# 打印black_cat对象的内存地址和字符串'black_cat'
print(f'{id(black_cat)},black_cat') # 注意这里打印的是'balck_cat',应该是'black_cat'
# 运行结果示例: 140289177749312,black_cat
# 通过black_cat对象调用eat方法
# 解释器会将black_cat对象作为参数传递给eat方法中的self
black_cat.eat()
# 运行结果:
# 140289177749312,self
# 小猫爱吃鱼
在上面的输出中,你可以看到 blue_cat
和 black_cat
的内存地址是不同的,但是当你调用它们的 eat
方法时,self
参数引用的是各自的对象,所以打印出的内存地址也是各自对象的地址。
对象的属性操作
1.添加属性
对象.属性名 = 属性值
- 类内部添加
·在内部方法中,self是对象,
·self.属性名 = 属性值
·# 在类中添加属性一般写在__init__方法中
·在 Python 中,__init__
是一个特殊的方法,被称为 构造函数(constructor)。它的主要作用是在创建类的对象时,自动执行一些初始化操作,比如设置对象的属性或执行一些必要的准备工作。 - 类外部添加
对象.属性名 = 属性值
# 一般不适用
获取属性
对象.属性名
- 类内部
在内部方法中,self是对象
self.属性名 - 类外部
对象.属性名
# 一般很少使用
# 定义一个名为cat的类
class cat():
# 定义一个名为eat的方法,表示小猫吃鱼的行为
def eat(self):
# 打印当前对象的内存地址和字符串'self'
print(f'{id(self)},self') # 打印对象的内存地址和'self'
# 打印小猫的名字和爱吃鱼的信息
print(f'小猫{self.name}爱吃鱼...') # 需要对象有name属性
# 创建一个cat类的实例,名为blue_cat
blue_cat = cat()
# 打印blue_cat对象的内存地址和字符串'blue_cat'
print(f'{id(blue_cat)},blue_cat') # 打印对象的内存地址和'blue_cat'
# 给blue_cat对象添加name属性,并赋值为'蓝猫'
blue_cat.name = '蓝猫'
# 通过blue_cat对象调用eat方法
# 解释器会将blue_cat对象作为参数传递给eat方法中的self
blue_cat.eat() # 运行结果:
# 对象blue_cat的内存地址,self
# 小猫蓝猫爱吃鱼...
print('_*_' * 30) # 打印分隔线
# 创建另一个cat类的实例,名为black_cat
black_cat = cat()
# 给black_cat对象添加name属性,并赋值为'黑猫'
black_cat.name = '黑猫'
# 打印black_cat对象的内存地址和字符串'black_cat'
print(f'{id(black_cat)},black_cat') # 打印对象的内存地址和'black_cat'
# 通过black_cat对象调用eat方法
# 解释器会将black_cat对象作为参数传递给eat方法中的self
black_cat.eat() # 运行结果:
# 对象black_cat的内存地址,self
# 小猫黑猫爱吃鱼...
魔法方法
python中有一类方法,以两个下划线开头,两个下划线结尾,并且在满足某个条件的情况下,会自动调用,这类方法称位魔法方法。
学习内容
- 什么情况下自动调用
- 有什么用,用在哪
- 书写的注意事项
__init__方法(重要)
- 什么情况下自动调用
创建对象之后会自动调用 - 有什么用,用在哪
1. 给对象添加属性(初始化方法,构造方法)
2. 某些代码,在每次创建对象之后,都要执行,就可以将这行代码写在 __init__ 方法中 - 书写的注意事项
1. 不要写错了
2. 如果 init 方法中,存在除了self 之外的参数,在创建对象的时候必须传参
"""
猫类, 属性 name, age , show_info(输出属性信息)
"""
# 定义一个名为cat的类,包含name和age属性,以及一个show_info方法用于输出属性信息
class cat():
# 定义初始化方法,当创建对象时会自动调用此方法
def __init__(self, name, age): # 初始化方法,接收name和age两个参数
self.name = name # 给对象添加name属性,并赋值为传入的name参数
self.age = age # 给对象添加age属性,并赋值为传入的age参数
# 定义一个名为show_info的方法,用于输出对象的name和age属性
def show_info(self):
print(f'小猫的名字是:{self.name}, 年龄是:{self.age}') # 输出对象的name和age属性
# 创建一个cat类的实例,名为blue_cat,传入'name'为'蓝猫','age'为2
# 此时会自动调用__init__方法来初始化blue_cat对象
blue_cat = cat('蓝猫', 2)
# 创建一个对blue_cat对象的引用,名为blue
blue = blue_cat
# 通过blue引用调用show_info方法,输出blue_cat对象的属性信息
# show_info方法不会自动调用,需要显式调用
blue.show_info() # 运行结果: 小猫的名字是:蓝猫, 年龄是:2
# 创建另一个cat类的实例,名为black_cat,传入'name'为'黑猫','age'为3
# 此时会自动调用__init__方法来初始化black_cat对象
black_cat = cat('黑猫', 3)
# 通过black_cat对象调用show_info方法,输出black_cat对象的属性信息
# show_info方法不会自动调用,需要显式调用
black_cat.show_info() # 运行结果: 小猫的名字是:黑猫, 年龄是:3
__str__方法 *
- 什么情况下自动调用
1. 使用print(对象)打印对象的时候,会自动调用 - 有什么用,用在哪?
1. 在这个方法中一般书写对象的 属性信息的,即打印对象的时候想要查看什么信息,在这个方法中进行定义的
2. 如果类中没有 __str__方法,print(对象),默认输出对象的引用地址 - 书写的注意事项
1. 这个方法必须返回一个字符串
# 定义一个名为cat的类
class cat():
# 定义初始化方法,当创建对象时会自动调用此方法
def __init__(self, name, age):
self.name = name # 给对象添加name属性,并赋值为传入的name参数
self.age = age # 给对象添加age属性,并赋值为传入的age参数
# 定义一个名为__str__的方法,用于定义对象的字符串表示形式
# 当使用print函数打印对象时,会自动调用此方法
def __str__(self):
# 方法必须返回一个字符串,这里返回包含name和age信息的字符串
return f'小猫的名字:{self.name},年龄是:{self.age}'
# 创建一个cat类的实例,名为blue_cat,传入'name'为'蓝猫','age'为2
# 此时会自动调用__init__方法来初始化blue_cat对象
blue_cat = cat('蓝猫', 2)
# 使用print函数打印blue_cat对象
# 由于定义了__str__方法,print函数会调用此方法并输出返回的字符串
print(blue_cat) # 运行结果: 小猫的名字:蓝猫,年龄是:2
# 创建另一个cat类的实例,名为black_cat,传入'name'为'黑猫','age'为3
# 此时会自动调用__init__方法来初始化black_cat对象
black_cat = cat('黑猫', 3)
# 使用print函数打印black_cat对象
# 由于定义了__str__方法,print函数会调用此方法并输出返回的字符串
print(black_cat) # 运行结果: 小猫的名字:黑猫,年龄是:3
__del__方法
- __init__方法:
创建对象之后,会自动调用(构造方法) - __del__方法:
对象被删除销毁时,自动调用的(遗言,处理后事)(析构方法)
- 调用场景:程序代码运行结束后,所有对象都被销毁
- 调用场景:直接使用del删除对象(如果对象有多个名字或者多个对象引用一个对象),需要把所有的对象都删除才行
# 定义一个名为Demo的类
class Demo:
# 定义初始化方法,当创建对象时会自动调用此方法
def __init__(self, name):
print('我是 __init__, 我被调用了 ') # 打印初始化方法被调用的提示信息
self.name = name # 给对象添加name属性,并赋值为传入的name参数
# 定义析构方法,当对象被销毁时会自动调用此方法
def __del__(self):
print(f'{self.name} 没了, 给他处理后事...') # 打印对象被销毁的提示信息,包含对象的name属性
# Demo('a') # 这行代码如果取消注释,会创建一个Demo类的实例,并调用__init__方法
# 创建一个Demo类的实例,名为a,传入'name'为'a'
a = Demo('a') # 运行结果: 我是 __init__, 我被调用了
# 创建另一个Demo类的实例,名为b,传入'name'为'b'
b = Demo('b') # 运行结果: 我是 __init__, 我被调用了
# 删除销毁对象a
del a # 运行结果: a 没了, 给他处理后事...
# 打印代码运行结束的提示信息
print('代码运行结束') # 运行结果: 代码运行结束
# 当程序运行到此结束,Python解释器会自动销毁所有未引用的对象
# 因此,b对象会被销毁,调用其__del__方法
# 运行结果: b 没了, 给他处理后事...