********以下笔记参考廖雪峰老师的Python教程

1. Python内置函数调用(如)

求绝对值:abs()

求最大值:max()

数据类型转换:int()


函数名是指向一个函数对象的引用,把函数名赋给一个变量相当于给这个函数起别名。


2. 函数定义:

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

import math
def quadratic(a,b,c):
    t=math.sqrt(b**2-4*a*c)
    x1=(-b+t)/(2*a)
    x2=(-b-t)/(2*a)
    return x1,x2

print(quadratic(2, 3, 1))



这是我自己写的廖老师该章节的练习,对比其他同学的答案发现很不严密:1.没有考虑非法值的判断;2.没有考虑(b^2-4ac)是否大于0

另外在写代码中,发现:1. Python中幂的表示 x**y;2. *不可省略


以下是重写代码:

注:raise显示错误:

当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。

import math
def quadratic(a,b,c):
    if not isinstance(a, (int,float)): 
        raise TypeError('bad oprand type')
    if not isinstance(b, (int,float)):
        raise TypeError('bad oprand type')
    if not isinstance(c, (int,float)):
        raise TypeError('bad oprand type')
    if a==0:
        return('非一元二次方程')
    t=b**2-4*a*c
    if t>0:
        t=math.sqrt(t)
        x1=(-b+t)/(2*a)
        x2=(-b-t)/(2*a)
        return('方程有两个根',x1,x2)
    elif t==0:
        x=-b/(2*a)
        return('方程有一个跟',x)
    elif t<0:
        return('无解')
------------------------------------
print(quadratic(2, 3, 1))
print(quadratic(1, 3, -4))
print(quadratic(1, 1, 1))
print(quadratic(0, 1, 1))



输出结果为:

('方程有两个根', -0.5, -1.0)
('方程有两个根', 1.0, -4.0)
无解
非一元二次方程



函数体内部的语句在执行时,一旦执行到return,函数就执行完毕,并将结果返回。

如果没有return语句,函数执行完毕后会自动返回None;return None可以简写为return。


注:Python函数中print()和return()的区别:

这两个看起来输出结果一样,但是内涵是完全不一样的
return的作用之一是返回计算的值
print的作用是输出数据到控制端

def add (x, y):
	z = x + y
	return/print z



如此段代码中,如果是return z,则返回了z,如果不在之后print z 的话则没有输出

如果是print z,则该函数没有return,默认返回值是None,会多出一个空值,但会直接输出z的值


3. 定义函数调用,如需要调用abstest.py中的quadratic函数,应写为:

from abstest import quadratic
print(quadratic(0, 1, 1))



4. 空函数:

def  nop():
	pass



5. Python函数返回值:

python函数可以返回多个值,但这是个假象,Python返回的多个值其实是一个tuple,所以Python函数返回的仍然是个单一值


6. 函数的参数:

① 位置参数:

调用函数的时候,传递的参数都是根据位置来跟函数定义里的参数表匹配的,比如funcB(100, 99)和funcB(99, 100)的执行结果是不一样的。

对于func(x)函数,参数x就是一个位置参数。


② 关键字参数:(个人感觉廖老师这部分解释较为复杂,建议参见该blog)

http://www.iplaypython.com/jinjie/jj130.html

目的:在程序比较繁琐的时候,参数顺序是很难能记住的,为了让程序简单不出错,会为参数起一个名字,这就是关键字参数的作用;另外,可以为关键字参数设置默认值。


③ 默认参数:

func(x,y=2)

把参数y的默认值设定为2,此时,调用func(5)时,相当于调用func(5,2)

如果需要改变y的值,则可直接传入(5,3)

注:设定参数时:1) 必选参数在前,默认参数在后;2) 变化大的参数放在前面,变化小的参数放在后面。


默认参数易错点:

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

>>>add_end()调用默认参数,输出['END'],再次调用时结果为['END','END']


原因:

Python函数在定义的时候,默认参数的L的值被定义为[],因为默认参数L也是一个变量,它指向[],每次调用该函数,如果改变了L 的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时候的L了。

传入参数[1,2,3]时,接下来的代码都是针对[1,2,3],和L=[]没有关系。当没有传入参数时,之后的代码针对L的默认值[]进行修改。


默认参数必须指向不变对象!


④ 可变参数:

1)可变参数:*list

目的:传入不确定个数的参数。

其他方法:可通过构建一个list或tuple传入不确定个数的参数。如:func([1,2,3,4,5])

,如:

def func(names)
for name in names:
print(name)

传值时,需要先构建list,func(['Zhangsan','Lisi','Wangwu'])



可变参数:在参数前加*,如:

def func(*names)
for name in names:
print(name)

可以直接传:func(‘Zhangsan’,'Lisi','Wangwu');在函数内部,参数names收到的是一个tuple


2)关键字参数**kw

传入dict的key值,常用**kw表示

和可变函数的区别:可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。


a. 判断关键字参数:

def persons(name,age,**kw)
	if 'city' in kw
		pass
	if 'job' in kw
		pass



b. 命名关键字参数(即只接收指定的关键字作为关键字参数)

如:只接收city和job作为关键字参数

def persons(name,age,*,city,job):
    print(name,age,city,job)

*后面的参数被视为命名关键字参数。

命名关键字参数必须传入参数名。

如果函数定义中已经有一个可变参数,后面跟着的命名关键字参数不需要单独出一个*了


⑤ 参数组合:

5种参数定义的顺序必须是:必选参数(位置参数)、默认参数、可变参数、命名关键字参数和关键字参数。

如:

def f1(a,b,c=0,*args,**kw):
	print('a=',a,'b'=,b,'c=',c,'args=',args,'kw=',kw)


输入:
args=(1,2,3,4)
kw={'d':99,'x':'#'}
f1(*args,**kw)

输出:
a=1,b=2,c=3,args=(4,),kw={'d':99,'x':'#'}



7. 递归函数:在一个函数内调用自身本身。

如:fact=n!

即:fact(n)=n*fact(n-1),当n=1时特殊处理

def fact(n):
    if n==1:
        return 1
    return n*fact(n-1)

print(fact(5))



个人理解相当于利用递推公式和截止条件计算。(不用人脑算通项公式了哈哈哈)

使用递归函数需要防止栈溢出。




④ 关键字参数:

目的:在程序比较繁琐的时候,参数顺序是很难能记住的,为了让程序简单不出错,会为参数起一个名字,这就是关键字参数的作用。