python学习 day5

set类型(集合)

无序且不重复的元素集合(可以简单快速的记忆:就是一个无序,不允许重复的列表) 

创建:

s = {11, 22, 33}

s = set(传入可迭代的对象)

注意:比如传入的是列表或者元组等,他会去遍历对象;然后将遍历出来的元素增加到自己内部中去;如果有重复的则将不再创建新的列表元素。 

li = [11, 22, 11, 33,22]
s = set(li)
print(s) # 结果{33, 11, 22}

方法详情

class set(object):
    """
    set() -> new empty set object
    set(iterable) -> new set object


    Build an unordered collection of unique elements.
    """
    def add(self, *args, **kwargs): # real signature unknown
        """
        Add an element to a set,添加元素


        This has no effect if the element is already present.
        """
        pass

    def clear(self, *args, **kwargs): # real signature unknown
        """ Remove all elements from this set. 清除内容"""
        pass

    def copy(self, *args, **kwargs): # real signature unknown
        """ Return a shallow copy of a set. 浅拷贝  """
        pass

    def difference(self, *args, **kwargs): # real signature unknown
        """
        Return the difference of two or more sets as a new set. A中存在,B中不存在


        (i.e. all elements that are in this set but not the others.)
        """
        pass

    def difference_update(self, *args, **kwargs): # real signature unknown
        """ Remove all elements of another set from this set.  从当前集合中删除和B中相同的元素"""
        pass

    def discard(self, *args, **kwargs): # real signature unknown
        """
        Remove an element from a set if it is a member.


        If the element is not a member, do nothing. 移除指定元素,不存在不报错
        """
        pass

    def intersection(self, *args, **kwargs): # real signature unknown
        """
        Return the intersection of two sets as a new set. 交集


        (i.e. all elements that are in both sets.)
        """
        pass

    def intersection_update(self, *args, **kwargs): # real signature unknown
        """ Update a set with the intersection of itself and another.  取交集并更更新到A中 """
        pass

    def isdisjoint(self, *args, **kwargs): # real signature unknown
        """ Return True if two sets have a null intersection.  如果没有交集,返回True,否则返回False"""
        pass

    def issubset(self, *args, **kwargs): # real signature unknown
        """ Report whether another set contains this set.  是否是子序列"""
        pass

    def issuperset(self, *args, **kwargs): # real signature unknown
        """ Report whether this set contains another set. 是否是父序列"""
        pass

    def pop(self, *args, **kwargs): # real signature unknown
        """
        Remove and return an arbitrary set element.
        Raises KeyError if the set is empty. 移除元素
        """
        pass

    def remove(self, *args, **kwargs): # real signature unknown
        """
        Remove an element from a set; it must be a member.


        If the element is not a member, raise a KeyError. 移除指定元素,不存在保错
        """
        pass

    def symmetric_difference(self, *args, **kwargs): # real signature unknown
        """
        Return the symmetric difference of two sets as a new set.  对称差集


        (i.e. all elements that are in exactly one of the sets.)
        """
        pass

    def symmetric_difference_update(self, *args, **kwargs): # real signature unknown
        """ Update a set with the symmetric difference of itself and another. 对称差集,并更新到a中 """
        pass

    def union(self, *args, **kwargs): # real signature unknown
        """
        Return the union of sets as a new set.  并集


        (i.e. all elements that are in either set.)
        """
        pass

    def update(self, *args, **kwargs): # real signature unknown
        """ Update a set with the union of itself and others. 更新 """
        pass
方法详情

.add(*args, **kwargs):添加元素==>直接在原有的基础上增加

se = set()
se.add(44)
se.add(33)  # 一次只能增加一个,多了会报错
print(se) # 结果{33, 44}

问题:我们知道set集合的创建有2中方式;如果我们用大括号这种?

se = {11, 22, 33}
se.add(55)  # 一次只能增加一个,多了会报错
print(se) #结果 {33, 11, 22, 55}

# 但是此时如果{}里面的内容为空的话会怎样?
se = {}
se.add(55)
print(se) #结果 报错!

分析上面报错的原因:

se = {}
# 当我们创建后我们我们可以看看se的类型:
print(type(se)) # 结果<class 'dict'>

分析结果:se = {} 这样创建的不是set类型;而是字典(dict)类型,而字典没有add方法;所以报错!

.clear():清除

