Python之路-函数

一.函数是什么

  python中函数定义:函数是逻辑结构化和过程化的一种编程方法。定义函数的方法为:

def function():
""The function definitions""
    do  something
    return reselut
    
def:定义函数的关键字
function 函数名
()括号内可定义形参或者实参
""可描述函数功能,非必选
结构体:do somethin,完成某种功能
return:将函数结果返回

二.使用函数的好处

  1.减少代码重用

  2.保持一致性,易维护。相同功能可以使用同一个函数,功能发生改变时,直接修改函数即可

  3.扩展性更好

三.函数的参数(实参,形参,可选参数,默认参数)

1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

def test(a):  #a为形参,在函数结构体中起到占位的作用
    return a*a

test(1)  #1为实参

3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)

def test(a,b,c,d)
    print(a)
    print(b)
    print(c)
    print(d)

test(1,d=2,c=3,b=1)
'''
使用关键字传参,可不用注意参数的位置
'''

4.可选参数  *args  **kwargs(如果同时存在,**kwargs位置需要在*args后面)

*args以元组的形式传递多个参数

def fun(*args):
    print(args)
    print(type(args))
fun(1,2,3,4)

结果:
(1, 2, 3, 4)
<class 'tuple'>

**kwargs 以字典的形式传递多个参数,所以参数需要是

def fun(**kwargs):
    print(kwargs)
    print(type(kwargs))
fun(a=1,b=2,c=3,d=4)

输出结果:
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
<class 'dict'>

5.默认参数

  设置好默认参数,如果该形参参数无对应的实参,则使用默认参数

def fun(a='b'):
    print(a)

fun()
fun('a')

输出结果
b
a

四.局部变量和全局变量 

  在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

  全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
  当全局变量与局部变量同名时(为防止同名出现问题,全局变量全部用大写,局部变量用小写):
  在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
  
  在函数中,使用 global 关键字来定义全局变量,我们分情况来看下现象:
  1.没有global关键字,且未定义变量,则使用全局变量。
name=123
def fun():
    print(name)
fun()

输出结果:
123

  2.没有global关键字,则在函数中重新定义了变量,则函数内使用局部变量,全局变量保存不变

name=123
def fun():
    name=234
    print(name)
fun()
print(name)

输出结果:
234
123

  由此可知,函数没有global关键字时,对全局变量只有读的权限,没有重新赋值的权限。需要注意的是:当全局变量为可变数据类型(列表,字典)时,函数是可以进行列表内容的修改。由此可见得,函数无法为全局变量开辟新的内存空间,但是可以对其内存地址存储内容进行修改。

name=[1,2,3,4]
def fun():
    name.append(5)
    print(name)
fun()
print(name)

输出结果:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

  3.有global关键字,且重新定义了全局变量。则会修改全局变量。

name=123
def fun():
    global name
    name=234
    print(name)
fun()
print(name)

输出结果:
234
234

  我们要注意,不能在函数内,global前再定义变量,这样global无法区分你要申请的是全局变量还是 局部变量,会导致报错。

name=234
def fun():
    name = 123
    global name
    print(name)
fun()

报错信息:
SyntaxError: name 'name' is assigned to before global declaration

  4.有global关键字,则定义的变量在全局变量中不存在,则创建全局变量。  

def fun():
    global name
    name=234
    print(name)

def fun1():
    print('fun1',name)

fun()
fun1()

输出结果:
234
fun1 234

  当我们无论在内嵌多少层的函数中使用global时,他都会变为全局变量。在内存中,可理解为:

  

     global在此告一段落,接下来,介绍一下内嵌函数如何使用上层函数的变量。

   nonlocal 关键字,定义了内嵌函数使用上层函数的变量

name=234
def fun():
    name=1
    def fun1():
        nonlocal name
        print('fun1',name)
    fun1()
fun()

输出结果:
fun1 1

  如果我们在第一层函数上使用该关键字,则会报错。所以不能在第一层函数使用该关键字。

 
五.函数即变量
  函数和变量一样,可以将函数的内容或者结果赋值给新的变量名,通过调用变量名来进行调用函数内容。下面,通过一个简单的例子来看知悉函数的过程
def func():   #定义函数时,将函数内容以字符串形式保存在内存里
    print('test')
    return func

print('haha')  #第一步,执行打印命令
func()           #调用函数,将内存中存储的字符串当命令使用
a=func()      #将func的内存地址赋值给变量名a
a()              #通过a来调用函数func

打印结果:
haha
test
test
test

  函数调用前,都需要先将函数内容读取到内存中,再进行调用。和变量一样。我们定义变量时,会先将变量名和内容读取到内容中。当我们在调用变量名时,如果内存中午对应的值,则会报错。

