暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

python基础(三)

牛谈琴 2021-01-16
196

1函数简介

在程序中,如果发现某个功能的代码要多次使用,就把该代码块组织为一个模块,这一模块就是函数。我们可以举一个简单的例子进行说明:比如说,我们要计算圆的面积公式:S = ∏*r*r

r1 = 12.34
r2 = 9.08
r3 = 73.1
s1 = 3.14 * r1 * r1
s2 = 3.14 * r2 * r2
s3 = 3.14 * r3 * r3

所以有函数以后,我们就不需要写的那么麻烦只需要写一个函数进行调用即可。

2函数的定义和调用

函数定义如下:

def 函数名():  #括号里面的参数在后面的章节会重点讨论
 代码(代码有缩进)
#定义函数,完成信息的打印功能
def printInfo():
 print('***')
 print('数据分析')
 print('***')

定义函数后,相当于完成了某个功能的代码,想要代码执行,只需要调用即可。函数的调用如下:

printInfo()

****
数据分析
***

3函数的参数

在python中函数的定义非常简单,由于函数参数的存在,函数变的非常灵活,不但使得函数能够处理复杂多变的参数,而且还能简化参数的调用。Python中的函数参数有如下几种:位置参数  默认参数可变参数  关键字参数

3.1位置参数

计算x的平方的函数

def power(x):
 return x * x

对于power(x)
函数,参数x就是一个位置参数,也叫必填参数。当我们调用power
函数时,必须传入有且仅有一个参数x:重新写入为:

def power(x):
 return x *x
print(power(5))

25

如果要是计算x的三次方或者更高次方,可以另外定义:

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

print(power(5,2))
print(power(5,3))

25
125

3.2默认参数

默认参数是指其中一个参数是固定的,我们并不需要全部输入,只需要输入其中的一个即可。但是默认参数一般放在函数参数的后面。

def power(x,n = 2):
 s = 1
 whlile n > 0:
  n = n - 1
  s = s * x
 return s

25
25

使用默认参数可以简化书写

def enroll(name,gender):
 print("name:",name)
 print("gender:",gender)

这样我们设置好了一个函数,接下来我们需要调用函数:

enroll('Sarah','F')

name: Sarach
gender: F

如果想传入年龄城市等相关信息,需要继续调用函数,会显得较为复杂。因而我们会设定一些默认参数。

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

有了默认参数这个选项,我们就不需要再输入城市、年龄的相关信息了。

name: Sarch
gender: F
age: 6
city: beijing

只有与 默认参数信息 不符合的才需要重新输入:

enroll('Bob','M',7)
enroll('Adam','M',city = 'Tianjing')

name: Bob
gender: M
age: 7
city: beijing
name: Adma
gender: M
age: 6
city: Tianjing

默认有一个地方需要注意

def add_end(L=[]):
 L.append('END')
 return
print(add_end([1,2,3]))
print(add_end(['x','y','z']))

[123'END']
['x''y''z''END']

但是如果使用默认参数调用时,一开始结果是对的,但是再次调用的时候就出现了错误。

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

['END']
['END''END']
['END''END''END']

python函数在定义的时候,默认参数L
的值被计算出来了,即[]
,默认参数L
也是一个变量,它指向对象[],每次调用该函数,如果改变了L
的内容,下次调用的时候,默认参数的内容就变了,不再是函数定义的[]
了。所以定义默认参数要牢记一点:默认参数必须指向不变对象!所以我们修改上面的例子

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

['END']
['END']
['END']

不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,因此同时读取不会出现问题。

3.3可变参数

可变参数顾名思义就是定义的参数是可变的,可变参数就是传入的参数个数是可变的 可以是1个、2个到任意个,还可以是0个。如果我们要计算a的平方一直加到无穷,所以我们需要确定输入的参数,由于参数个数不确定,所以我们可以将a,b,c...作为一个list
tuple
传进来,我们可以定义函数如下:

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

14

如果是利用可变参数那么问题就会简单很多,

calc(1,2,3)
calc(1,3,5,7)

将函数调成可变参数如下:

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

14
35

如果已经有了一个list
或者tuple
,需要调用可变参数就只需要在调用的地方添加即可。例如:

num = [1,2,3]
calc(*num)

14

3.4 命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于传入哪些,就需要在函数内部通过kw
检查 我们以person
为例:

def person(name,age,**kw):
 if 'city' in kw:
  pass
 if 'job' in kw:
  pass
print('name:',name,'age:',age,'other:',kw)
person('jack',24,city = 'Beijing',addr = 'chaoyang',zipcode = 123456)

输出结果为:

name: jack age: 24 other: {'city''Beijing''addr''chaoyang''zipcode'123456}

所以我们可以看出,后面不在的参数例如city
addr
zipcode
都用字典的形式展现出来。

3.5 参数组合

在参数中,可以用必选参数默认参数可变参数关键字参数命名关键字参数进行组合,而且命令的顺序也是如此:

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)
f1(1,2,c=3)
f1(1,2,3,'a','b')
f1(1,2,3,'a','b',x=99)
f2(1,2,d=99,ext= None)

a = 1 b =  2 c =  0 args =  () kw =  {}
a = 1 b =  2 c =  3 args =  () kw =  {}
a = 1 b =  2 c =  3 args =  ('a''b') kw =  {}
a = 1 b =  2 c =  3 args =  ('a''b') kw =  {'x'99}
a = 1 b= 2 c= 0 d= 99 kw= {'ext'None}

