8、python集合&函数(上)——旺仔

本文介绍了Python中的集合,强调其不可重复和无序的特性,以及如何通过add、update等方法操作集合。同时,文章讲解了函数的基础,包括函数定义、参数传递方式,如位置传参、关键字传参,并探讨了可变类型与不可变类型的区别。此外,还涉及了函数的默认值、不定长参数以及参数拆包等概念,并提供了课后作业巩固学习。

在这里插入图片描述

一、集合

1、集合的简介

  • 集合表现形式为set 集合和列表非常相似
  • 不同点
    • 集合只能存储不可变对象
    • 集合中存储的对象是无序的
  • 集合不能出现重复元素
  • 使用{}来创建集合
  • 可以通过set()来将序列和字典转换成集合

总结一下:
集合的最大特点是:集合里边的元素是不可重复的并且集合内的元素还是无序的。
集合与字典的创建都是用花括号——{},但是集合是没有key与value键值对的。
一般情况下集合常用的两个场景是:

  • 去重(如:列表去重);
  • 关系测试(如:取交集、取并集、取差集等)
  • 代码展示讲解
#  使用{}来创建集合
set1 = {2, 'ab'}
print(set1)
# 运行结果 》》》{2, 'ab'}
# 创建空集合, 需要用到set()
s = {}  
print(type(s))
# 运行结果 》》》<class 'dict'>

s = set()
print(type(s))
# 运行结果 》》》<class 'set'>
# 集合只能存储不可变对象
set1 = {2, 'ab', [1, 2, 3]}
print(set1, type(set1))
# 上述代码一运行就会报错,因为集合只能存储不可变对象,列表是可变对象
# 集合中存储的对象是无序的
set2 = {6, 8, 9}
print(set2)
# 运行结果 》》》{8, 9, 6}
# 集合不能出现重复元素 通过这一特性,我们可以来做一个数据去重的效果
set3 = {1, 2, 3, 4, 1, 2, 3, 4}
print(set3)
# 运行结果 》》》{1, 2, 3, 4}

list1 = [1, 1, 2, 3, 3]     # 列表通过set()转换成集合去重
s4 = set(list1)
print(s4)
# 运行结果 》》》{1, 2, 3}

2、集合的使用

集合的一些方法与列表都是通用的,但是还是要看一下的哦,方法,虽然差不多,但是练习一下总没坏处哦。

集合的方法说明
len()使用len()来获取集合中元素的数量
add()像集合中添加元素
update()将一个集合中的元素添加到另一个集合当中
pop()随机删除集合中的一个元素一般是删除开始一个元素
remove()删除集合中指定的元素
clear()清空集合
  • len() 使用len()来获取集合中元素的数量
set1 = {2, 'ab'}
print(len(set1))
# 运行结果 》》》2
  • add()像集合中添加元素
s = set()
s.add(1)
s.add('a')
print(s)
# 运行结果 》》》{1, 'a'}
  • update()将一个集合中的元素添加到另一个集合当中
s1 = {1, 2, 3}
s2 = {'a', 'b', 'c'}
s1.update(s2)
print(s1)
# 运行结果 》》》{'c', 1, 2, 3, 'a', 'b'}
  • pop()随机删除集合中的一个元素一般是删除开始一个元素
s1 = {'c', 1, 2, 3, 'a', 'b'}
s1.pop()
print(s1)
# 运行结果 》》》{2, 3, 1, 'a', 'b'}
s1.pop()
print(s1)
# 运行结果 》》》{3, 1, 'a', 'b'}
  • remove() 删除集合中指定的元素
s1 = {1, 2, 3, 'a', 'b','c'}
s1.remove('a')
print(s1)
# 运行结果 》》》{1, 2, 3, 'c', 'b'}
  • clear() 清空集合
s1 = { 1, 2, 3, 'a', 'b','c'}
s1.clear()
print(s1)
# 运行结果 》》》set()

3、集合的运算

