我们前面用的代码都是比较简单的脚本,而实际工作中是没有人把整个一个功能从头写到尾按顺序堆到一块的。一个规范的值得借鉴的Python程序,除非代码量很少(10行20行左右)应该由多个函数组成,这样的代码才更加的模块化、规范化

  函数的基础知识这里就不详细说明了,这里讲一些其他的内容!

一.多态

  我们先看一个这样的函数

def fun(a,b):
return a+b
print(fun(1,2))
print(fun('',''))

  运行后会发现效果是不一样的。Python不用考虑输入数据的类型,而是将其交给具体的代码去判断执行,同样一个函数可以同时用在int、str等数据类型的操作中。这种行为就称为多态。这也是Python和Java,C等很大的一个不同点。注意这是一个中性的特点,无所谓优略,但在必要时需要在开头加上数据的类型检查。

二.嵌套

  Python函数的另一大特性就是支持函数的嵌套

def fun1():
print('in fun1')
def fun2(): #fun2是嵌套在fun1内部的
print('in fun2')
fun2() fun1()

  这里再fun1内部定义了fun2,在调用fun1时,先打印‘in fun1’,然后fun1内部调用fun2,在打印‘in fun2’。这样做有什么好处呢?

  嵌套的优点

    1.函数的嵌套可以保证内部函数的隐私。内部函数只能被外部函数调用或访问,不会被暴露在全局作用域。如果函数内部有一些隐私数据(数据库的用户、密码等)不想被暴露在外部,就可以使用函数的嵌套。将其封装在函数内部,只通过外部函数来访问

def connect_DB():
def get_DB_configuration():
host = ''
username = ''
password = ''
return host,username,password
conn = connertor.connect(get_DB_configuration()) #这里所有的用户信息是不会被暴露出来的
return conn #函数只返回连接状态

  这里的get_DB_configuration()只能在connect_DB函数内部被调用,在全局内部是无法调用的。

    2.合理的使用函数的嵌套,能够提高程序的运行效率。比如我们想算一个数的阶乘,在计算前需要判定传递的参数是否合法

def factorial(input):
if not isinstance(input,int):
raise Exception('input must be an integer.')
if input < 0:
raise Exception('input must be greater or equal to 0') def inner_factorial(input):
if input <=1:
return 1
return input*inner_factorial(input-1)
return inner_factorial(input) print(factorial(3))

  这样通过函数的嵌套我们在检查数据的合法性时只执行了一次,而如果我们不用嵌套的化每次递归都要进行一次判定,会降低程序的运行效率。在工作中会经常遇到这种情况,那么运用嵌套就是非常必要的了。

三.函数变量作用域

  函数的变量作用域和其他语言类似,如果变量在函数内部,就是局部变量,只在函数内部有效,一旦函数执行完毕,局部变量就会被回收,无法访问。

  相对应的,全局变量则是定义在整个文件层次上的,例如这样

MAX = 10
MIN = 1
def fun():
if MAX > MIN:
print(MAX)
fun()

  但是我们不能随意改变变量的值,例如函数里出现这样就会报错

MAX = 10
MIN = 1
def fun():
MAX+=1
fun()
UnboundLocalError: local variable 'MAX' referenced before assignment

因为Python解释器会默认函数内部的变量为局部变量,调用时发现MAX并没有被声明,就会抛出异常。那如果我们在函数中定义了个变量名称和全局变量名字一样会怎么样呢?

A = 123
def fun():
A = 456
print('in fun A:{}'.format(A))
print('before call fun A:{}'.format(A))
fun()
print('after call fun A:{}'.format(A))
before call fun A:123
in fun A:456
after call fun A:123

结论

但还是要注意,在函数内如果先调用了全局变量是不能重新声明一个和它名字相同的变量的,也不能重新改变它的值。而假如需要对这个变量进行改变时,就需要加上关键字Global。

A = 123
def fun():
global A
print(A)
A = 456
print('in fun A:{}'.format(A))
print('before call fun A:{}'.format(A))
fun()
print('after call fun A:{}'.format(A))
before call fun A:123
123
in fun A:456
after call fun A:456

结论

  切记切记,这个方法一定要慎用。因为一旦函数被调用变量的值就会被更改。如果哪次在哪次调用中被修改成不需要的值,要追溯起来时相当麻烦的。

  还有就是嵌套函数,内部函数可以访问外部的变量而不能改变其值。要想改变值的话在内部函数用关键字nonlocal声明变量

def fun1():
x = 'local'
def fun2():
nonlocal x #一定要在一开始声明
print('before change x:{}'.format(x))
x = 'inside'
print('after change x:{}'.format(x))
fun2()
print('after call fun2 x:{}'.format(x))
fun1()
before change x:local
after change x:inside
after call fun2 x:inside

结论

四.闭包、闭包、闭包

  闭包(closure)是这节课里最重要却右不好理解的内容。闭包和嵌套类似,不过这里的外部函数返回的是一个函数而不是具体的值,返回的函数通常赋予一个变量,这个变量可以在后面被继续执行调用。

  举个例子,我们想计算一个数的n次幂,用闭包可以这么写

def nth_power(exponent):
def exponnet_of(base):
return base**exponent
return exponnet_of #返回值是一个函数
square = nth_power(2) #计算一个数的平方
cube = nth_power(3) #计算一个数的立方
print(square(3))
print(cube(3))

  这里的外部函数nth_power()的返回值是函数exponnet_of(),在执行完

