Python - set & 函数

一、基本数据类型补充 ─ set(是一个无序且不重复的元素集合)

#创建集合,两种方式
>>> s = set([11,22,33])  #set 中最多传一个参数
>>> type(s)
<#class 'set'>    # 这里的#加上是为了显示,可以忽略

>>> new_s = {11,22,33}  #用{},看起来像是字典,但是字典是有键值对,而set没有
>>> type(new_s)
<#class 'set'>
#转换
>>> li = [11,22,33]   
>>> set(li)              #讲列表转换为集合
{33, 11, 22}

>>> li = [11,11,11]  
>>> set(li)         #集合是不允许重复的,所以当列表li转为集合的时候,想的元素在集合中只显示一次
{11}
  • add(self,*args,**kwargs) #添加元素
  • >>> s = set()    #创建一个空集合
    >>> s.add(11)    #add只能添加一个元素,也不能添加列表,添加多个可以使用update
    >>> s
    {11}
    
  • update(self,*args,**kwargs) #添加元素,可以添加多个
  • >>> s = set()
    >>> s.update([11,22,33])
    >>> s
    {33, 11, 22}
    
  • clear(self,*args,**kwargs) #清除内容
  • >>> s.clear()
    >>> s
    set()
    
  • difference(self,*args,**kwargs) #A中存在,B中不存在的,并将其赋于一个新值
  • >>> A = {11,22,33,44}
    >>> B = {11,33,55,77}
    >>> ret = A.difference(B)
    >>> A                      #A的数值不变
    {33, 11, 44, 22}
    >>> ret                    #将A集合存在,B集合不存在的元素ret
    {44, 22}
    
  • difference_update(self,*args,**kwargs) #A中存在,B中不存在的,并更新A
  • >>> ret = A.difference_update(B)
    >>> A 
    {22, 44}             #A本身得到了变化 
    >>> ret
    >>>                  #ret是和空,这里就不会赋值给ret,而是赋值给了A
    
  • intersection(self,*args,**kwargs) #交集(A中存在且B中也存在的),将交集部分赋于一个新值
  • >>> A = {11,22,33,44}
    >>> B = {11,33,55,77}
    >>> ret = A.intersection(B)
    >>> ret
    {33, 11}
    
  • intersection_update(self,*args,**kwargs) #交集,将交集更新给A
  • >>> A.intersection_update(B)
    >>> A
    {33, 11}
    
  • symmetric_difference(self,*args,**kwargs) #对称差集(A中存在,B中不存在的),并将差集赋于一个新值
  • >>> A = {11,22,33,44}
    >>> B = {11,33,55,77}
    >>> ret = A.symmetric_difference(B)
    >>> ret
    {22, 55, 44, 77}
    
  • symmetric_difference_update(self,*args,**kwargs) #对称差集,将差集赋于给A
  • >>> A.symmetric_difference_update(B)
    >>> A
    {22, 55, 44, 77}
    
  • union(self,*args,**kwargs) #并集(A,B中都存在的元素),并将其赋于一个新值
  • >>> A = {11,22,33,44}
    >>> B = {11,33,55,77}
    >>> ret = A.union(B)
    >>> ret
    {11, 77, 22, 33, 44, 55}         #相同的元素只存一个,因为集合是不允许重复的
    
  • discard(self,*args,**kwargs) #删除元素,元素不存不报错
  • >>> A
    {22, 55, 44, 77}
    >>> A.discard(22)        #从集合A中删除22
    >>> A
    {55, 44, 77}
    >>> A.discard(99)        #删除99,但是在集合中没有99,也没有报错
    
  • remove(self,*args,**kwargs) #删除元素,元素不存报错
  • >>> A
    {55, 44, 77}
    >>> A.remove(77)          #移除77,没问题
    >>> A
    {55, 44}
    >>> A.remove(88)          #移除88,在集合中不存在,报错
    Traceback (most recent call last):
      File "", line 1, in 
    KeyError: 88              
    
  • pop(self,*args,**kwargs) #删除末尾元素,元素不存报错
  • >>> A = {11,22,33,44}
    >>> A.pop()                #这里删除的为啥不是44呢?? 因为set是无序的,
    33
    >>> A
    {11, 44, 22}
    
  • isdisjoint(self,*args,**kwargs) #如果没有交集,返回True,否则返回False
  • >>> A = {11,22,33,44}
    >>> B = {11,33,55,77}
    >>> A.isdisjoint(B)
    False                     #A、B存在交集
    >>> C = {56,7,8,4}
    >>> B.isdisjoint(C)
    True                      #B和 C完全不同,没有交集
    
  • issubet(self,*args,**kwargs) #是否是子集,是则返回True
  • >>> A = {11,22}
    >>> B = {11,22,33,44} 
    >>> A.issubset(B)                 #A完全属于B,所以A是B的子集
    True
    
  • issuperset(self,*args,**kwargs) #是否是父集
  • >>> B.issuperset(A)
    True
    

    二、三元运算

    #普通
    if 1 == 1:
        name = 'alex'
    else:
        name='durand'
    
    print(name)
    
    #三元运算 (减少代码量,只能做简单的if,else)
    name = 'alex' if 1 ==1  else 'durand'   #name = 值1 if 条件 else 值2
    print(name)
    

    三、深浅拷贝

    1.数字和字符串

    对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
    import copy
    # ######### 数字、字符串 #########
    n1 = 123
    # n1 = "i am alex"
    print(id(n1))
    
    # ## 赋值 ##
    n2 = n1
    print(id(n2))
    
    # ## 浅拷贝 ##
    n3 = copy.copy(n1)
    print(id(n3))
      
    # ## 深拷贝 ##
    n4 = copy.deepcopy(n1)
    print(id(n4))
    

    2.其他基本数据类型

    对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。
    1)、赋值
    赋值,只是创建一个变量,该变量指向原来内存地址,如:
    n1 = {"name1": "Alex", "name2": 'Durand', "name3": ["Kevin", 19]}
      
    n2 = n1
    

    2)浅拷贝,在内存中只额外创建第一层数据
    import copy
      
    n1 = {"name1": "Alex", "name2": 'Durand', "name3": ["Kevin", 19]}
      
    n3 = copy.copy(n1)
    

    3)深拷贝,在内存中将所有的数据重新创建一份(除了最后一层,即:python内部对字符串和数字的优化)
    import copy
      
    n1 = {"name1": "Alex", "name2": 'Durand', "name3": ["Kevin", 19]}
      
    n4 = copy.deepcopy(n1)
    

    四、函数

    1)背景

    在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:
    while True:
        if cpu利用率 > 90%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接
        
        if 硬盘使用空间 > 90%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接
        
        if 内存占用 > 80%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接
    
    函数式编程,if条件语句下的内容可以被提取出来公用,如下:
    def 发送邮件(内容)
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
        
    while True:
        
        if cpu利用率 > 90%:
            发送邮件('CPU报警')
        
        if 硬盘使用空间 > 90%:
            发送邮件('硬盘报警')
        
        if 内存占用 > 80%:
    
    对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,其实这就是函数式编程和面向过程编程的区别:
    • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
    • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”
    函数式编程最重要的是增强代码的重用性和可读性

    2)定义和使用

    def 函数名(参数):
           
        ...
        函数体
        ...
        返回值
    
    函数的定义主要有如下要点:
    • def:表示函数的关键字
    • 函数名:函数的名称,日后根据函数名调用函数
    • 函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
    • 参数:为函数体提供数据
    • 返回值:当函数执行完毕后,可以给调用者返回数据。
    001返回值

    函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。

    以上要点中,比较重要有参数和返回值
    def 发送短信():
           
        发送短信的代码...
       
        if 发送成功:
            return True
        else:
            return False
       
       
    while True:
           
        # 每次执行发送短信函数,都会将返回值自动赋值给result
        # 之后,可以根据result来写日志,或重发等操作
       
        result = 发送短信()
        if result == False:
            记录日志,短信发送失败...
    
    002参数
  • 普通参数:数量一致、一一对应(形参、实参)
  • def open_the_door(name):      #定义函数的时候,这个name这个值为形式参数,他没有一个固定的数值,用来代替下面调用的时候需要传入的参数
        return True if name == 'alex' else False
    
    ret = open_the_door('durand') #当调用函数的时候,需要传入一个参数与上面形参对应,如果有多个形参,也要传入对应个数的实参
    print('开门') if ret else print('不开')
    
  • 默认参数
  • def drive(age,name = 'alex'):   #如果传多个参数,且含默认参数,默认参必须数要放在后面
        tmp = name +' 坐飞机'
        return tmp
    
    ret = drive(29,'durand')  #如果传入name,将取代默认的alex
    ret1 = drive(19)   #这里只需要传入一个数值给age
    print(ret,ret1)
    
  • 动态参数:*args 、 **kwargs
  • def name(*a,**aa):      # **aa 必须放在*a后面
        print(a,type(a))    # *a为元组类型
        print(aa,type(aa))  # **aa 为字典类型
    
    name('alex','durand',name1='kevin',name2='Jin')
    
    def name(na,*a,**aa):      # 传值的时候会把第一个参数传给na,剩下的传给 *a 与 **aa
        print(na,type(na))
        print(a,type(a))    
        print(aa,type(aa))  
    
    name('alex','durand',name1='kevin',name2='Jin')
    
    def name(*args):
        print(args,type(args))
    
    li = ['alex','durand','kevin','Jin']
    name(li)  #  结果是 (['alex', 'durand', 'kevin', 'Jin'],) 
              #  把li当作一个整体传进去了
    
    name(*li) #  结果是 ('alex', 'durand', 'kevin', 'Jin') 
              #  传值的时候,加上*,则是把列表的每个元素传进去
    

    五、全局和局部变量

    NAME = 'alex'    #全局变量都用大写,可以被局部读取,不能修改,若修改需要使用global
    def name():
        name = 'kevin'   #局部变量都用小写,局部变量只能在局部被调用,出了这个函数就无法调用他
        print(name)
        global NAME
        NAME = 'Jin'   #如果没有使用global,这里创建的NAME 和全局的NAME是完全两个元素
        print(NAME)
    
    def name2():
        print(NAME)   #调用全局NAME,看是否被更改成功
    
    name()
    name2()
    

    评论

    此博客中的热门博文

    Skype 常用命令

    三星xpress M2070W 如何连接 WiFi

    Python - shutil 模块