运算说明
&交集运算,结果为一样的部分
|并集运算,将2个集合 合并成一个集合
-差集运算,结果为第一个集合与第二个集合不一样的元素
^亦或集,将2个集合不一样的地方合并成一个集合
<=检查一个集合是否是另一个集合的子集
<检查一个集合是否是另一个集合的真子集
>=检查一个集合是否是另一个集合的超集
>检查一个集合是否是另一个集合的真超集
  • 代码演示
s1 = {1, 2, 3, 7, 8}
s2 = {4, 5, 6, 7, 8}

#  交集运算(&)
s3 = s1 & s2
print(s3)
# 运行结果 》》》{8, 7}

# | 并集运算
s4 = s1 | s2
print(s4)
# 运行结果 》》》{1, 2, 3, 4, 5, 6, 7, 8}

# - 差集运算
s5 = s1 - s2
print(s5)
# 运行结果 》》》{1, 2, 3}

# ^ 亦或集
s6 = s1 ^ s2
print(s6)
# 运行结果 》》》{1, 2, 3, 4, 5, 6}

让我们先了解一下子集,真子集和超集,真超集的基本概念

  • 子集,真子集:
    两者的包含范围不同。子集比真子集范围大,子集是包括本身的元素的集合,真子集是除本身的元素的集合。
    子集:集合A范围大于或等于集合B,B是A的子集;
    真子集:集合A范围比B大,B是A的真子集。
    如果集合A的任意一个元素都是集合B的元素(任意a∈A则a∈B),那么集合A称为集合B的子集,记为A⊆B或B⊇A,读作“集合A包含于集合B”或集合B包含集合A”。
    如果集合A是B的子集,且A≠B,即B中至少有一个元素不属于A,那么A就是B的真子集。
  • 超集,真超集
    超级和真超集与子集和真子集对应。
    如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集。 S1是S2的超集,若S1中一定有S2中没有的元素,则S1是S2的真超集,S2是S1的真子集。

简单点来说:
如果集合B是集合A的子集,那么集合A就是集合B的超集
如果集合B是集合A的真子集,那么集合A就是集合B的真超集
集合B是集合A的真子集,那么集合B就一定是集合A的子集,如果B∈A那么B⊊A
但集合B是集合A的子集,集合B不一定是集合A的真子集
超集的结论与子集差不多

# <= 检验是否为子集
set1 = {4, 5, 6, 7, 8}
set2 = {4, 5, 6, 7, 8}
set7 = set1 <= set2
print(set7)
# 运行结果 》》》True

# < 检验是否为真子集
set1 = {4, 5, 6, 7, 8}
set2 = {4, 5, 6, 7, 8}
set8 = set1 < set2
print(set8)
# 运行结果 》》》False

# < 检验是否为超集
set1 = {4, 5, 6, 7, 8}
set2 = {4, 5, 6, 7, 8}
set9 = set1 > set2
print(set9)
# 运行结果 》》》False

# < 检验是否为真超集
set1 = {4, 5, 6, 7, 8}
set2 = {4, 5, 6, 7, 8}
set10 = set1 >= set2
print(set10)
# 运行结果 》》》True

二、可变类型和不可变类型

结合之前博客中,我们已经讲完所有python中的基本类型,这里我们还要总结一下所有的数据类型。

  • 可变类型(mutable):列表,字典(key是不可变),集合
    里面的元素改变了,但是他的id还是不会变化
  • 不可变类型(unmutable):int,float,字符串,元组
    里面的元素改变了,那么他的id也就发生了变化

这里的可变不可变,从对象内存地址方向来说,是指内存中的值(value)是否可以被改变。
python所声明的变量都以对象的形式存在,存在于机器的固定内存之中。

  • 代码实操
# 字符串的更改
str1 = 'abc'
print(id(str1))
# 运行结果 》》》2480058428696

str2 = str1.replace('a', 'b')   # 将字符串中的a换成b
print(id(str2))
# 运行结果 》》》2480059406632

a = 'abc'
print(id(a))
# 运行结果 》》》2480058428696

a = 'bcd'
print(id(a))
# 运行结果 》》》2480059406352
# 列表更改
list1 = [1, 2, 3, 4]
print(id(list1))
# 运行结果 》》》2480058553160

