python全栈学习笔记(九)

 

基本数据类型---set

set集合,是一个无序且不重复的元素集合 

 

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
集合set方法

 

set的创建有两种方法,下面第一种可以创建空集合,第二种可以创建有元素的集合,虽然set和dict都是用大括号{}组成,但是我们创建空集合的时候不能这么创建:a = {} ,这样创建的是空字典,不是空集合。

#set两种创建方式
test = set()
test = {1,2,3,4,5}

也可以通过set方法接收别的数据类型(需要可以迭代的对象)来转换成集合,

test_list = [2,3,4,5,6]
test_set = set(test_list)
print(test_set)

 

 

下面介绍下set的常用方法

add方法,添加一个元素:

test_set = {2, 3, 4, 5, 6}
test_set.add(120)
print(test_set)

执行结果:

{2, 3, 4, 5, 6, 120}

clear方法,清空所有元素:

test_set = {2, 3, 4, 5, 6}
test_set.clear()
print(test_set)

执行结果:

set()

 

difference方法,找到test_set1中存在,test_set2不存在的集合,并且把它赋值给新变量。  这个方法改变的不是元集合,而是生成了新的集合。 

difference_update方法区别于difference的地方是,结果是更新自己,不是生成新的集合

test_set1 = {2, 3, 4, 5, 6}
test_set2 = {1,3,5}
test_set3 = test_set1.difference(test_set2)
test_set4 = test_set2.difference(test_set1)
print(test_set1)
print(test_set3)
print(test_set4)
print('###############')
test_set1.difference_update(test_set2)
print(test_set1)

执行结果:

{2, 3, 4, 5, 6}
{2, 4, 6}
{1}
###############
{2, 4, 6}

 

 discard方法和remove方法都是移除集合的元素,但是discard移除不存在的元素不会报错,remove方法则会。

test_set1 = {2, 3, 4, 5, 6}
test_set1.discard(2)
print(test_set1)
test_set1.remove(100)
print(test_set1)

执行结果:

{3, 4, 5, 6}
Traceback (most recent call last):
  File "C://untitled1/aa.py", line 9, in <module>
    test_set1.remove(100)
KeyError: 100

 

 intersection方法是取两个集合的交集,生成一个新集合

 

test_set1 = {2, 3, 4, 5, 6}
test_set2 = {1,3,5}
test_set3 = test_set1.intersection(test_set2)
print(test_set3)

 

执行结果:

{3, 5}

 

isdisjoint方法,判断两集合是否有交集,返回bool值,有交集为false,没有为true

test_set1 = {2, 3, 4, 5, 6}
test_set2 = {1,3,5}
print(test_set1.isdisjoint(test_set2))

执行结果:

False
 
issubset判断test_set1是不是test_set2的子序列
issuperset判断test_set1是不是test_set2的父序列
test_set1 = {2, 3, 4, 5, 6}
test_set2 = {3,5}
print(test_set1.issubset(test_set2))
print(test_set1.issuperset(test_set2))

执行结果:

False
True

 

pop方法,移除元素,移除的是最后一个元素,但是由于集合是无序的所以每次显示的集合顺序都会变,所以相当于随机移除一个元素

test_set1 = {2, 3, 4, 5, 6}
test_set1.pop()
print(test_set1)

执行结果:

{3, 4, 5, 6} 

 

三元运算(三目运算),是对简单的条件语句的缩写。

# 书写格式
 
result = 1 if 条件 else 2
 
# 如果条件成立,那么将 “值1” 赋值给result变量,否则,将“值2”赋值给result变量:
 
if  True:
    name = 'Tom'
else:
    name = 'Pitter'
#上面的if语句可以使用三元表达式:
result = 'Tom' if True else 'Pitter'
print(result)

执行结果:

Tom

 

   不同数据类型在内存中的存址方式
我们可以想象把内存分成一个一个的小格,每个小格代表一个内存地址,
当我们存list、tupple、dict、set这些数据的时候,是以链表的·方式存储的,情况如下:
我们的list = [11,22,33]
11,22,33这三个数字不会说正好存储在内存地址连续的地方,而且list这数据类型是可以修改的,我们也不知道要给新建的list预留多少空间,所以我们设计了成每个格子都知道自己的上一个格子和下一个格子的位置
在python里是这样设计的。但是有些语言有数组 这种数据类型,数组定义以后是不能修改的,所以可以占用连续的内存地址
 
 
相比于list这种数据类型,string 的存储方式就不同了,比如:name = "alex"
这个name字符串在定义以后就不能改变的,占用了连续的内存地址,如果我们想把alex改成abex,在内存中是不能直接把  l   改成  b 的。
我们平时使用方法修改str,实际上在不是在它原有本身修改的,而是在新的内存地址创建新的值
 
