• Python基础语法快速复习-函数


    1、定义函数

    参数检查

    观察自己设置的绝对值函数(my_abs)和内置函数abs的报错区别:

    def my_abs(x):
        if x>=0:
            return x
        else:
            return -x
    
    my_abs('A')
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-1-3a70387458fd> in <module>
          5         return -x
          6 
    ----> 7 my_abs('A')
    
    
    <ipython-input-1-3a70387458fd> in my_abs(x)
          1 def my_abs(x):
    ----> 2     if x>=0:
          3         return x
          4     else:
          5         return -x
    
    
    TypeError: '>=' not supported between instances of 'str' and 'int'
    
    abs('A')
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-2-6eee3e7a739d> in <module>
    ----> 1 abs('A')
    
    
    TypeError: bad operand type for abs(): 'str'
    

    观察上方的报错信息,内置函数abs会检查参数错误而我们自己定义的函数不会,所以我们的函数定义不够完善。

    对my_abs的定义进行修改,只允许整数和浮点数类型的参数,进行数据类型的检查。

    isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。

    isinstance()语法规范:isinstance(object, classinfo)

    classinfo:可以是直接或间接类名、基本类型或者由它们组成的元组。

    #添加参数检查
    def my_abs(x):
        if not isinstance(x,(int,float)):
            raise TypeError('bad operand type')
        if x>=0:
            return x
        else:
            return -x
    my_abs('A')
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-3-f13543a1b7d8> in <module>
          7     else:
          8         return -x
    ----> 9 my_abs('A')
    
    
    <ipython-input-3-f13543a1b7d8> in my_abs(x)
          2 def my_abs(x):
          3     if not isinstance(x,(int,float)):
    ----> 4         raise TypeError('bad operand type')
          5     if x>=0:
          6         return x
    
    
    TypeError: bad operand type
    

    返回多个值

    import math
    
    def move(x,y,step,angle = 0):
        nx = x+step*math.cos(angle)
        ny = y-step*math.sin(angle)
        return nx,ny
    #import math语句表示导入math包,也就是导入相应sin和cos之类的数学函数
    
    x,y = move(100,100,60,math.pi/6)
    print(x,y)
    
    151.96152422706632 70.0
    

    其实这是一种返回多个值的假象,实际上python函数返回的是一个tuple,多个变量可以同时接收一个tuple,按位置赋给对应的值。

    练习

    定义一个函数quadratic(a,b,c),接收三个参数,返回一元二次方程image.png的两个解

    计算平方根调用math.sqrt()函数:

    import math
    
    def quadratic(a,b,c):
        d = b*b-4*a*c
        if d>=0:
            x1 = (-b+math.sqrt(d))/(2*a)
            x2 = (-b-math.sqrt(d))/(2*a)
            return x1,x2
        else:
            return '此方程无解'
    
    quadratic(1,2,1)
    
    (-1.0, -1.0)
    

    2、函数的参数

    定义函数接口的基本要求:确定参数的名字和位置即可。

    位置参数

    编写计算某数平方的函数

    def power(x):
        return x*x
    print(power(5))
    print(power(10))
    
    25
    100
    

    以上代码中,x为位置参数,调用函数必须传入对应个数的位置参数

    编写计算x^n的函数

    def power(x,n):
        s = 1
        while n > 0:
            n = n-1
            s = s * x
        return s
    print(power(5,2))
    print(power(5,3))
    
    25
    125
    

    传入位置参数时不仅要保证个数相同,还要保证和定义函数时候的顺序也相同(直接用函数名的话可以忽略顺序)

    默认参数

    给幂设置默认值

    def power(x,n=2):
        s = 1
        while n>0:
            n = n-1
            s = s*x
        return s
    print(power(5))
    print(power(5,2))
    
    25
    25
    

    设置默认参数的注意事项:

    (1)必选参数在前,默认参数在后。

    (2)当函数有多个参数时,把变化大的参数放在前面,变化小的参数放在后面(变化小的参数就可以作为默认参数)

    设置默认参数的好处:降低调用函数的难度。

    学生注册问题:来自相同的城市,拥有相同的年龄,只有名字和班级不一样。

    def enroll(name,gender,age=6,city='Beijing'):
        print('name',name)
        print('gender',gender)
        print('age',age)
        print('city',city)
    enroll('Sarah','F')
    
    name Sarah
    gender F
    age 6
    city Beijing
    

    定义默认函数时候的注意点:默认参数必须指向不变对象

    例如:如果默认参数指向一个列表,在运行函数时会将列表看作一个变量,改变列表的内容后下次调用函数列表的初始内容就会发生改变。

    可以使用None这种不变对象来设置默认参数值。

    def add_end(L = []):
        L.append('END')
        return L
    add_end()
    add_end()
    add_end()
    
    ['END', 'END', 'END']
    

    可变参数

    定义具有可变参数的函数,必须确定输入参数。

    可变参数在函数调用时自动组装成为一个tuple。

    定义可变参数比定义一个list或tuple参数相比,仅仅在参数前加了一个 * 号。在函数内部,可以传入任意个参数,包括0个参数。

    def calc(*numbers):
        sum = 0
        for n in numbers:
            sum = sum+n*n
        return sum
    print(calc(1,2))
    print(calc())
    
    5
    0
    

    关键字参数

    关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数被自动组装成一个dict。

    函数除了需要接受必须参数外,还可以接受关键字参数kw,传入关键字参数后会以字典的形式呈现出来

    def person(name,age,**kw):
        print('name:',name,'age:',age,'other:',kw)
    print(person('Michael',30))
    print(person('Bob',35,city='Beijing'))
    
    name: Michael age: 30 other: {}
    None
    name: Bob age: 35 other: {'city': 'Beijing'}
    None
    

    关键字参数可以扩展函数功能,接收到调用者提供的更多参数(例如必填项之外的选项)

    ** +字典名表示把字典内所有的key-value用关键字参数传入到函数 ** kw参数中,kw仅仅是dict的一份拷贝。

    命名关键字参数

    限制关键字参数的名字,需要用命名关键字参数,在参数之间加上特殊的分隔符 * 即可,分隔符后面的参数即为命名关键字参数。

    def person(name,age,*,city,job):
        print(name,age,city,job)
    
    person('Jack',24,city='Beijing',job='Engineer')
    
    Jack 24 Beijing Engineer
    

    如果函数定义中已经含有可变参数,那么不需要分隔符,只需要在可变函数后加上命名关键字参数即可。

    def person(name,age,*args,city,job):
        print(name,age,args,city,job)
    person('Jack',24,city = 'Beijing',job='Engineer')
    
    Jack 24 () Beijing Engineer
    

    函数参数的定义顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

    def f1(a, b, c=0, *args, **kw):
        print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
    
    def f2(a, b, c=0, *, d, **kw):
        print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
    
    f1(1, 2)
    
    a = 1 b = 2 c = 0 args = () kw = {}
    
    f1(1, 2, c=3)
    
    a = 1 b = 2 c = 3 args = () kw = {}
    
    f1(1, 2, 3, 'a', 'b')
    
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
    
    f1(1, 2, 3, 'a', 'b', x=99)
    
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
    
    f1(1, 2, 3, 'a', 'b', x=99)
    
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
    
    f2(1, 2, d=99, ext=None)
    
    a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
    

    3、递归函数

    求阶乘的函数 f(n) = n! = 1×2×3×⋅⋅⋅×(n−1)×n=(n−1)!×n=f(n−1)×n

    所以f(n)可以表示为n * f(n-1)

    def f(n):
        if n ==1:
            return 1
        return n*f(n-1)
    
    print(f(1))
    print(f(5))
    print(f(100))
    
    1
    120
    93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
    

    使用递归函数可能会导致栈溢出的问题(调用次数过多的时候)

    解决递归调用栈递归的方法是尾递归优化

    尾递归:在函数返回的时候调用自身本身,且return语句不能包括表达式,能够让递归函数只使用一个栈帧,不出现栈溢出。上面的f(n)在return语句中使用了乘法表达式,不能算作尾递归。

    def fact_iter(num,product):
        if num==1:
            return product
        return fact_iter(num-1,num*product)
    
    fact_iter(5,1)
    
    120
    

    上述为尾递归调用,大多数编程语言没有针对尾递归的优化,python也没有,所以即使将f(n)修改成尾递归方式也会导致栈溢出

  • 相关阅读:
    java:LeakFilling (SQL,JDBC)
    java:JQueryReview
    java:LeakFilling(JS,JQ)
    java:JQuery(声明,JQ和JS对象的区别,prop,attr,addClass,offset,trigger,dblclick和change事件,hide,show,toggle,slideUp,slideDown,slideToggle,三种选择器,标签的获取,三张图片的放大与缩小)
    java:JavaScript3(innerHTML,post和get,单选框,多选框,下拉列表值得获取,JS中的数组,JS中的正则)
    java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)
    java:javaScript(定义方式,循环语句,函数与参数,事件机制,控制台记录,event事件获取键盘ascii,confirm和prompt,事件和内置对象,获取input,点击更换背景色)
    java:Review(Oracle-HTML-CSS)
    java:CSS(定位,组合选择符,边距,Float,Table的样式,显示和隐藏,换行,盒子模型,iframe和frameset框架)
    java:HTML(table表格,ul列表)和CSS(导入.css文件,三种定义颜色方式,三种样式选择器,a标签属性顺序,)
  • 原文地址:https://www.cnblogs.com/MurasameLory-chenyulong/p/14529506.html
Copyright © 2020-2023  润新知