list1.remove(4)   # 删除4这个元素
print(id(list1))
# 运行结果 》》》2480058553160

   通过上述代码,我们就可以很直观的看到ID的变换,不可变类型字符串,只要更改,ID就会随之改变可变类型列表,不管怎么更改,还是原先的ID

三、函数(上)

1、函数简介

语法:

def 函数名([形参1,形参2,形参3....]):
    代码块
	pass
xxx(实参)
  • 函数可以用来保存一些可以执行的代码,在你需要的时候可以对这些代码进行多次的使用
  • 函数保存的代码不会立即执行,需要调用函数的时候代码才会执行
  • 函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头)
  • 函数对象 fun
  • 函数调用 fun()

2、函数的参数

  • 形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是并不是赋值
  • 实参(实际参数)指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参就要有几个实参
# 需求: 定义一个函数求任意2个数的和
# 在函数中定义形参,相当于在函数内声明了变量
def fun(a, b):   # a, b  是形参  就是形式上的参数  ,你如果定义了形参,那么就必须在调用的时候传递实参
    print(a + b)

fun(1, 2)  # 1, 2 是实参,也就是实际参数

3、函数的传递方式

3.1、设置默认值

参数可以再设置形参的时候,直接给他设置一个默认值, 如果实参没有传递参数,那么直接使用默认值,如果实参传递了,那么就是用实参

def fun(a, b, c=20):
    print(a, b, c)

fun(1, 2)
# 运行结果 》》》1 2 20

fun(1, 2, 3)
# 运行结果 》》》1 2 3

3.2、位置传参

位置传参 就是讲对应位置上的实参赋予给对应位置上的形参

def fun1(a, b, c):
    print(a, b, c)

fun1(1, 2, 3)
# 运行结果 》》》1 2 3

3.3、关键字传参

关键字传参 可以不按照定义的顺序去进行参数的传递,根据参数名去传递实参

def fun2(a, b, c):
    print(a, b, c)

fun2(b=1, a=2, c=3)
# 运行结果 》》》2 1 3

3.4、混合使用

混合使用 位置传参必须放到关键字传参的前面

def fun2(a, b, c):
    print(a, b, c)

fun2(2, c=1, b=2)
# 运行结果 》》》2 2 1

4、不定长参数

不定长参数在一个函数中不管是还是**都只能存在一个,而且必须要在**之前
(*args , **kwargs)

4.1、*args参数

  • *不定长参数必须放到位置参数后面, 放到关键字参数的前面
# 需求: 求任意个数的和
def fn(*a):
    r = 0
    for i in a:
        r += i
    print(r)

fn(1, 2, 3, 4)
# 运行结果 》》》10
# 如需第一位为1	,最后一位为5,则
def fn(b, *a, c):
    r = b + c
    for i in a:
        r += i
    print(r)

fn(1, 2, 3, 4, c=5)
# 运行结果 》》》15

4.2、**kwargs参数

  • **kwargs不定长参数必须放到位置参数和关键字参数的后面
def fn1(*args, a, **kwargs):
    print(args)
    print(a)
    print(kwargs)

fn1(2,1, a=1, b=2, c=3, d=4, e=5)
# 运行结果 》》》
(2, 1)
1
{'b': 2, 'c': 3, 'd': 4, 'e': 5}

5、参数传递类型

  • 任意类型的参数都是可以传递的
    包括:int(整型);float(浮点型);string(字符串);bool(布尔值);None(空值);list(列表);tuple(元组);dict(字典);set(集合)
  • 这里还要说一下不同类型的参数传递后的改变
# 不可变类型 int
def fun2(a):  # a = b = 1
    a = 10
    print(a)

b = 1
fun2(b)
print(b)
# 运行结果 》》》
10
1
# 可变类型 list
def fun3(a):  # a = b = [1, 2, 3]
    a[2] = 10
    print(a)

b = [1, 2, 3]
fun3(b)
print(b)
# 运行结果 》》》
[1, 2, 10]
[1, 2, 10]