错误示例:
print(name)
name='haha'

func()
def func():
    print('this is func')

  当我们执行函数时,只要函数内容已经存在内存中,则不分它存储的前后顺序。如下示例,虽然在定义函数时,func()调用func1时,func1并未定义,但是执行时func,func1都已经定义好了,故执行未报错。

def func():
    print('this is func')
    func1()

def func1():
    print('this is func1')

func()

输出结果:
this is func
this is func1

六.递归函数

  递归函数:在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身,则是递归函数。

 1 def calc(n):
 2     print(n)
 3     if int(n/2) ==0:
 4         return n
 5     return calc(int(n/2))
 6  
 7 calc(10)
 8  
 9 输出:
10 10
11 5
12 2
13 1

递归特性:

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

  由于递归函数的效率性不高,所以可以使用尾部调用来进行调优。即在函数的最后一步进行函数调用(最后一步不一定在最后一行)。这样就可以再调用函数完,即可释放内存。

函数的作用域

  函数变量的作用域取决去它所在的内存位置,而不是在代码中所调用的位置。例如:

def scope():
    scope_var='this is scope'
    def scope1():
        scope_var='this is scope1'
    scope1()
    print(scope_var)
    return scope1

var=scope()   #scope1

'''
虽然是在主程序中直接调用了scope1函数,但是scope_var='this is scope1'的作用域还是只在scope函数下的scope1函数中,
这是因为python在读取函数定义时,已经按照相应层级读取到内存中。在主程序的调用只是直接调用内存而已
'''

高阶函数

  满足俩个特性任意一个即为高阶函数

  1.函数的传入参数是一个函数名

  2.函数的返回值是一个函数名

  map函数

  map(func, *iterables) --> map object,处理序列中的每个元素,得到的结果是一个‘列表 ’,该‘列表’元素个数及位置与原来一样。map函数的原理如下:

def map_test(func,list_name):
    res=[]
    for i in list_name:
        res.append(func(i))
    return res

def add_one(n):
    return n*n
test=[1,2,3,4,5]
print(map_test(add_one,test))

   可以用lambda来处理对象 

print(list(map(lambda x:x+1,[1,2,3,4])))

  filter函数

  filter(function or None, iterable) --> filter object,遍历序列中的每个元素,判断每个元素的布尔值,如果为Ture,则留下该值。filter的原理如下 :

name=['sb1','sb2','3sb','xb']
def func(item):
    return not item.startswith('sb')

def filter_test(func,item):
    new_list=[]
    for i in  item:
        if func(i):
            new_list.append(i)
    return new_list

print(filter_test(func,nam

  可以用lambda来处理对象 

list(filter(lambda x:not x.startswith('sb'),name))

  reduce函数

  reduce(function, sequence[, initial]) -> value,reduce()处理一个序列,然后把序列进行合并操作。原理如下:

def func(res,i):
    return res+i
def reduce_test(func,seq,init=None):
    if  init == None:
        res=seq.pop(0)
    else:
        res=init
    for i in seq:
        res=func(res,i)
    return res
seq=[1,2,3,4,5,6,]
print(reduce_test(func,seq))

  用lambda来处理对象 

from functools import reduce
seq=[1,2,3,4,5,6,]
print(reduce(lambda  x,y:x+y,seq))

内置函数

#abs()
print(abs(-1)) #去绝对值

#all()
print(all([1,'',None])) #判断序列元素布尔值是否都为True,有一个为False,则返回False.空列表,空字符串等返回Ture
print(all(''))  #True
print(all(['']))  #False

#any
print(any([1,'',None])) #判断序列元素布尔值是否都为False,有一个为True,则返回True.空列表,空字符串等返回False
print(any(''))  #False
print(any([1,'',None]))  #True

#bin
bin(12) #将十进制转换为二进制

#bool()   判断bool值
print(bool(0))

#chr  根据序号找到acsii码表对应的字符
print(chr(97))

#ord  根据字符,找出对应的ascii码对应的序号
print(ord('a'))

#compile() 将source编译为代码或者AST对象。代码对象能够通过exec语句来执行或者eval()进行求值。 没什么用。忽略

#divmod(x, y) 返回元组(x//y, x%y),即返回商的整数和余数部分
print(divmod(3,2))
View Code
字典的运算:最小值,最大值,排序
salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'

可以取values,来比较
>>> max(salaries.values())
100000000
>>> min(salaries.values())
2000
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'



也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys()) 

先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, 'alex')


salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence



sorted(iterable,key=None,reverse=False)
View Code
原文地址:https://www.cnblogs.com/white-small/p/6854730.html