Python3 函数

1.定义函数

  函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。

  任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

  函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

  函数内容以冒号起始,并且缩进。

  return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

  可以返回多个值,其实就是一个tuple。

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

  空函数:如果想定义一个什么事也不做的空函数,可以用来占位,可以用pass语句:

def nop():
    pass

2.参数传递 

  可更改(mutable)与不可更改(immutable)对象
  在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

  不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。

  可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

  python 函数的参数传递:

  不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。

  可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

  python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

3.参数

  调用函数时可使用的正式参数类型:必需参数,关键字参数,默认参数,不定长参数等,参数类型也可以组合。

  a. 必须参数,也叫位置参数

  必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

  b.关键字参数

  关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。

  使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

def printinfo( name, age ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="runoob" )

  c.默认参数

  调用函数时,如果没有传递参数,则会使用默认参数。默认参数要放在最后。默认参数必须指向不可变对象。

def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )

  d.不定长参数,可变参数,收集参数

  需要一个函数能处理比当初声明时更多的参数。

  加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。

  果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。

  如果* 后,还有参数,参数必须用关键字传入。

  加了两个星号 ** 的参数会以字典的形式导入。允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return
 
# 调用printinfo 函数
printinfo( 10 )
printinfo( 70, 60, 50 )

>>> nums = [1, 2, 3]
>>> calc(*nums)
14

def fun(**kwargs):
for x, y in kwargs.items():
print(x,y)

fun(city = "asdasd",beijing = "sadasdw")

4.匿名函数

  python 使用 lambda 来创建匿名函数。

  所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  lambda 只是一个表达式,函数体比 def 简单很多。
  lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

sum = lambda arg1, arg2: arg1 + arg2

  请参考:https://www.cnblogs.com/kaishirenshi/p/8611358.html

  two_sum = (lambda x, y: x + y)(34)

  匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

   也可以把匿名函数作为返回值返回,

def build(x, y):
    return lambda: x * x + y * y

5.高阶函数

  一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

def add(x, y, f):
    return f(x) + f(y)

def zheng(n):
    if n > 0:
        return n
    else:
        return -n

x = -5
y = 10
f = zheng  #变量指向函数,函数名就是变量
print(add(x, y, f))

5.1 map()reduce()函数

map()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

>>> def f(x):
...     return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> from functools import reduce
>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

  作业:

  利用mapreduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456

  摘选了一个答案:

def str2float(str):

    d = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
         '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

    def s2n(s):
        return d[s]

    def fn(a, b):
        return reduce(lambda x, y: x * 10 + y, map(s2n, a)) + reduce(lambda x, y: x * 10 + y, map(s2n, b)) * (10 ** -len(b))

    theS = str.split('.')

    return fn(theS[0], theS[1])

 5.2 filter

Python内建的filter()函数用于过滤序列。

map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]

用filter求素数

def _odd_iter():  #构造一个从3开始的奇数序列,这是一个生成器,并且是一个无限序列。
    n = 1
    while True:
        n = n + 2
        yield n
def _not_divisible(n): #定义一个筛选函数 return lambda x: x % n > 0
def primes(): #定义一个生成器,不断返回下一个素数 yield 2 it = _odd_iter() # 初始序列 while True: n = next(it) # 返回序列的第一个数 #每次循环,it会改变,n取新序列的第一个数。 yield n it = filter(_not_divisible(n), it) # 构造新序列 #循环一次,就将n及n倍数的值去掉返回新的Iterator
#将lambda函数写在filter中,筛选有问题,没搞懂是怎么回事,应该是闭包的问题。
# 打印1000以内的素数: for n in primes(): if n < 1000: print(n) else: break

5.3 stored

sorted()函数也是一个高阶函数,可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

 先将序列输入key函数,获取新序列,然后再排序。

>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)  #反向排序
['Zoo', 'Credit', 'bob', 'about']

key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

序列中的元素是一个个传入key函数,再返回一个新序列。

max,min

salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 需求1:找出薪资最高的那个人=》lili
# res=max([3,200,11,300,399])
# print(res)

# res=max(salaries)
# print(res)


salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 迭代出的内容    比较的值
# 'siry'         3000
# 'tom'          7000
# 'lili'         10000
# 'jack'         2000

# def func(k):
#     return salaries[k]

# ========================max的应用
# res=max(salaries,key=func) # 返回值=func('siry')
# print(res)

# res=max(salaries,key=lambda k:salaries[k])
# print(res)

# ========================min的应用
# res=min(salaries,key=lambda k:salaries[k])
# print(res)