对于不可变类型来说,将其作为实参传递给形参,并通过函数,对其本身的值不产生变化,但是可变类型的值会随之改变,此处需注意,不清楚可以自行尝试其他几种基本数据类型。

6、参数拆包

def fun(a, b, c):
    print(a, b, c)

# 元组的拆包
t = (4, 5, 6)
fun(t[0], t[1], t[2])    # 通过索引取值为实参
# 运行结果 》》》4 5 6
fun(*t)					 # args不定长参数取值
# 运行结果 》》》4 5 6

# 字典的拆包
t = {'a': 1, 'b': 2, 'c': 3}		# kargs不到场参数取值
fun(**t)

字典的拆包需要注意key,key值必须与形参定义的一样,比如形参是abc,key也必须是abc

四、课后作业

在这里插入图片描述

1. 打印名片程序:输入姓名,电话号码,性别,最后打印出来名片

  • 控制姓名长度为6-20
  • 电话号码长度11
  • 性别只能允许输入男或女
  • 每一样信息不允许为空
# 第一种方法
while True:
    a = input("请输入姓名:")
    if len(a) > 20 or len(a) < 6:
        print("姓名长度在20到6之间")
    else:
        break
while True:
    b = input("请输入手机号码:")
    if len(b) == 11 and b.isdigit() == True:
        break
    else:
        print("手机号只能是11位")
while True:
    c = input("请输入性别:")
    c1 = ['男', '女']
    if c not in c1:
        print("性别只能是男或女")
    else:
        break
def fun(e,f,g):
    print("\t名片")
    print(f"姓名:\t{e}")
    print(f"手机号码:\t{f}")
    print(f"性别:\t{g}")

print("》》》》开始打印名片》》》》")
fun(a,b,c)
  • 运行结果如下:
    在这里插入图片描述

  • 知识点运用及编写思路:

此方法为最后输出的部分编写了一个函数,开始先进行3个输入循环判断,都没问题后,将得到的3个值作为函数fun的实参,然后进行输出,此题运用的while循环,if判断,以及运算符的使用都在往期博客中提过,此处就不过多赘述。

# 第二种方法
def name():
    while True:
        a = input("请输入姓名:")
        if len(a) > 20 or len(a) < 6:
            print("姓名长度在20到6之间")
        else:
            return a
def tel():
    while True:
        b = input("请输入手机号码:")
        if len(b) == 11 and b.isdigit() == True:
            return b
        else:
            print("手机号只能是11位")
def sex():
    while True:
        c = input("请输入性别:")
        c1 = ['男', '女']
        if c not in c1:
            print("性别只能是男或女")
        else:
            return c
print(f"》》》》开始打印名片》》》》\n\t名片\n姓名:\t{name()}\n电话:\t{tel()}\n性别:\t{sex()}")
  • 运行结果如下:
    在这里插入图片描述

  • 知识点运用及编写思路:

此方法与第一题的方法有相似之处,不同的地方就是将3个输入判断分别写成3个函数,最后直接输出,在输出中调用函数,重要的就是那个思路,相同就容易了,知识点运用与第一种方法一样。

2. 使用函数求前20个斐波那契数列斐波那契数列:1,1,2,3,5,8,13,21…即: 起始两项均为1,此后的项分别为前两项之和

# 方法一
def sum(a,b):
    return a+b
list1 = []
for i in range(20):
    if i <= 1:
        list1.append(1)
    else:
        list1.append(sum(list1[i-2],list1[i-1]))
else:
    print(list1)
  • 运行结果如下:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
  • 知识点运用及编写思路:

方法一就是创建一个sum的函数,将传入的参数相加然后return出和的值,再创建一个空列表,通过for循环,将i作为列表的索引,之后每次循环都添加一个数,数为前2个数的和。
有人问我这样还是看不懂怎么办,那么我们来看图:
在这里插入图片描述
这样写应该就很清晰了吧,可以再往后推几步哦。

# 方法二 递归
def fun(n):
    return 1 if n <= 1 else fun(n - 1) + fun(n - 2)