在使用函数的时候,尽量不要使用太多的混合参数,否则函数的理解性很差。

3.6 递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,就这个就是递归函数。我们用fact(n)
,其中fact(n) = n! = 1 * 2 * 3 * 4 * 5 * 6 * (n-1) * n

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

1
120

4 函数的返回值

4.1 函数的返回值介绍

所谓的"返回值",就是程序中函数完成一件事情后,最后调用者的结果。举例如下:

def cal(a,b):
 c = a +b
 return c #返回值
print(cal(1,2))

3

def cal(a,b):
 return a + b
print(cal(1,5))

6

我们发现打印print(cal(1,5))
会很琐碎,因而可以使用另外一种保存函数的方法:

def cal(a,b):
 return a + b
result = cal(100,98)
print(result)

198

return
函数还有另外一个作用,就是结束函数,我们来看来两个例子:

def cal_nums():
    print("--1---")
    return 1
    print("----2---")
    return 2
    print("----3----")
cal_nums()

--1---

return
的功能就是结束运算,后面的就不需要执行了。一个函数也会返回多个数据的方式

def calculate(a,b):
 shang = a // b
 yushu = a % b
 return shang,yushu  #默认元组
result = calculate(5,2)
print(result)

def calculate(a,b):
    shang = a // b
    yushu = a % b
    return shang,yushu #返回的是元组
result = calculate(5,2)
print(result)

(2,1)

6局部变量与全局变量

6.1局部变量

就是在函数内部定义的变量,作用是只能在函数内部使用,在函数的外部是不能使用的。为了临时保存数据需要在函数中定义变量来进行储存。当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了。

def show():
 #定义局部变量
 sal = 15000
 print("薪资:",sal)
show()

薪资: 15000

6.2全局变量

如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。例如:有2个兄弟都有手机,各自有自己的小秘密在手机里,不让另外一方使用(可以理解为局部变量) 如果家里的电话是2个兄弟都可以随便使用的(可以理解为全局变量) 举一个例子:

money = 1200
def test1():
 print(money)
def test2():
 print(money)
#调用函数
test1()
test2()

总结:

  • 在函数外定义的变量叫做全局变量
  • 全局变量能够在所有的函数中进行访问

6.3全局变量与局部变量冲突问题

#定义全局变量
x = 1000

def test1():
 #定义局部变量,与全局变量名字相同
 x = 300
 print('----test1----%d'%x)
 #修改
 x = 200
 print('x = %d'%x)
test1()
test2()

6.4修改全局变量

x = 100
def test1():
    #定义全局变量
    global x
    print('修改之前:%d'%x)

    #修改
    x = 200
    print('修改后%d'%x)

def test2():
    print('x = %d'%x)
test1()
test2()

修改之前:100
修改后200
x = 200

7 捕获异常

一旦出错,还要一级一级上报,知道某个函数可以理解该错误。所以高级语言都内置了一套try...except...finally
的错误处理机制。python 也不例外,我们来看一个简单的例子。

try:
 print('try....')
 r = 10 / 0
except ZeroDivisionError as e:
 print('except:',e)
finally:
 print('finally...')
print('END')

当我们认为代码可能会出错时,使用try
运行这段代码,如果执行错误,后续代码
不会继续执行,就会直接跳转到except
代码块。执行完except
后如果有 finally
就会执行finally

try...
except: division by zero
finally...
END

同样,如果我们把上式中的0
修改为2
,我们继续执行就会出现如下结果:

try...
result: 5.0
finally...
END

说明在异常部分没有执行,但是仍然继续执行下面的代码。

在真实的编程过程中,会有很多种类的错误,如果发生了不同类型的错误,就应该由不同的except
语块处理。就应该由duogeexpect
来捕获不同类型的错误。再举一个例子:

try:
    print('try...')
    r = 10 / int('a')
    print('result:',r)
except ValueError as e:
    print('ValueError:',e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:',e)
finally:
    print('finally....')
print('END')

输出结果为:

try...
ValueError: invalid literal for int() with base 10'a'
finally....
END

因为int()
函数可能会抛出valueError
,所以我们用except
捕获valueError
,用另外一个except
捕获zeroDivisionError
此外我们可以在except
语块后面加一个else
,所以当没有错误发生时,会自动执行else
语句:

try:
    print('try...')
    r =10/int('2')
    print('result:',r)
except ValueError as e:
    print('ValueError:',e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:',e)
else:
    print("no error!")
finally:
    print('finally...')
print('END')  

try...
result: 5.0
no error!
finally...
END

Python的错误其实也是class
,所有的错误类型都继承自BaseExcept
,所以在使用except
时需要注意的是,它不但捕获该类型的错误,还能把其他子类也一并处理。

try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')

第二个except
永远也捕捉不到unicodeError
。python的常见错误是从BaseException
类派生出来的。常见的错误类型和继承关系可以参看

使用try...except
捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如main()
调用foo()
foo()
调用bar()
结果bar()
这时,只要main()
捕捉到了就可以处理。

def foo(s):
    return 10 /int(s)
def bar(s):
    return foo(s) * 2
def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:',e)
    finally:
        print('finally...')

不需要在每个可能出错的地方去捕捉错误,只要在合适的层次去捕获错误就可以了。这样一来就大大减少了try...except...finally
的麻烦。

往期回顾

美国PM2.5污染变化图

用python绘制中国地区

pandas学习笔记(二)

文章转载自牛谈琴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论