知识点1:深拷贝和浅拷贝
- 非拷贝(=赋值:数据完全共享,内存地址一样,修改一个另一个也变化)
- 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)像[[1,2],3,4]如果修改列表中列表[1,2]的值则会一起修改
- 深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)
知识点2:set集合
- 去重功能,集合本身无序、不重复,所以不能通过索引和键进行取值,集合对象是无序可哈希(不可改变)的值(也就是说对于set([[1,2],3,4])是不行的,因为列表里面中还包含了列表(可改变的值),所以会出现set失败)
- 空集合(set()),而{}是字典,集合分可变和不可变(frozenset),一般我们说的都是可变的,由于可变,所以set()本身就是不可哈希的,因此不能作为字典的key
- 创建集合:set("liu")就是{'l', 'i', 'u'}且类型为set,注意虽然是大括号但是不是字典类型
- 访问集合:由于集合本身的无序,所以不能使用索引、切片等访问,只能通过循环遍历访问或者in not in去判断是否是集合元素
- 集合添加元素:add方法和update,详情如下
-
s = set("liu") s.add("ta") #添加一个元素'ta' s.update("za") #添加两个元素,'z'和'a' s.update(["34","12"]) #添加两个元素'34'和'12' print(s)
结果:
{'ta', 'l', 'u', 'a', '12', 'z', 'i', '34'} - 集合元素删除:remove(元素)删除指定元素,pop()随机删除集合元素,s.clear()清空集合元素,剩下一个空集合,del s(删除集合,删除后s就不存在了)
- 集合类型操作:
s1 = {"a", "b", "c"} s2 = {"c", "d", "e"} # 交集 # 两个集合中的共有元素 print(s1 & s2) # {'c'} print(s1.intersection(s2)) # {'c'} # 并集(联合) print(s1 | s2) # {'e', 'd', 'b', 'a', 'c'} print(s1.union(s2)) # {'e', 'd', 'b', 'a', 'c'} # 差集 print(s1 - s2) # {'a', 'b'} print(s1.difference(s2)) # {'a', 'b'} # 反交集(对称差集) print(s1 ^ s2) # 两个集合中单独存在的数据 {'e', 'a', 'd', 'b'} print(s1.symmetric_difference(s2)) # 两个集合中单独存在的数据 {'e', 'a', 'd', 'b'} s1 = {"a", "b"} s2 = {"a", "b", "c"} # 子集 print(s1 < s2) # set1是set2的子集吗? True print(s1.issubset(s2)) # 超集(父级) print(s1 > s2) # set1是set2的超集吗? False,s2是s1的超集 print(s1.issuperset(s2))
知识点3:函数
- 必需参数(以正确的顺序传入函数。调用时的数量必须和声明时的一样。类似f(name, age),传入的时候这样f("liu", 18))
- 关键字参数(使用关键字参数允许函数调用时参数的顺序与声明时不一致。类似f(name, age),传入的时候这样f(age=18, name="liu"))
- 缺省参数(调用函数时,缺省参数的值如果没有传入,则被认为是默认值。类似f(name, age = 18),传入的时候这样f(name="liu"),而age为默认参数)
- 不定长参数(加了星号(*)的变量名会存放所有未命名的变量参数。而加(**)的变量名会存放命名的变量参数,*args会将参数存成元祖,**kwargs会将参数存放成字典)
1、总结四种参数位置优先级:必需参数和关键字参数放最左边,缺省(默认参数)第二位,不定长参数放第三位(**args放在左边,**kwargs参数放在右边)
2、函数注意点:
- 函数内没有return,默认返回None
- 如果return多个对象,python会自动帮我们将多个对象封装成元祖返回
- test(*args)中* 的作用其实就是把序列 args 中的每个元素,当作位置参数传进去。比如上面这个代码,如果 args 等于 (1,2,3) ,那么这个代码就等价于 test(1, 2, 3)
- test(**kwargs)中** 的作用则是把字典 kwargs 变成关键字参数传递。比如上面这个代码,如果 kwargs 等于 {'a':1,'b':2,'c':3} ,那这个代码就等价于 test(a=1,b=2,c=3)
3、python中的作用域分4种情况:
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:局部作用域>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,而nonlocal关键字是修改嵌套作用域(enclosing作用域,外层非全局作用域)
4、函数小结:
(1)变量查找顺序:LEGB,局部作用域>外层作用域>当前模块中的全局>python内置作用域;
(2)只有模块、类、及函数才能引入新作用域;
(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。
一个有趣的函数例子:
def outer(): def inner(): return 1 return inner #返回inner的内存地址 a = outer #将outer的内存地址赋值了给a print(a()) #相当于outer(),结果实际上是返回了inner的内存地址 print(a()()) #这里打印了结果1,因为执行了inner,所以返回了1
5、函数的递归
定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
其实函数的递归最典型的就是斐波那契数列(1、1、2、3、5、8.。。),下面是这个的例子
u'''斐波那契数列(1、1、2、3、5、8.。。)''' #第一种:循环方式实现 def feibo1(n): if n <= 1: return n first_num = 0 second_num = 1 for i in range(n-1): sum1 = first_num + second_num first_num = second_num second_num = sum1 return sum1 #第二种:递归方式实现 def feibo2(n): if n <= 1: return n return feibo2(n-1) + feibo2(n-2)
递归函数的优点: 是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
6、重要的内置函数:
1 filter(function, sequence) 对sequence中的item依次执行function(item),将执行结果为True的item做成一个filter object的迭代器返回。可以看作是过滤函数。
list1 = [1, 2, 3, 4] def fun(str1): if str1 != 3: return str1 result = filter(fun, list1) #主要是过滤作用,返回结果为True的值 print(list(result)) -->结果是[1, 2, 4]
2 map(function, sequence) 对sequence中的item依次执行function(item),将执行结果组成一个map object迭代器返回,当然map也支持多个sequence,这就要求function也支持相应数量的参数输入。
list1 = ["a", "b", "c"] def fun1(str): return str + "test" result1 = map(fun1, list1) #注意下面map和filter区别,如果没条件过滤,filter后还是返回本身 result2 = filter(fun1, list1) print(list(result1)) #结果是['atest', 'btest', 'ctest'] print(list(result2)) #结果是['a', 'b', 'c']
def add1(x,y): #多个sequence的情况 return x+y print (list(map(add1, range(10), range(10))))##[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
3 reduce(function, sequence, starting_value) 对sequence中的item顺序迭代调用function,如果有starting_value,还可以作为初始值调用.
from functools import reduce def fun1(x, y): return x*y result = reduce(fun1, range(1, 6)) # 通过reduce就直接实现了阶乘,注意下,这里reduce的结果就是一个值而不是迭代器 print(result)
4 lambda 匿名函数
像上面reduce实现的阶乘,这里通过匿名函数再实现,对比下两者:
from functools import reduce result = reduce(lambda x, y: x*y, range(1, 6)) #匿名函数的命名规则,用lamdba 关键字标识,冒号(:)左侧表示函数接收的参数(x,y) ,冒号(:)右侧表示函数的返回值(x*y) print(result)