python 函数(一)

预习:

  一  函数的返回值可以以元组的形式返回多个。

  补充一个小知识: 

  判断是否为元组的核心是逗号,即便是没有()包裹起来,它也是元组。明白这一点,就会有恍然大悟的感觉。

  例如: 

a=1,2
print(a,type(a))

  输出:

(1, 2) <class 'tuple'>

  

  所以,下面就比较容易理解了:

def plus(x,y):
    return x,x+y                 #看起来是两个返回值,本质上是一个元组,因为有个逗号,所有python会认为x,x+y 就是元组(x,x+y)。下面的结果就是理所当然
print(plus(1,2))

  等价于:

def plus(x,y):
    a=x,x+y                      #在这里,a就是一个元组。
    return a
print(plus(1,2))

  输出:

(1, 3)

  二  函数传参的时候注意可变类型与不可变类型。

  函数定义阶段读取的时候,函数变量会被一同读取。默认参数的值在定义阶段就确定了。函数体不被读取。

  传参的时候,一定要区分可变类型与不可变类型。两者会有本质的区别。  

  传的参数是不可变类型时:

name='hello'
def func(x):
    return x.replace('l','g')
result=func(name) print(result) print(name)

  输出:

heggo
hello

  会发现,传入的变量本身并没有变化。

 

  传的参数是可变类型时:

l=[1,2,3,4]
def func(x):
    x.append(5)
    return x
result=func(l)
print(result)
print(l)

  输出:

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

  去上面不可变类型不同的是,可变类型作为参数传入的时候,会被函数所影响,会发生变化。

 

  原因就在于,传参实际上是有这样一个过程。参数传进来的时候,会有一个赋值的过程。

name='hello'
def func(x):
    return x.replace('l','g')
result=func(name)
# name='hello'
# x=name
# x='hello'              #x,name在这个时候尽管都等于‘hello’,指向‘hello’在内存中的同一个地址。但是因为是不可变类型,所哟x.repalce()之后,x就会指向一个新的内存地址,表现出来x发生了变化。而name本身没有变化
print(result)
print(name)

  

l=[1,2,3,4]
def func(x):
    x.append(5)
    return x
result=func(l)
    # l=[1,2,3,4]      #x=l,实际上变量名x,变量名l,指向内存中同一个空间。列表是可变类型,对其的方法都会使其本身发生变化。
    # x=l
    # x=[1,2,3,4]
print(result)
print(l)

  

  三 关于 *与**

  作用:

  *与**在函数定义阶段(形参)起收集的作用,在函数调用阶段(实参)是打散分配的作用。*针对列或者元组格式,**针对是字典格式。

  *与**在形参位置:

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

def func(**kwargs):
    print(kwargs)
func(x=1,y=2)

  输出:

(1, 2, 3, 4)
{'x': 1, 'y': 2}

  

  *与**在形参位置  实参位置:

def func(*args):
    print(args)
a=(1,2,3,4)
func(*a)

d=dict(x=1,y=2)
def func(**kwargs):
    print(kwargs)
func(**d)

  输出:

(1, 2, 3, 4)
{'x': 1, 'y': 2}

  

 

  什么时候用呢,请看下面示例:

msg=dict(name='egon',age=88)                                                               #msg数据类型是字典
def func(**kwargs):                                                                        # 函数定义阶段(形参)
    print('{}老师已经{}岁了'.format(kwargs['name'],kwargs['age']))                           
func(**msg)                                                                                #函数调用阶段(实参)


def fun(kwargs):
    print('{}老师已经{}岁了'.format(kwargs['name'], kwargs['age']))                          #传的参数数据类型是字典是可以的
fun(msg)

  输出:

egon老师已经88岁了
egon老师已经88岁了

  func()定义和调用阶段都使用了*,fun()函数两处都没有用到,但得到了同样的效果。所以型号只在定义函数(允许使用不定数目的参数)或者调用(分割字典或者序列)时才有用。

  

  四 作用域(命名空间):namespace

  每个函数调用都会创建一个新的作用域。

  python的函数是可以嵌套的,也就是可以将一个函数放在另一个函数内部。

  举个例子:

def func1():
    def func2():
        print('hello world')
    func2()
func1()

  输出:

hello world

  

    由函数是可以嵌套的,可以引出一个很重要的概念——闭包函数。简单的来说,闭包函数是由两层函数构成,调用外层函数返回内层函数的地址,此时的内层函数并没有被调用。 之后再对内层函数传参加括号调用时,重点到了,内层函数除了自己本身的作用域可以访问,还可以访问它的定义所在的作用域。换句话说,内层函数是带着定义它的环境和(相关的自己局部变量)。

  函数存储子封闭作用域的行为叫做闭包。

  闭包函数是针对内层函数而说的,内层函数先天是是带着外层函数的作用域和它自己本身的作用域。

def func1(x):
    def func2(y):
        return x+y
    return func2
var=func1(2)
res=var(3)
print(res)

  输出:5

  

  想当然的直接调用func2,是会出现这种情况。

def func1(x):
    def func2(y):
        return x+y
    return func2
res=func2(3)           #这一行报错,因为向上找找不到func2这个函数,找不到定义它的语句。报错。
print(res)

  

 

  五 函数式编程

  把函数作为参数传入,这样的函数就称为高阶函数。而函数式编程就是指这种高度抽象的编程范式。

  在python2 与 python3 中会有不同:

  map():映射。

  在python2中:

>>> map(lambda x:x**2,[1,2,3,4,5])
[1, 4, 9, 16, 25]

  在python3中:

>>> map(lambda x:x**2,[1,2,3,4,5])
<map object at 0x000001D455A48A90>
>>> list(map(lambda x:x**2,[1,2,3,4,5]))
[1, 4, 9, 16, 25]

  

  filte():过滤

  在python2中:

>>> map(lambda x:x**2,[1,2,3,4,5])
[1, 4, 9, 16, 25]

 

  在python3中

>>> filter(lambda x:x%2==1,[1,2,3,4,5])
<filter object at 0x000001D455A48A58>
>>> list(filter(lambda x:x%2==1,[1,2,3,4,5]))
[1, 3, 5]

  reduce()

  在python2中:

>>> reduce(lambda x,y:x*y,[1,2,3,4])
24

  在Python3中:

>>> reduce(lambda x,y:x*y,[1,2,3,4])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'reduce' is not defined

  原因是讲reduce函数放在了functools 模块了,需要导入。

>>> from functools import reduce
>>> reduce(lambda x,y:x*y,[1,2,3,4])
24

  

  使用reduce可以实现这样一个功能。

  将[1,2,3,4,5,6,7,8]变成 12345678,列表内是整型,所以不能用join方法。

>>> reduce(lambda x,y:10*x+y,[1,2,3,4,5,6,7,8])
12345678

  完美!

  六 列表推导式

  可能和filter函数能实现一样的效果。  

>>> list(filter(lambda x:x%2==0,[1,2,3,4,5,6,7,8]))
[2, 4, 6, 8]
>>> seq=[1,2,3,4,5,6,7,8]
>>> [x for x in seq if x%2==0]
[2, 4, 6, 8]

  

 

posted @ 2017-08-27 14:15  骑者赶路  阅读(249)  评论(0编辑  收藏  举报