se = {11, 22, 33}
print(se.clear()) # 结果 None
# set()创建的
se = set()
se.add(55)
se.add(22)
print(se.clear()) # 结果 None
.difference():找出方法前面对象里存在有的元素;而方法后面对象不存在的元素==》返回不同值形成的一个新的集合;
元素本身不变。
如:s1.difference(s2):意思:找出s1中存在有;而s2中不存在的元素 
s1 = {11, 22, 33}
s2 = {11, 55, 66}
print(s1.difference(s2)) # 结果 {33, 22}
# 将s1与s2互换
print(s2.difference(s1)) # 结果 {66, 55}

.difference_update():找出方法前面对象里存在有的元素;而方法后面对象不存在的元素,然后删除前后对象共有的元素;然后更新增加==》元素本身(s1或s2)会改变;内容会被更新;此方法不会返回值

注意:方法后面的元素不受影响

s1 = {11, 22, 33}
s2 = {11, 55, 66}
print(s1.difference_update(s2)) # None
print(s1) # 结果 {33, 22}
# 将s1与s2互换
s1 = {11, 22, 33}
s2 = {11, 55, 66}
print(s2.difference_update(s1)) # None
print(s2) # 结果 {66, 55}

注意:两个difference的区别。

.discard():移除指定元素,不存在不报错 

se = {11, 22, 33}
se.discard(11)
print(se) # 结果:{33, 22}
se.discard(44)
print(se) # 结果:{33, 22}

.remove():移除指定元素;不存在会报错

se = {11, 22, 33}
se.remove(11)
print(se) # 结果:{33, 22}
se.remove(44)
print(se) # 结果:报错

.intersection():取得交集==》返回一个集合

s1 = {11, 22, 33}
s2 = {"ah", 11, 5}
j = s1.intersection(s2)
print(j) # 结果{11}
print(s1) # {33, 11, 22} -->对象本身不变化

.intersection_update:去除交集,并更新元素本身;不共有的被删除;只剩共有值==》此方法不会产生新值

注意:方法后面的元素在操作中不受影响

s1 = {11, 22, 33}
s2 = {"ah", 11, 5}
j = s1.intersection_update(s2)
print(j) # None
print(s1) # {11} -->对象本身变化;只剩下交集
print(s2) # 元素后面的对象没变化 {'ah', 11, 5}

.isdisjoint():判断没有交集==》返回(没有是)True/(有是)False

s1 = {11, 22, 33}
s2 = {"ah", 11, 5}
j = s1.isdisjoint(s2)
print(j) # 结果 False

.issubset():判断是不是子序列==》返回True/False

注意:判断的是方法前面的是不是方法后面的子序列:一定要弄清顺序

s1 = {11, 22, 33}
s2 = {"ah", 11, 5}
s3 = {11, 22}
j = s1.issubset(s2) # 判断s1是不是s2的子序列
k = s3.issubset(s1) # 判断s3是不是s1的子序列
m = s1.idsubset(s3) # 判断s1是不是s3的子序列
print(j) # 结果 False
print(k) # 结果 True
print(m) # 结果 False
.issuperset():判断是不是父序列==》返回True/False
注意:判断的是方法前面的是不是方法后面的父序列:一定要弄清顺序
s1 = {11, 22, 33}
s2 = {"ah", 11, 5}
s3 = {11, 22}
j = s1.issuperset(s2) # 判断s1是不是s2的父序列
k = s3.issuperset(s1) # 判断s3是不是s1的父序列
m = s1.issuperset(s3) # 判断s1是不是s3的父序列
print(j) # 结果 False
print(k) # 结果 False
print(m) # 结果 True

总结:issubset()和issuperset():他们之间比较的子, 父关系;是看对应的对象里的每个元素;是否被包含,或包含的关系;

.pop():移除元素==》移除的过程会返回这个移除的值;可以用变量接收

s1 = {11, 22, 33, 44}
p = s1.pop() # 会返回一个值;然后用变量可以接收
print(p) # 结果 33
print(s1) # 结果 {11, 44, 22}
问题:为什么会删除33,而不是44?
引因为set()集合是无序的。里面的元素没排序的。是随机的。

.symmetric_difference():对称差集,然后返回差集组合的新对象

s1 = {11, 22, 33, 44}
s2 = {55, 11, 22, 66}
r1 = s1.difference(s2) # 获得s1有而s2没有的值
r2 = s2.difference(s1) # 获得s2有而s1没有的值
print(r1)  # 结果{33, 44}
print(r2)  # 结果{66, 55}