5.4 函数作为返回值

  闭包

  https://blog.csdn.net/qq_37616069/article/details/79646905

  在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包

  函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包

  #形成闭包的条件
    #1、必须要有一个内嵌函数
    #2、内嵌函数中要对外层函数变量的引用
    #3、外部函数必须返回内嵌函数

 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

 5.5 装饰器

  可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件或者帮助输出,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)

  要先理解闭包。

    def outer(func):  # 装饰函数
        def inner():
            print("认证成功!")
            result = func()
            print("日志添加成功")
            return result
        return inner

    @outer
    def f1():  # 被装饰函数
        print("业务部门1数据接口......")

  a.程序开始运行,从上到下开始解释。读到def outer(func)时,发现这是一个函数的定义,将其函数体放入内存中,然后跳过。

  b.跳到@outer时,程序被@这个python语法糖吸引住,知道这是个装饰器,按规矩要立即执行,于是程序开始运行@后面那个名字outer所定义的函数。

  c.程序返回到outer函数,开始执行装饰器的语法规则。规则是:被装饰函数的名字会被当作函数形参传递给装饰函数。装饰函数执行它自己内部的代码后,会将它的返回值赋值给被装饰函数。原来f1函数被当作参数传递给了func,而f1这个函数名之后会指向inner函数。 注意:@outer和outer()是有区别的。没有括号时,outer函数会被立即执行。这个与传统的用括号才能调用函数不同。

  d.程序开始执行outer函数内部的内容,一开始它又碰到了一个函数inner,inner函数定义块被程序观察到后不会立刻执行,而是读入内存中(这是默认规则)。

  e.再往下,碰到return inner,返回值是个函数名,并且这个函数名会被赋值给f1这个被装饰函数,也就是f1 = inner。此时,f1函数被新的函数inner覆盖了(实际上是f1这个函数名更改成指向inner这个函数名指向的函数体内存地址,f1不再指向它原来的函数体的内存地址),再往后调用f1的时候将执行inner函数内的代码,而不是先前的函数体。那么先前的函数体去哪了?还记得我们将f1当做参数传递给func这个形参么?func这个变量保存了老的函数在内存中的地址,通过它就可以执行老的函数体,你能在inner函数里看到result = func()这句代码,它就是这么干的!

  f.接下来,还没有结束。当业务部门,依然通过f1()的方式调用f1函数时,执行的就不再是旧的f1函数的代码,而是inner函数的代码。在本例中,它首先会打印个“认证成功”的提示,很显然你可以换成任意的代码,这只是个示例;然后,它会执行func函数并将返回值赋值给变量result,这个func函数就是旧的f1函数;接着,它又打印了“日志添加成功”的提示,这也只是个示例,可以换成任何你想要的;最后返回result这个变量。我们在业务部门的代码上可以用r = f1()的方式接收result的值。

  g.以上流程走完后,你应该看出来了,在没有对业务部门的代码和接口调用方式做任何修改的同时,也没有对基础平台部原有的代码做内部修改,仅仅是添加了一个装饰函数,就实现了我们的需求,在函数调用前进行认证,调用后写入日志。这就是装饰器的最大作用。

  f1._name_    输出inner。Python内置functools.wraps(),可以解决它们的__name__已经从原来的'f1'变成了'inner'的问题

import functools

def log(text):    ###now = log('execute')(now)
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
@log('execute') ###decorator本身需要传入参数
def now():
    print('2015-3-25')
#带参数
def outer(func):
    def inner(*args, *kwargs):
        print("认证成功")
        result = func(*args, **kwargs)
        print("日志添加成功")
        return result
    return inner
@outer
def f1(name, age):
    print("{}正在调用业务部门1的数据接口".format(name))
# 调用方法
f1("jack", 19)
#有多个装饰器
def outer1(func):
    def inner(*args,**kwargs):
        print("认证成功!")
        result = func(*args,**kwargs)
        print("日志添加成功")
        return result
    return inner


def outer2(func):
    def inner(*args,**kwargs):
        print("一条欢迎信息。。。")
        result = func(*args,**kwargs)
        print("一条欢送信息。。。")
        return result
    return inner


@outer1
@outer2
def f1(name,age):
    print("%s 正在连接业务部门1数据接口......"%name)

# 调用方法
f1("jack",18)
###装饰器中形参是函数   
 # 认证函数
    def  auth(request,kargs):
        print("认证成功!")
        
    # 日志函数
    def log(request,kargs):
        print("日志添加成功")
        
    # 装饰器函数。接收两个参数,这两个参数应该是某个函数的名字。
    def Filter(auth_func,log_func):
        # 第一层封装,f1函数实际上被传递给了main_fuc这个参数
        def outer(main_func):
            # 第二层封装,auth和log函数的参数值被传递到了这里
            def wrapper(request,kargs):
                # 下面代码的判断逻辑不重要,重要的是参数的引用和返回值
                before_result = auth(request,kargs)
                if(before_result != None):
                    return before_result;
    
                main_result = main_func(request,kargs)
                if(main_result != None):
                    return main_result;
    
                after_result = log(request,kargs)
                if(after_result != None):
                    return after_result;
            return wrapper
        return outer
    # 注意了,这里的装饰器函数有参数哦,它的意思是先执行filter函数。然后将filter函数的返回值作为装饰器函数的名字返回到这里。所以,Filter(auth,log) = outer , @Filter(auth,log) =  @outer
    @Filter(auth,log)
    def f1(name,age):
        print("%s 正在连接业务部门1数据接口......"%name)
    
    # 调用方法
    f1("jack",18)

 5.6 偏函数

  functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数。

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

固定参数,返回新的函数。

 参考:菜鸟教程和廖雪峰Python3

 https://www.jianshu.com/p/affeb6acf1c9

原文地址:https://www.cnblogs.com/yunlong-study/p/12555954.html