square = nth_power(2)
cube = nth_power(3)

  以后外部函数的参数exponent是会被内部函数exponnet_of()记住的,之后我们调用时程序就能顺利的输出结果。

  这么看起来,我们也可以把程序写成这样的

def nth_power_rewrite(base,exponnet):
return base**exponnet

  其实也是可以的,但是使用了闭包可以使程序变得更简洁易读。比如我们需要算很多个数的平方,就成这样的了

不用闭包
res1 = nth_power_rewrite(1,2)
res2 = nth_power_rewrite(2,2)
res3 = nth_power_rewrite(3,2)
res4 = nth_power_rewrite(4,2)
#使用闭包
squre = nth_power(2)
res1 = square(1)
res2 = square(2)
res3 = square(3)
res4 = square(4)

  首先看来,闭包在每次调用函数时都少数如一个参数,更加简洁。

  其次,和前面的嵌套类似,函数开开始需要做一些额外的工作,而需要多次调用这个函数时,就可以把这些额外的工作放在外部函数中,可以减少多次调用导致的不必要的开销。

  另外一点以后会讲,闭包常常和装饰器(decorator)一起使用。

Python核心技术与实战——七|自定义函数的更多相关文章

  1. Python核心技术与实战——八|匿名函数

    今天我们来学习一下匿名函数.在学习了上一节的自定义函数后,是时候了解一下匿名函数了.他们往往非常简短,就一行,而且有个关键字:lambda.这就是弥明函数. 一.匿名函数基础 匿名函数的基本格式是这样 ...

  2. Python核心技术与实战 笔记

    基础篇 Jupyter Notebook 优点 整合所有的资源 交互性编程体验 零成本重现结果 实践站点 Jupyter 官方 Google Research 提供的 Colab 环境 安装 运行 列 ...

  3. Python核心技术与实战——十九|一起看看Python全局解释器锁GIL

    我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...

  4. Python核心技术与实战——六|异常处理

    和其他语言一样,Python中的异常处理是很重要的机制和代码规范. 一.错误与异常 通常来说程序中的错误分为两种,一种是语法错误,另一种是异常.首先要了解错误和异常的区别和联系. 语法错误比较容易理解 ...

  5. python教程(三)·自定义函数

    前面介绍了如何使用函数,这一节我们就来学习怎么创建自己的函数! 自定义函数 创建函数非常简单,它使用关键字 "def",下面的代码创建了一个带有一个参数的函数,并使用不同的参数调用 ...

  6. Python核心技术与实战——二一|巧用上下文管理器和with语句精简代码

    我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? ...

  7. Python核心技术与实战——十六|Python协程

    我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多 ...

  8. Python核心技术与实战——十四|Python中装饰器的使用

    我在以前的帖子里讲了装饰器的用法,这里我们来具体讲一讲Python中的装饰器,这里,我们从前面讲的函数,闭包为切入点,引出装饰器的概念.表达和基本使用方法.其次,我们结合一些实际工程中的例子,以便能再 ...

  9. Python学习笔记(七)函数的使用

    python中的函数使用较简单,这里列出值得注意的几点:   内嵌函数   例如: # coding: utf-8 def foo(): def bar(): print 'bar() called. ...

随机推荐

  1. mysql根据身份证查询年龄,地址,性别

    elect  case left(idcard,2)  when '11' then '北京市' when '12' then '天津市' when '13' then '河北省' when '14' ...

  2. AI工程师职业规划和学习路线完整版

    AI工程师职业规划和学习路线完整版   如何成为一名机器学习算法工程师 成为一名合格的开发工程师不是一件简单的事情,需要掌握从开发到调试到优化等一系列能 力,这些能力中的每一项掌握起来都需要足够的努力 ...

  3. linux系统下自动删除前N天的日志文件

    删除文件命令: find 对应目录 -mtime +天数 -name "文件名" -exec rm -rf {} \; 实例命令: find /opt/soft/log/ -mti ...

  4. tomcat在45秒内没有启动,启动超时

    在部署的时候出现Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server ...

  5. 为什么在vmware中不能使用ctrl+alt+F1~6切换到字符控制台

    为什么在vmware中不能使用ctrl+alt+F1~6切换到字符控制台 是因为vmware虚拟机的快捷键: ctrl+alt也用到了 因为vmware本身的hot keys也用到了ctrl+alt: ...

  6. python检测编码

    # -*- coding: utf-8 -*- import chardet import urllib #可根据需要,选择不同的数据 TestData = urllib.urlopen('http: ...

  7. JavaScript中this的一些坑

    我们经常在回调函数里面会遇到一些坑: var obj = { name: 'qiutc', foo: function() { console.log(this); }, foo2: function ...

  8. Django信号量

    摘自官方文档 使用 信号 Django发送的所有信号的列表.使用该send()方法发送所有内置信号. 参见 有关如何注册和接收信号的信息,请参阅信号调度器上的文档. 用户登录/注销时,身份验证框架会 ...

  9. 关于db4o的透明激活与激活声明

    关于db4o的透明激活与激活声明 有关于透明激活,其介绍可以参看这里:http://www.cnblogs.com/redmoon/archive/2008/02/23/1078619.html 文中 ...

  10. application.events 识别组合键 参考。

    https://blog.csdn.net/chinayu2007/article/details/43761277 在窗体上放上ApplicationEvents控件,在OnMessage消息中加入 ...