# 使用 s1.symmetric_difference()
ret = s1.symmetric_difference(s2)
print(ret) # 结果{33, 66, 44, 55}

总结:相当于;将2个集合中不同的元素拿出来组成一个新的集合

.symmetric_difference_update:将方法前后的集合中不同的元素拿出组合成新的集合然后替换掉方法前面的对象
注意:获取的集合替换的是方法前面的集合;后面的不受影响
s1 = {11, 22, 33, 44}
s2 = {55, 11, 22, 66}
ret = s1.symmetric_difference_update(s2)
print(ret) # 结果None
print(s1) # 结果{33, 66, 44, 55}-->方法前面的(s1)集合内容被替换掉
print(s2) # 结果 {66, 11, 22, 55}--》方法后面的集合(s2)不受影响

.union():取并集,取方法前后集合的所有值;组成新的集合,并让重复值,值显示一次==》返回新的集合

s1 = {11, 22, 33, 44}
s2 = {55, 11, 22, 66}
ret = s1.union(s2)
print(ret) # 结果 {33, 66, 11, 44, 22, 55}

# 当两个集合值不同时;可以组和两个集合
s1 = {11, 22, 33, 44}
s2 = {55, 66}
ret = s1.union(s2)
print(ret) # 结果 {33, 66, 22, 55, 11, 44}

.update:更新==》直接更新方法前面的原始集合,不产生新的对象

注意:更新的是方法前面的集合,后面的不受影响

s1 = {11, 22, 33, 44}
s2 = {55, 66}
s1.update(s2)
print(s1) # 结果{33, 66, 22, 55, 11, 44}
print(s2) # 结果{66, 55} 方法后面的不受影响

# 可以传入列表 等
s1 = {11, 22, 33, 44}
s1.update(["haha",489])
print(s1) #结果{33, 489, 11, 44, 'haha', 22}

练习:数据更新

两个数据(old和new)的key值比较;如果key相同;则new里面key对应的value会替换掉old里面相同key的值;
如果new里面有的key值;而old里面没有;则将new里面的数据增加进old里面。
如果old里面有;而new里面没有;则将old里面的独有的数据清除掉
old_dict = {
    "#1":11,
    "#2":22,
    "#3":100,
}
new_dict = {
    "#1":33,
    "#4":22,
    "#7":100,
}
# 获取旧数据中的key,并转换成set集合
old_set = set(old_dict.keys())
# 获取新数据中的key,并转换成set集合
new_set = set(new_dict.keys())
# 取出两个集合中的共有元素
in_set = old_set.intersection(new_set)
# 遍历取出的共有元素
for i in in_set:
    # 新/旧共有的数据;用新数据中key值对应的value值替换旧的数据
    old_dict[i] = new_dict[i]
# 获取旧数据中有的;而新数据中没有的数据;
j2 = old_set.difference(new_set)
# 遍历获取旧数据中的独有数据
for k in j2:
    # 将旧数据中的独有数据删除
    old_dict.pop(k)
# 获取新数据中有的;而旧数据中没有的数据
j3 = new_set.difference(old_set)
# 循环获取的新数据独有的数据
for c in j3:
    # 将其数据赋给旧数据;达到新数据替换旧数据的作用
    old_dict[c] = new_dict[c]
# 将整理完的数据打印
print(old_dict)

三目运算(三元运算)

理解性记忆:(我们之前学的)

if 条件:
    name = "haha"
else:
    name = "heihei"

用三元运算表示:

name = "值1" if 条件 else "值2"
注意:
1. 上面2串代码的意思是一样的。只是写法不一样;简单的if...else:都可以使用三元(目)运算表示
2. 条件成立将if前面的 值1 赋给变量;如果不成立将if后面的 值2 赋给变量
# 条件成立
name = "haha" if 1 == 1 else "heihei"
print(name) # 结果 haha
# 条件不成立
name = "haha" if 1 == 2 else "heihei"
print(name) # 结果 heihei

浅拷贝和深拷贝

1. str:一次性创建,不能被修改;如果修改;在内存里面是再创建一个新的字符串
2. 只要能被修改的,如(list等):他们是动态的;可以被添加,也可以被删除;他本质和 c语言 里面的链表一样;他创建完后,在内存里面会记录他的对应地址的上一个元素地址或者下一个元素地址的位置,这样方便添加。

一 数字和字符串

对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。

import copy  # 引入的copy模块
# ######### 数字、字符串 #########
n1 = 123
# n1 = "i am alex age 10"
print(id(n1))
# ## 赋值 ##
n2 = n1
print(id(n2))
# ## 浅拷贝 ##
n2 = copy.copy(n1)
print(id(n2))

