返回值&&作用域&&树
返回值
- 举例:
- 多条return语句
函数返回值总结:python函数使用return语句返回“返回值”所有函数都有返回值,如果没有return,隐式调用return Nonereturn语句并不一定是函数语句块的最后一条语句。例如条件分支一个函数可以存在多个return语句,但是只有一条可以被执行。如果没有一条return隐式返回None如果有必要,可以显示调用return,可以简写成return如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句不被执行作用:结束函数调用,返回return值
返回多值总结:函数不能同时返回多个值return [1,2,3]时指明返回一个列表,是一个列表对象return 1,3,4看似是返回多个值,隐式的被python封装成一个元组
函数嵌套
- 解释:在一个函数中定义了另一个函数
作用域***
- 概念:一个标识符的可见范围,这就是标识符的作用域,一般常说的是变量的作用域
- 全局作用域:
- 在整个程序运行环境中都可见
- 局部作用域:
- 在函数、类等内部可见
- 局部变量使用范围不能超过其所在的局部作用域
- 通过下面例子可以看出
- 外层变量作用域在内层作用域中可见
- 内层作用域inner中如果定义了o=97,相当于在当前作用域重新定义了一个新的o变量,但是这个o没有覆盖外层作用域中的o
- 全局变量global
- 使用golbal关键字变量,将foo内的x声明为使用外部的全局作用域中定义的x
- 全局作用域中必须有x的定义
- global作用范围,只在声明global的局部作用域和外部全局作用域中生效
- y在内部作用域为一个外部作用域的变量赋值,所以在golbal下面加上y = 1时,y+=1不会报错,注意这里的y的作用域还是全局的
global总结:x += 1这种特殊形式产生的错误原因,是因为先引用后赋值造成的。而python动态语言是赋值才算定义,才能被引用。解决办法:在这条语句之前加上x=0之类的赋值语句,或者使用global告诉内部作用域,去全局作用域查找变量定义。内部作用域使用x=5之类的赋值语句会重新定义局部作用域的变量x,但是一旦这个作用域中使用global声明x为全局的,那么x=5相当于为全局作用域的变量x赋值使用规则:不用global如果函数需要使用外部全局变量,请使用函数的形参传参解决
闭包
- 自由变量:未在本地作用域中定义的变量,例如定义在内部函数外的外层函数的作用域中的变量应用在函数嵌套中。随着外部函数的消亡,自由变量不会消亡以为在内层函数中还会调用
- 闭包:出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量就形成了闭包。很多语言都有这个概念例如javascript
- 代码解析:c[0] += 1,c在counter函数中定义过了,而且inc中的使用方式是为c的元素修改值,而不是重新定义变量。c=100不会生效因为inc中的c使用的是函数counter中的c而非外部全局变量。这种方法是python2中实现闭包的方式,python3中使用nonlocal关键字
[闭包应用于装饰器中]
- 概念:将变量标记为上级的局部作用域中定义,但不能是全局作用域中定义
- 上述代码解释:
- count 是外层函数的局部变量,被内部函数引用
- 内部函数使用nonlocal关键字声明count变量在上一级作用域中
- 举例一,代码可以正常使用,且形成闭包
- 举例二,不能正常运行,变量a不能在全局作用域中
- 例子三说明,函数地址并没有变,就是说函数这个对象没有变,调用它,他的属性__defaults__中使用元组保存所有默认值
- xyz默认值时引用类型,引用类型的元素变动,并不是元组的变化。
- 非引用类型举例:
- 属性__defaults__中使用元组保存所有默认值,它不会因为函数体内使用了它而发生变化
- 可变类型默认值,如果使用了默认值,就可以修改这个默认值
- 使用场景举例:
- 举例一:使用影子拷贝创建了一个新的对象,永远不能改变传入的参数
- 举例二:
- 通过值得判断就可以灵活的选择创建或者修改传入对象
- 很多函数的定义,都可以看到使用None这个不可变的值作为默认参数,广泛用法
函数销毁
- 全局函数销毁:
- 重新定义同名函数
- del语句删除函数对象
- 程序结束时
- 局部函数销毁:
- 重新在上级作用域定义同名函数
- del语句删除函数对象
- 上级作用域销毁时
树
- 非线性结构,每个元素可以有多个前驱和后继
- 树是n(n≥0)个元素的集合
- n = 0时,称为空树
- 树只有一个特殊的没有前驱的元素,称为树的跟Root
- 树中除了根节点外,其余元素只能有一个前驱,可以有0个或多个后继
- 递归定义:
- 树T是n(n≥0)个元素的集合,n=0时,称为空树
- 有且只有一个特殊元素根,剩余元素都可以被划分成m个互不相交的集合T1、T2、…Tm而每一个集合都是树,称为T的子树subtree
- 子树也有自己的根
- 结点:树中的数据元素
- 结点的度degree:结点拥有的子树的数目称为度,记作d(v)
- 叶子结点:结点的度为0,称为叶子结点leaf、终端结点、末端结点
- 分支结点:结点的度不为0,称为非终端结点或分支结点
- 分支:结点之间的关系
- 内部结点:除根结点外的分支结点,当然不包括叶子结点
- 树的度是树内各结点的度的最大值。D结点度最大为3,树的度数就是3
- 孩子结点:结点的子树的根结点称为该节点的孩子
- 双亲结点:一个结点是它各子树的根结点的双亲
- 兄弟结点:具有相同双亲的结点
- 祖先结点:从根结点到该节点所经分支上所有的结点ABD都是G的祖先结点
- 子孙结点:结点的所有子树上的结点都称为该结点的子孙,B的子孙是DGHI
- 结点的层次:根结点为第一层,依次往下推记做L(v)
- 树的深度(高度Depth):树的层次的最大值,如下图的树深度为4
- 堂兄弟:双亲在同一层的结点
- 有序树:结点的子树是有顺序的(兄弟有大小,有先后顺序),不能交换
- 无序数:结点的子树是无序的,可以交换
- 路径:树中的k个结点n1、n2、….nk,满足ni是n(i+1)的双亲,成为n1到nk的一条路径,就是一条线串下来的,前一个都是后一个的父结点
- 路径长度:路径上结点数-1,也是分支数
- 森林:m(m≥0)棵不相交的树的集合
- 对于结点而言,其子树的集合就是森林,A结点的2棵子树的集合就是森林
- 树的特点:
- 唯一的根
- 子树不想交
- 除了根以外,每个元素只能有一个前驱,可以有零个或多个后继
- 根结点没有双亲结点,叶子结点没有后继
- vi是vj的双亲,则(vi)=L(vj)-1,也就是说双亲比孩子结点的层级小1
二叉树
- 每个结点最多2棵子树
- 二叉树不存在度数大于2的结点
- 他是有序的树,左子树、右子树是有序的,不能交换次序
- 即使某个结点只有一颗子树,也要确定他是左子树还是右子树
- 二叉树的五种基本形态:
- 空二叉树
- 只有一个根结点
- 根结点只有左子树
- 根结点只有右子树
- 根结点有左右子树
- 斜树
- 左斜树,所有结点都只有左子树
- 右斜树,所有结点都只有右子树
- 一棵二叉树的所有分支结点都存在左右子树,并且所有叶子结点只存在在最下面一层
- 同样深度二叉树中,满二叉树结点最多
- k为深度(1≤k≤n),则结点总数为2^k-1
- 若二叉树的深度为k,二叉树的层数从1到k-1层的结点数都达到了最大个数,在第k层的所有结点都集中在最左边。这就是完全二叉树。
- 完全二叉树由满二叉树引出
- 满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树
- k为深度(1≤k≤n),则结点总数最大值为2^k-1,当达到最大值时就是满二叉树
- 完全二叉树,最下一层的叶子结点都是从左边连续的扩展
right:
- 在二叉树的第i层上至多有2^(i – 1)个结点(i≥1)
- 深度为k的二叉树,至多有2^k-1个结点(k≥1)
- 对任何一棵二叉树T,如果其叶子结点数为n0,度数为2的结点为n2,则有n0=n2+1
- 换句话说,就是叶子结点数-1就是度数为2的结点数
- 证明:
- 高度为k的二叉树,至少有k个个结点
- 含有n(n≥1)的结点的二叉树高度至多为n同上
- 含有n(n≥1)的结点的二叉树高度至多为n,最小为math.ceil(log2(n+1)),不小于对数值得最小整数,向上取整
- 假设高度为h,2^h-1=n => h = log2(n+1),层次数是取整。如果是8个结点,3.1699就要向上取整为4,为4层
- 具有n个结点的完全二叉树的深度为int(log2n)+1或者math.ceil(log2(n+1))
- 如果有一棵n个结点的完全二叉树深度为性质4,结点按照层序编号如下图
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/87922