Python核心技术与实战——七|自定义函数
我们前面用的代码都是比较简单的脚本,而实际工作中是没有人把整个一个功能从头写到尾按顺序堆到一块的。一个规范的值得借鉴的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核心技术与实战——七|自定义函数的更多相关文章
- Python核心技术与实战——八|匿名函数
今天我们来学习一下匿名函数.在学习了上一节的自定义函数后,是时候了解一下匿名函数了.他们往往非常简短,就一行,而且有个关键字:lambda.这就是弥明函数. 一.匿名函数基础 匿名函数的基本格式是这样 ...
- Python核心技术与实战 笔记
基础篇 Jupyter Notebook 优点 整合所有的资源 交互性编程体验 零成本重现结果 实践站点 Jupyter 官方 Google Research 提供的 Colab 环境 安装 运行 列 ...
- Python核心技术与实战——十九|一起看看Python全局解释器锁GIL
我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...
- Python核心技术与实战——六|异常处理
和其他语言一样,Python中的异常处理是很重要的机制和代码规范. 一.错误与异常 通常来说程序中的错误分为两种,一种是语法错误,另一种是异常.首先要了解错误和异常的区别和联系. 语法错误比较容易理解 ...
- python教程(三)·自定义函数
前面介绍了如何使用函数,这一节我们就来学习怎么创建自己的函数! 自定义函数 创建函数非常简单,它使用关键字 "def",下面的代码创建了一个带有一个参数的函数,并使用不同的参数调用 ...
- Python核心技术与实战——二一|巧用上下文管理器和with语句精简代码
我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? ...
- Python核心技术与实战——十六|Python协程
我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多 ...
- Python核心技术与实战——十四|Python中装饰器的使用
我在以前的帖子里讲了装饰器的用法,这里我们来具体讲一讲Python中的装饰器,这里,我们从前面讲的函数,闭包为切入点,引出装饰器的概念.表达和基本使用方法.其次,我们结合一些实际工程中的例子,以便能再 ...
- Python学习笔记(七)函数的使用
python中的函数使用较简单,这里列出值得注意的几点: 内嵌函数 例如: # coding: utf-8 def foo(): def bar(): print 'bar() called. ...
随机推荐
- 进程间通信(IPC)-管道、匿名管道
每个进程都有各自的地址空间,任何一个进程的全局变量在另一个进程中都看不到 所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读 ...
- switch 失效
switch 开关失效无法切换,可以关闭,无法开启. 发现问题点 require-table.js 中toggle value的数据类型不是 number 导致 (value ? no : yes ...
- 如何使用Jetbrains Clion 在一个工程里 编译单个C++源文件 (实现一键编译且运行)
这篇文章主要在下面这篇文章的基础上,先是实现了一键编译和一键运行两个单个功能,最后又进一步使用Clion自带的Custom Build Application实现编译且运行一键实现. https:// ...
- kafka操作命令
kafka启动 bin/kafka-server-start.sh -daemon config/server.properties 创建topic bin/kafka-topics.sh -zook ...
- 【mysql】时间类型-如何根据不同的应用场景,选择合适的时间类型?
首先理解mysql时间存储类型,与使用场景 一些帮助理解的资料: 摘自:MySQL如何存储时间datetime还是timestamp MySql中关于日期的类型有Date/Datetime/Times ...
- C# CLR20R3 程序终止的几种解决方案 【转】
[转]CLR20R3 程序终止的几种解决方案 这是因为.NET Framework 1.0 和 1.1 这两个版本对许多未处理异常(例如,线程池线程中的未处理异常)提供支撑,而 Framework ...
- Linux_进程管理&计划任务
目录 目录 top打开Linux系统任务管理控制台 ps进程查询指令 kill进程关闭指令 一个小实验 一次性计划任务 周期性计划任务 top打开Linux系统任务管理控制台 快捷键: P M k q ...
- 看看 Delphi XE2 为 VCL 提供的 14 种样式
看看 Delphi XE2 为 VCL 提供的 14 种样式 其实只提供了 13 个 vsf 样式文件, 还有默认的 Windows 样式, 共 14 种. 在空白窗体上添加 ListBox1 等控件 ...
- map根据属性排序、取出map前n个
/** * map根据value排序 * flag = 1 正序 * flag = 0 倒序 * * @param map * @param flag * @return */ public stat ...
- zip函数用于对列表对应元素打包成元组
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表. 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以 ...