今日目录:
1. set
2. 函数
3. 内置函数
4. 文件操作
5. 三元运算
6. lambda表达式
7. 全局变量
一. set
set是Python基本数据类型中的一种,主要特性是: 无序、不重复的序列,基本功能包括关系测试(如父集子集等)、消除重复的元素等。set集合还支持difference(差集)、intersection(交集)、union(联合)、sysmmetric difference(对称差集)等数学运算。学习set还是按照两步骤来:1.创建 2.功能
1. 创建set集合
>>> s = set('daniel') >>> s {'d', 'n', 'e', 'l', 'i', 'a'} >>> type(s) <class 'set'>
或者:
>>> s1 = {'a','b','c',} >>> s1 {'a', 'c', 'b'} >>> type(s1) <class 'set'>
注意如果要创建一个空集合,必须使用set()了,s={} 默认的是字典类型,需要使用s=set()才行
>>> s1 = {} >>> type(s1) <class 'dict'> >>> s1 = set() >>> type(s1) <class 'set'> >>>
可以试着尝试下传入一个列表进去:
>>> l1 = [1,2,3,4,5,5,4,3,2,1,1,2,3,4,5] >>> s4 = set(l1) >>> s4 {1, 2, 3, 4, 5} #可以看到set的不重复特性
2. 操作方法
add 往set里添加元素
>>> s1 {1, 2, 3, 4, 5} >>> s1.add(6) >>> s1 {1, 2, 3, 4, 5, 6} #add()方法一次只能接受一个参数,也就是只能添加一个元素到set里 >>> s1.add(7,8,9) #一次加3个会报错 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: add() takes exactly one argument (3 given) #通过字符串形式添加,看能否一次添加多个 >>> l3='789abc' >>> s1.add(l3) >>> s1 {1, 2, 3, 4, 5, 6, '789abc'} #也是把一个字符串当成一个参数来添加
clear 清空set
>>> s1 {1, 2, 3, 4, 5, 6, '789abc'} >>> s1.clear() >>> s1 set()
copy 复制
>>> s1 {1, 2, 3, 4, 5, 6, '789abc'} >>> s2 = s1.copy() >>> id(s1) 139851744274920 >>> id(s2) 139851744275368
difference 取差集
>>> s1 = {1,3,4,5,} >>> s2 = {3,1,7,9} >>> s1.difference(s2) #A里有的元素,B里没有的元素 {4, 5}
intersection 取交集
>>> s1 = {1,3,4,5,} >>> s2 = {3,1,7,9} >>> s1.intersection(s2) #A和B都有的元素 {1, 3}
symmetric_difference 对称差集
>>> s1 = {1,3,4,5,} >>> s3 = {11,22,3,4} >>> s1.symmetric_difference(s3) #A中有,B没有,B有,A没有的元素 {1, 5, 11, 22}
difference_update intersection_update symmetric_difference_update 这三个放在一起说,主要是带update会更新原始数据:
>> s1 {1, 3, 4, 5} >>> s2 {9, 1, 3, 7} >>> s1.difference_update(s2) >>> s1 #s1的值已经变成了s1和s2的交集的结果 {4, 5} >>> s2 #s2的值没变 {9, 1, 3, 7} #intersection_update >>> s2 {9, 1, 3, 7} >>> s3 {3, 4, 11, 22} >>> s2.intersection_update(s3) >>> s2 #s2的值变成两个交集的结果 {3} >>> s3 #s3不变 {3, 4, 11, 22} #symmetric_difference_update >>> s3 {3, 4, 11, 22} >>> s4 {3, 44, 11, 22, 55} >>> s3.symmetric_difference_update(s4) >>> s3 #取两个集合的对称差集写入到s3中了 {4, 55, 44} >>> s4 #s4不变 {3, 44, 11, 22, 55}
discard 如果set中存在某元素,就删除
>>> s1 {4, 5} >>> s1.discard(60) #set中没有60元素,所以没返回任何消息 >>> s1 {4, 5} >>> s1.discard(5) #set中有元素5,所以,元素被删除 >>> s1 {4}
pop 删除元素,set是无序的,因此也是随机删除元素,但是会返回删除的这个元素值,pop的特性,在Python的数据类型中都是这种,删除后会返回这个删除元素;
>>> s4 {3, 44, 11, 22, 55} >>> s4.pop() 3 >>> s4.pop(55) >>> s4.pop() 44
remove 删除指定的元素,必须要返回一个值
>>> s4 {11, 22, 55} >>> s4.remove(44) #由于set中没有44元素,所以报错 Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 44 >>> s4.remove(55) #删除55元素 >>> s4 {11, 22}
issubset 是否是子集,是为True,否为False
>>> s3 {4, 55, 44} >>> s4 {33, 11, 44, 22, 55} >>> s3.issubset(s4) #s3不是s4的子集,返回为False False >>> s4.issubset(s3) False >>> s5 = {11,22,33} >>> s5.issubset(s4) #s5是s4的子集,返回True True
issuperset 是否是父集,是为True,否为False
>>> s4 {33, 11, 44, 22, 55} >>> s5 {33, 11, 22} >>> s4.issuperset(s5) #s4是s5的父集合,返回True True
union 联合,数据可以是字符串、list、dict、int任意类型,并且会把元素拆开,去重之后添加到set中,但是,如果需要保存的话,应该赋值给一个变量
>>> l1 = [1,2,3,4,5,] #创建一个列表 >>> s3 #查看s3以前元素 {4, 55, 44} >>> s3.union(l1) #将l1中的每一个元素遍历,并加入到sets中打印出来 {1, 2, 3, 4, 5, 44, 55} >>> s3 #s3中的元素还是没有变,所以如需保存,应该赋值给变量 {4, 55, 44} >>> str1='daniel' #创建一个字符串 >>> s3.union(str1) #union会将字符串拆分,去重后加入set打印 {4, 'l', 44, 'i', 55, 'a', 'n', 'e', 'd'} >>> t1 = (3,4,5,6,) #tuple一样 >>> s3.union(t1) {3, 4, 5, 6, 44, 55} >>> t1 = (3,4,5,6,99,0,234,441,34,) >>> s3.union(t1) {0, 34, 3, 4, 5, 6, 99, 234, 44, 55, 441} >>> d1 = {'k1':'v1','k2':'v2','k3':[1,3,3,4,55,]} #字典默认会遍历所有key然后加入到set打印 >>> s3.union(d1) {'k3', 'k2', 4, 55, 44, 'k1'}
update,和union一样,都是扩充/添加元素到set,唯一不同的是update会写入原有集合中,而union不会
>>> s1='daniel' #先创建一个字符串 >>> s2 = {'a','b','c'} #含有abc元素的set >>> s2 {'a', 'c', 'b'} >>> s2.update(s1) #加入元素s1 >>> s2 {'l', 'c', 'b', 'i', 'a', 'n', 'e', 'd'} #结果是直接写入到s2的set中 >>> l1 = [1,2,23,4,5,6,] >>> s2 {'l', 'c', 'b', 'i', 'a', 'n', 'e', 'd'} >>> s2.update(l1) >>> s2 {1, 2, 4, 'l', 'c', 5, 6, 'b', 'i', 23, 'a', 'n', 'e', 'd'}
isdisjoin 判断两个set中是否有交集,有返回True,否则返回False
>>> s2 {1, 2, 4, 'l', 'c', 5, 6, 'b', 'i', 23, 'a', 'n', 'e', 'd'} >>> s3 {4, 55, 44} >>> s2.isdisjoint(s3) False
3. 练习题
寻找差异
#需求: #如下数据,假设是一个CMDB,老的数据库中的数据(内存槽位): old_dic = { '#1': 8, '#2': 4, '#4': 2, } #新采集的数据, new_dic = { '#1': 4, '#2': 4, '#3': 2, } # 槽位1,槽位2值发生变化需要更新数据到老的数值 # 槽位4发生变化,已经移除,需要删除数据 # 槽位3发生变化,新增槽位,需要插入记录
old_dic = { '#1': 8, '#2': 4, '#4': 2, } new_dic = { '#1': 4, '#2': 4, '#3': 2, } #将新老数值的key值取出,并转换成set类型 old_dic1 = set(old_dic.keys()) new_dic1 = set(new_dic.keys()) #A和B取差集,找到要删除的槽位 print('要删除的槽位是: %s' %old_dic1.difference(new_dic1)) #A和B取交集,找到需要更新的槽位 print('要更新的槽位是: %s' %old_dic1.intersection(new_dic1)) #B和A取差集,找到要插入的槽位 print('要增加的槽位为: %s' %new_dic1.difference(old_dic1))
二. 函数
函数说白了就是一组代码集合,用于在程序中反复调用,解决代码重复编写的问题。两天的作业中,基本上都是堆积代码实现的,第二天的购物车程序更是码了近400行,根据作业需求逻辑从上到下一步一步码代码,一个打印功能就写了四处代码,而且一旦修改重复功能的话,所有的地方都要修改。这个是面向过程的编程方式。如果用到函数的话,代码首先变的很简洁,另外,review代码的人也比较容易看懂代码,毕竟程序不是一个人来编写的,即便是一个人编写的,过几天作者都有可能忘记自己写的代码段的功能了,所以函数式编程+良好的注释是一个很好的习惯和修养。
如下一个实例,验证用户登录身份,1:登录程序 2: 注册用户,如果用到面向过程编程的话,代码看起来是介样子的:
user_input_num = input('1. 登录程序 2.注册用户').strip() if user_input_num == '1': user_input_name = input('请输入用户名:').strip() user_input_pass = input('请输入密码:').strip() with open('user.db','r') as f: for line in f: if user_input_name == line.strip().split()[0] and user_input_pass == line.strip().split()[1]: print('登录成功') break else: print('登录失败,用户名或者密码错误') if user_input_num == '2': user_input_name = input('请输入用户名:').strip() user_input_pass = input('请输入密码:').strip() with open('user.db','r+') as f: for line in f: if user_input_name == line.strip().split()[0]: print('用户名太抢手,已经被注册啦') else: user_info = ' ' + user_input_name + ' ' + user_input_pass f.write(user_info) print('%s,恭喜你,注册成功' %user_input_name)
而使用函数式编程是这样的:
def login(username,password): ''' 用户登录程序 :param username:接受用户输入的用户名 :param password: 接受用户输入的密码 :return: True:表示认证成功,False:表示认证失败 ''' #with open('user.db','r') as f: f = open('user.db','r') for line in f.readlines(): if line.strip().split()[0] == username and line.strip().split()[1] == password: return True else: return False def registry(user,passwd): ''' 用户注册函数 :param user: 接受用户传入注册用的用户名 :param passwd: 接受用户传入的注册密码 :return: 如果用户不存在,并且写入用户名到文件成功后返回True,否则返回False ''' with open('user.db','r+') as f: for line in f: if user == line.strip().split()[0]: return True else: info = ' ' + user + ' ' + passwd f.write(info) return False def main(): user_select = input('1:登录程序, 2:注册用户').strip() if user_select == '1': username = input('请输入用户名:').strip() password = input('请输入密码:').strip() r = login(username,password) if r: print('登录成功') else: print('登录失败,用户名或密码错误') if user_select == '2': user_input_name = input('请输入用户名:').strip() passwd_input = input('请输入密码:').strip() R = registry(user_input_name,passwd_input) if R: print('用户名太抢手,已经被注册了!') else: print('注册成功!') if __name__ == '__main__': main()
好吧,这个例子不太明显,因为代码量少,看看我写的第二天的作业购物车程序例子吧:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Author: DBQ(Du Baoqiang) ''' Author: DBQ Blog: http://www.cnblogs.com/dubq/articles/5497639.html Github: https://github.com/daniel-vv/ops ''' import time import sys import os import pickle import getpass def User_Input_salary(): ''' 定义一个函数,用于接收用户输入工资金额 ''' Flag = False while not Flag: User_salary = input('请输入您预消费的金额(元):').strip() if User_salary.isdigit(): User_salary=int(User_salary) Flag = True if User_salary >= 200000: print('-'*50) print('