for i in range(20):
    print(fun(i), end=' ')
  • 运行结果如下:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 
  • 知识点运用及编写思路:

这里我们直接上图:在这里插入图片描述
这种方法是递归法,原先函数里面的是if条件语句,但是改成三元运算符也可以,只不过看上去更简便,此方法每次循环都调用一次fun函数,并将返回值输出,最终得到效果

# 方法三 递推
def fun1(n):
    a, b = 0, 1
    for i in range(n + 1):
        a, b = b, a + b
    return a
for j in range(20):
    print(fun1(i), end=' ')
  • 运行结果如下:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 
  • 知识点运用及编写思路:
i = 0 》fun1(0) 》n=0 》开始循环
a=1,b=1  》循环结束
return a 》fun(0)=1
i = 1 》fun1(1) 》n=1 》开始循环
a=1,b=1
a=1,b=2  》循环结束
return a 》fun(1)=1
i = 2 》fun1(2) 》n=2 》开始循环
a=1,b=1
a=1,b=2
a=2,b=3  》循环结束
return a 》fun(2)=2
i = 3 》fun1(3) 》n=3 》开始循环
a=1,b=1
a=1,b=2
a=2,b=3
a=3,b=5  》循环结束
return a 》fun(3)=3
i = 4 》fun1(4) 》n=4 》开始循环
a=1,b=1
a=1,b=2
a=2,b=3
a=3,b=5
a=5,b=8》循环结束
return a 》fun(4)=5
》》》以此类推》》》

以上为递推的过程,这个过程看上去就挺烦的把,对,虽然这种方法也能得到最终结果,但是每次循环,都要从开始算,会造成极大的运算性能浪费,所以看看就好,不建议使用哦。

# 方法四 生成器
def fun2(n):
    a, b = 0, 1
    for i in range(0, n):
        a, b = b, a + b
        yield a
for i in fun2(20):
    print(i, end=' ')
  • 运行结果如下:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 
  • 知识点运用及编写思路:

首先用到yield生成器,我们肯定得知道他是做什么的,再次我就直接引用一篇大神的文章,感觉写的特别详细,博客链接。方法四与方法三有很多相似,方法四加上了yield生成器,减少了许多不必要的运算,定义一个函数生成器fun2(),之间用fun2()进行遍历:

3. 编写一段代码,定义一个函数求1-100之间所有整数的和,并调用该函数打印出结果

# 方法一
def sum1():
    sum = 0
    for i in range(101):
        sum+=i
    return sum
print(sum1())

# 方法二
def sum2(a):
    sum = 0
    for i in range(a+1):
        sum += i
    return sum
print(sum2(100))
  • 运行结果如下:
    在这里插入图片描述

  • 知识点运用及编写思路:

这题其实很容易,虽然不用函数也可以写,但题意要求,所以还是用一下函数,第一种方法没有给函数参数,直接将所有的都写在函数里面,然后直接print输出就得到了值。
第二种方法是定义了个参数,定义参数的好处就在于如果我们要想求一个其他的数的值,只用改一个参数就可以了。
定义参数的作用在一些简单的程序中体现不是特别明显,但是如果是在一个很长的程序中,定义参数就会减少很多工作量。

在这里插入图片描述

旺仔注:

古人说:“万般皆下品,惟有读书高。”说粗浅一点,人是能读书著书的动物。故读书是划分人与禽兽的界限,也是划分文明人与野蛮人的界限。读现代的书就是与同时代的人作精神上的沟通交谈,读古人的书可以承受古圣先贤的精神遗产。  
人不是天生就明白很多东西,但是先人会给后人留下知识写在书上,人们通过读书对世界、对自己、对大自然有了更深刻的了解,然后在这个基础上继续探索,从而让人类更好的活着。 
csdn真的是一个非常好的平台,集结了各类大佬,大神,许多不懂的知识,看一下他们的文章,真的是豁然开朗,多看看大佬的文章,像大佬们努力!!!( •̀ ω •́ )✧
在这里插入图片描述

在这里插入图片描述

评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值