# ## 深拷贝 ##
n3 = copy.deepcopy(n1)
print(id(n3))

二 其他基本数据类型

对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的

1. 赋值
赋值: 只是创建一个变量,该变量指向原来内存地址,如:
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 678]}
n2 = n1

2. 浅拷贝

浅拷贝,在内存中只额外创建第一层数据

import copy # 引入copy模块
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 678]}
n3 = copy.copy(n1)

3. 深拷贝
深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)
import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 678]}
n4 = copy.deepcopy(n1)

函数

一 背景

在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:

while True:
    if cpu利用率 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

    if 硬盘使用空间 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

    if 内存占用 > 80%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

腚眼一看上述代码,if条件语句下的内容可以被提取出来公用,如下:

def 发送邮件(内容)
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接

while True:
    if cpu利用率 > 90%:
        发送邮件('CPU报警')

    if 硬盘使用空间 > 90%:
        发送邮件('硬盘报警')

    if 内存占用 > 80%:

对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,其实这就是函数式编程和面向过程编程的区别:

  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”
函数式编程最重要的是增强代码的重用性和可读性

二 定义和使用 

def 函数名(参数):
    ...
    函数体
    ...
    返回值     # 没有返回值;结果为None

函数的定义主要有如下要点:

  • def:表示函数的关键字
  • 函数名:函数的名称,日后根据函数名调用函数
  • 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
  • 参数:为函数体提供数据
  • 返回值:当函数执行完毕后,可以给调用者返回数据。如果没设返回值;结果则为None 

1、返回值

函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。
以上要点中,比较重要有参数和返回值:
def 发送短信():

    发送短信的代码...

    if 发送成功:
        return True
    else:
        return False

while True:
    # 每次执行发送短信函数,都会将返回值自动赋值给result
    # 之后,可以根据result来写日志,或重发等操作

    result = 发送短信()
    if result == False:
        记录日志,短信发送失败..

2、参数

问题:为什么需要参数那? 

无参数实现: 

def CPU报警邮件()
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接

def 硬盘报警邮件()
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接

def 内存报警邮件()
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接

while True:
    if cpu利用率 > 90%:
        CPU报警邮件()

    if 硬盘使用空间 > 90%:
        硬盘报警邮件()

    if 内存占用 > 80%:
        内存报警邮件()

无参数实现

有参数实现:

def 发送邮件(邮件内容) # 邮件内容称法上叫 形式参数-->简称 形参

    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接

while True:
    if cpu利用率 > 90%:
        发送邮件("CPU报警了。") # 调用的时候传入的参数叫 实际参数-->简称 实参

    if 硬盘使用空间 > 90%:
        发送邮件("硬盘报警了。")

    if 内存占用 > 80%:
        发送邮件("内存报警了。")

有参数实现

函数的有三中不同的参数:

  • 普通参数
  • 默认参数
  • 动态参数

普通参数:

# ######### 定义函数 #########

# name 叫做函数func的形式参数,简称:形参
def func(name):
    print name

# ######### 执行函数 #########
#  'wupeiqi' 叫做函数func的实际参数,简称:实参
func('wupeiqi')

默认参数:-->放在参数的最后

def func(name, age = 18):
    print "%s:%s" %(name,age)

# 指定参数
func('wupeiqi', 19) # 结果 wupiqi:19
# 使用默认参数
func('alex')  # 结果 alex:18

注:默认参数需要放在参数列表最后

动态参数:

1、在形参前面加一个 * :传入的参数会形成一个元组(tuple)

def func(*args):
    print args

# 执行方式一
func(11,33,4,4454,5) # 返回的结果会形成个元组(11,33,4,4454,5)

# 执行方式二
li = [11,2,2,3,3,4,54]
func(*li) # 加了 * 相当于循环了整个列表,将其中的每个元素单独拿出来当实参传入

# 如果直接输入
li = [11, 22, 33]
func(li) # 结果([11, 2, 33],) 会将整个列表当成元素的一个元素

2、在形参前面加2个 **:传入的参数形成一个字典(list)

def func(**kwargs):
    print args

# 执行方式一
func(name='haha',age=18) # 传入参数的形式必须是一个key;对应一个value 结果 {'age': 18, 'name': 'haha'}

# 执行方式二
li = {'name':'haha', age:18, 'gender':'male'}
func(**li)