结论:对于str来说,是一次被创建的,不能被修改,只要修改就是再创建
对于可以被修改的(可以被append),它就相当于C里面的链表,可以记住上一个元素的size,和下一个元素的size
 

深浅拷贝

使用拷贝需要先导入copy模块:

import copy

一、数字和字符串
n1 = {'k1':'wu',}

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

import 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", 456]}
  
n2 = n1

 

2、浅拷贝

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

import copy
  
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
  
n3 = copy.copy(n1)

3、深拷贝

深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)

import copy
  
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
  
n4 = copy.deepcopy(n1)

 

在深拷贝中,最后一层的内存地址是一样的,python内部对字符串和数字的优化:

import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n2 = copy.deepcopy(n1)
print(id(n1['k3'][0]))
print(id(n2['k3'][0]))

执行结果:

11491904
11491904

很明显,最后一层是一样的。

 

函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

最重要的是增强代码的重用性和可读性

函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

定义一个函数

你可以定义一个由自己想要功能的函数,以下是简单的规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()
  • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

 

定义的函数里面只要执行return 语句,下面的代码就不执行了。

def 函数名(形参):

    函数主体

    return 

我们调用函数时是:函数名(实参)

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

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

普通参数:

def name(n):
    print(n)
name('laoni')

 

默认参数,我们调用函数时可以不给默认参数传参,当默认参数和非默认参数同时存在时,要把默认参数放后面,否则语法上回报错:

def name(n='laoni'):
print(n)
name()
name('Pitter')

执行结果:

laoni
Pitter

 

动态参数有两种,第一种在参数前加上*号,表示传多少个参数都能,传进去的实参,type是tupple

def name(*n):
    print(n,type(n))

name(1,2,3,4,5,[6,7,8],{'num':9})

执行结果:

(1, 2, 3, 4, 5, [6, 7, 8], {'num': 9}) <class 'tuple'>

如果我想在执行函数的时候,实参直接是个tupple,需要这样调用:

def name(*n):
    print(n,type(n))
info = (1,2,3,4,5,[6,7,8],{'num':9})
name(*info)

执行结果:

(1, 2, 3, 4, 5, [6, 7, 8], {'num': 9}) <class 'tuple'>

上面的例子在调用函数f1时,传的实参里没有加* 的话,会把li看成一个整体,作为tupple的一个元素存在,而加了*号的话,会把li里的每个元素看做tupple的一个个元素

 

第二种动态参数:
在形参前面加上两** 号,这种动态参数传的实参需要以key = value 的方式传参,type类型是dict
def name(**n):
    print(n,type(n))
name(Tom=11,Tim=22)

执行结果:

{'Tim': 22, 'Tom': 11} <class 'dict'>

 

同上面一样,如果形参是**的时候,传参的是dict也需要写成**dict,不填会报错,因为python会把整个dict看成一个整体,所有**kwargs这种动态参数,传参的时候,要不是**dict,要不就写成key=value

def name(**n):
    print(n,type(n))

info = {'Tom':11,'Cat':22,'Dog':33}
name(**info)

执行结果:

{'Cat': 22, 'Dog': 33, 'Tom': 11} <class 'dict'>

 

两种动态参数同时使用的情况,注意:一个*号的要放在两个**号的前面,不然会报错

def name(*n,**m):

    print(n,type(n))
    print(m, type(m))

info_tupple = (11,22,33,44,55)
info_dict = {'Tom':11,'Cat':22,'Dog':33}
name(*info_tupple,**info_dict)

执行结果:

(11, 22, 33, 44, 55) <class 'tuple'>
{'Tom': 11, 'Dog': 33, 'Cat': 22} <class 'dict'>

 

函数可以有默认参数(有默认值的参数一定要放在参数的尾部)

 一般情况下,我们定义动态参数名称是这样写的:

def name(*args,**kwargs)

 

 全局变量和局部变量:

 

 

一般情况下,在函数内部是可以调用全局变量的,但是不能修改全局变量
如果想在函数内定义全局变量,需要使用到关键字 global,而且这种方式需要先定义,再赋值。
建议定义全局变量全是大写字母,小写全是小写。

 

 

posted @ 2016-05-29 05:51  爬行的龟  阅读(122)  评论(0)    收藏  举报
如有错误,欢迎指正 邮箱656521736@qq.com