手把手教你学python3第三讲
函数的定义
正确的定义
>>> def myfunction(a,b):
return a+b
>>> myfunction(1+7)
Traceback (most recent call last):
File "<pyshell#74>", line 1, in <module>
myfunction(1+7)
TypeError: myfunction() missing 1 required positional argument: 'b'
>>> myfunction(1,7)
8
注意调用的形式必须与小括号里一样。
>>> def a([c,b]):
SyntaxError: invalid syntax
看出参数不能为列表,元组,字符串的形式,只能为一个变量,这个变量可以是列表,元组,字符串类型。
>>> def a():
print(2)
return
print(10)
>>> a
<function a at 0x00000208CA0560D0>
>>> a()
2
调用函数必须加括号,并且遇到return就会返回,所以python只能有一个函数返回值(但是可以返回一个序列),而matlab可以有多个函数返回值。
>>> def a(b):
c=[ i**2 for i in b]
return c
>>> a([1,2,3])
[1, 4, 9]
>>> b
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
b
NameError: name 'b' is not defined
>>> c
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
c
NameError: name 'c' is not defined
下面介绍各种参数
实参argument和形参parameter和c语言里一样,上面的例子里[1,2,3]就是一个实参,而b就是一个形式参数,也就是说定义函数的时候是形参,调用时时实参。
>>> def a(b):
c=[ i**2 for i in b]
return c
>>> c=[1,2,3]
>>> a(c)
[1, 4, 9]
>>> b
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
b
NameError: name 'b' is not defined
>>>
实参完全可以和形参一样,形参是部分变量,在函数访问结束的时候已经不在堆栈里了。
然后介绍关键字参数,有的时候我们参数位置忘了,但是实参位置是很重要的,那么我们可以用关键字参数
>>> def s(a,b):
print(a ,'is', b)
>>> s('a','b')
a is b
>>> s('b','a')
b is a
>>> s(b='b',a='a')
a is b
关键字参数可以在调用函数时保证参数顺序的正确性。
下一个是默认参数,默认参数是在函数定义时就写入的
>>> def a(n=2):
return n**2
>>> a()
4
>>> a
<function a at 0x00000215997678C8>
>>> a(3)
9
有默认参数的话,有些参数不需要传递。
还有一种叫做收集参数,如果你不知道这个函数需要几个参数,可以用收集参数
>>> def a(*b):
return sum(b)
>>> a(1,2,3,4,5)
15
>>> def a(*b,c):
return sum(b)+c
>>> a(1,2,3)
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
a(1,2,3)
TypeError: a() missing 1 required keyword-only argument: 'c'
这种做法其实就是把b作为一个元组,把实参都打包进去。
如果既有收集参数,又有普通参数,建议把收集参数放在后面,不然很容易报错,解决方法一种就是把收集参数放在后面,还有一种就是写关键字参数,还有一种是设默认参数,默认参数不建议用
>>> def a(c,*b):
return sum(b)*c
>>> a(2,3,4)
14
>>> def a(*b,c):
return sum(b)*c
>>> a(1,2,3,c=2)
12
>>> def a(*b,c=2):
return sum(b)*c
>>> a(1,2,3,4)
20
>>> a(1,2,3,c=4)
24
可以看到最后的默认参数很可能就会出问题,4也是被打包进了b这个元组里面。
我们来说一下函数文档
>>> def a(*b,c=2):
'函数文档'
#求和
return sum(b)*c
>>> a.__doc__
'函数文档'
>>> help(a)
Help on function a in module __main__:
a(*b, c=2)
函数文档
函数文档是函数的一个属性,在这里面你可以解释函数的作用,为什么要有这个东西,比如说可能你们几个人合作开发一个东西,你想知道小鹿给你的这个函数是干嘛的,又没有办法看到函数的定义语句,也就是看不到#内容,这时候你就可以调用函数文档。上面给出了调用函数文档的两种方法。
下面给一些print的文档
这里要再说下一字符串拼接问题
>>> a='s'
>>> print('666'a)
SyntaxError: invalid syntax
>>> print('666' a)
SyntaxError: invalid syntax
>>> print('666',a)
666 s
>>> print('666'+a)
666s
>>> print('a''b')
ab
如果拼接的直接是字符串,可以没有逗号和加号,但是如果其中有变量加逗号会引入空格,+可以无缝拼接。
再补充一点,reversed()字符串,列表和元组的直接结果都是不等的,需要转换格式
>>> (1,2,3)==reversed((3,2,1))
False
>>> [1,2,3]==reversed([3,2,1])
False
>>> '123'==reversed('321')
False
>>>
>>> (3,2,1)==tuple(reversed((1,2,3)))
True
>>> [1,2,3]==list(reversed([3,2,1]))
True
>>> "123"==str(reversed("321"))
False
字符串是有点问题的,这点要注意
编程语言都有函数和过程
函数是有返回值的,过程是没有的,但是严格来说的话,python里都是函数,没有过程
def a():
print(1)
>>> b=a()
1
>>> b
>>> type(b)
<class 'NoneType'>
>>> print(b)
None
>>> len(b)
Traceback (most recent call last):
File "<pyshell#43>", line 1, in <module>
len(b)
TypeError: object of type 'NoneType' has no len()
>>> not b
True
>>>
我们可以看到即使没有return,python也会返回一个none,所以其实python都是有返回值的。
下面来说一下编程语言里都有的问题,局部变量local variable和全局变量global variable的区别
def a(b):
b=2
print('局部变量',b)
b=3
a(b)
print('全局',b)
局部变量 2
全局 3
我们看到打出来的结果。函数里的是局部变量,python如果遇到和全局变量一样的出现在函数里的变量会在设为局部变量,局部变量在函数调用完成后自动被python从堆栈里删除,不会改变全局变量的值。
下面呢是讲python里比较智能的地方
def a(b):
b=2
p(b)
print('局部变量a',b)
def p(b):
b=3
print("b",b)
a(1)
b 3
局部变量a 2
我看可以看到如果在函数没有定义和声明前调用是可以的,这与c语言不同,不然a()里怎么会打印2?而且我们还可以看到,在这个函数里定义的局部变量作用范围只限该函数
我们来再分析一道题
b='1'
def a():
global b
b='i'
return c(b)
def c(b):
b+='love'
d(b)
return b
def d(b):
b='you'
print(a())
为什么结果是'ilove'?首先我们先介绍global 是全局变量的意思,那么我们来看a函数global b表示a函数里的b都是全局的了,函数调用完也不会被删除,我们来看对不对
你们看到了吗?b还是'i',没有变的。a函数里return用到了c函数,我们去看函数c
b+='love'
b现在就是'ilove',下一步进到d函数,注意从c,d函数里的b都是局部变量,调用完函数就释放了存储空间了。
建议最好不用全局变量
危害
中间博主再来补充一个内容
我们看到count是可以对长度大于一的字符串使用也有正确结果。index值返回了索引最小的。
c语言函数不能嵌套定义,但是python可以
但是要调用一个内部函数必须先定义这个内部函数,和前面的同级函数调用不一样。
内部函数是没有办法直接调用的,对比下面两段代码,注意缩进
只有外部函数才能直接调用内部函数。
下面就要一下相对的全局和局部变量,什么意思呢?就是说,外部函数里的变量对于内部函数就相当于一个全局变量。在内部函数里直接用外部函数变量下面情形是错的。
在内部函数新定义了x,那么python就会把外部函数的参数屏蔽掉,下面就是可以的,因为没有新定义参数x
还可以加上关键字nonlocal
还可以用容器,也就是前面的列表,元组,它们不是在堆栈里存放的
下面介绍闭包,
闭包就是内部函数在外部作用域内并且调用了外部参数那么就是一个闭包,闭包是一种函数式编程,
python是面向对象的编程语言,不需要关心变量的类型,像上图里我们看到a(5)是一个函数类型,上图提供了两种访问内部函数b的方法。
下面介绍一个例子
有些同学可能会疑惑?这x怎么跟全局变量一样?不是每次调用都要初始化吗?其实因为b=a(),只要b这个标签没给别人,b这个函数名一直在这吊着,这个函数调用不能结束在函数名这里,这不是一个完整的调用,a()一直处于没有调用结束的状态。我们来试下
我们看到,b这个标签给了4之后a()才算调用结束。
对比
这个每一次调用都是完整的,不是半吊子的。