3、万能参数:传入的形参由加一个 * 和2个 * 的组合:会根据传入的参数形式;自动对应形成列表或元组

def aa(*b, **c): # 注意:一个*和2**的位置(都在最后面):一个*必须在 ** 的前面;不能放在 **的后面去;不然报错;
                 # 这个是规定
    print(b, type(b)) # 结果 (11, 22, 33) <class 'tuple'>
    print(c, type(c)) # 结果 {'k2': 'haha', 'k1': 123} <class 'dict'>
aa(11, 22, 33, k1=123,k2="haha")

在这种情况下;我们同样可以传入普通参数:-->会依次将实参的值赋予对应的形参值上

def aa(a, *b, **c):
    print(a, type(a)) # 结果 11 <class 'int'>
    print(b, type(b)) # 结果 (22, 33) <class 'tuple'>
    print(c, type(c)) # 结果 {'k2': 'haha', 'k1': 123} <class 'dict'>
aa(11, 22, 33, k1=123,k2="haha")

4、指定参数:

实参的传入不一定要按形参的顺序;但是,必须要将形参中的变量名加上才行(具体操作看下面的视图)-->指定形参的值

如果我们改变传入参数的顺序:(而且要让程序正常执行的操作)

扩展:发送邮件实例

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

msg = MIMEText('邮件内容', 'plain', 'utf-8')
msg['From'] = formataddr(["武沛齐",'wptawy@126.com'])
msg['To'] = formataddr(["走人",'424662508@qq.com'])
msg['Subject'] = "主题"

server = smtplib.SMTP("smtp.126.com", 25)
server.login("wptawy@126.com", "邮箱密码")
server.sendmail('wptawy@126.com', ['424662508@qq.com',], msg.as_string())
server.quit()

发送邮件实例
发送扩展
总结:
1、在函数里,只要执行了 return ;后面的代码则不会再执行。
2、函数的执行: 函数名(实参)-->实参可以多个;个数由形参决定;默认按照顺序一一对应的。
3、实参的传入不一定要按形参的顺序;但是,必须要将形参中的变量名加上才行,指定形参的值
4、形参可以接收任何数据

5、动态参数:
  • 在形参前面加一个 *;传入的参数会形成一个元组(tuple)
  • 在形参前面加2个 **;传入的参数会形成一个字典(list)
  • 注意:一个 * 和2个 *的位置(都必须在最后面):一个 * 必须在 ** 的前面;不能放在 **的后面去;不然报错;这个是规定
  • 一个 * 的args 和两个 * 的kwargs:这个是大家公用的写法。大家都这么写 

全局变量和局部变量

局部变量:函数内部定义的;只能在函数内使用的,在函数体外不能用。

def aa():
    a = 123 # 在函数体里面定义的就是局部变量;离开函数体就没用了 这个 a 就是 局部变量
    print(a)
print(a) # 出现报错!因为 a 没定义;页面上的 a 是局部的;外面不能享受的

全局变量:在函数体外定义的;在程序任何位置都可以用

a = 123 # 在函数外面定义的就是全局变量;任何位置都可以用  这个 a 就是 全局变量
def aa():
    print(a)
aa() # 结果 123
print(a) # 结果 123

注意:全局变量在局部虽然能被调用;但是在局部却没办法修改

a = 123 # 在函数外面定义的就是全局变量;任何位置都可以用
def aa():
    a = 456 # 这里定义的 a 是不能改变全局的 a 的;他和全局的 a 是2个意思
            # 两个是完全不同的变量
    print(a)

def bb():
    print(a) # 结果会输出 123 说明 aa()中没有改变全局变量 a 的值

aa()  # 结果 456
bb()  # 结果 123

那如果我非要改变那?==》加入 global 关键字

a = 123 # 在函数外面定义的就是全局变量;任何位置都可以用
def aa():
    global a # 这个 global 关键字的意思;是说明这个 a 是来自全局变量的
    a = 456
    print(a)

def bb():
    print(a) # 结果会输出 456 说明 aa()中改变全局变量 a 的值

aa()  # 结果 456
bb()  # 结果 456
潜规则:
1、动态参数一个 * 的时候后面跟 args 如:*args;    两个 * 的时候后面跟 kwargs 如:**kwargs
2、全局变量一律大写 如:ABC = 123;   局部变量一律小写 如  ef = "haha"

posted on 2016-10-13 15:53  jayafs  阅读(142)  评论(0)    收藏  举报

导航