Python核心技术与实战——七|自定义函数

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

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

一.多态

  我们先看一个这样的函数

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

  运行后会发现效果是不一样的。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)一起使用。

原文地址:https://www.cnblogs.com/yinsedeyinse/p/11200542.html

时间: 2024-07-30 21:03:48

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

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

今天我们来学习一下匿名函数.在学习了上一节的自定义函数后,是时候了解一下匿名函数了.他们往往非常简短,就一行,而且有个关键字:lambda.这就是弥明函数. 一.匿名函数基础 匿名函数的基本格式是这样的: lambda argument1,argument2,argument3,...,argumentN:expression lambda后紧跟的是参数,冒号后是表达式.举个例子来说明用法 >>> fun = lambda x:x**2 >>> fun(4) 16 这里

Python核心技术与实战

课程目录:第00课.开篇词丨从工程的角度深入理解Python.rar第01课.如何逐步突破,成为Python高手?.rar第02课.Jupyter Notebook为什么是现代Python的必学技术?.rar第03课.列表和元组,到底用哪一个?.rar第04课.字典.集合,你真的了解吗?.rar第05课.深入浅出字符串.rar第06课.Python “黑箱”:输入与输出.rar第07课.修炼基本功:条件与循环.rar第08课.异常处理:如何提高程序的稳定性?.rar第09课.不可或缺的自定义函数

Python 学习日记第七篇 -- 函数

一.函数  1.函数的使用场景及定义 在使用函数编程之前,我们一直是面向过程式编程,语句的堆积造成大量的代码重复,由此,函数应运而生,函数式编程是将反复使用的代码封装到函数中,使用时只需调用即可.函数的学习会让我们更快理解面向对象这一抽象的概念,面向对象即是对函数进行分类和封装. #函数的定义 def first_func():     print("This is my first function!") first_func() def:定义函数的关键字 first_func:函数

Python核心技术与实战——十五|Python协程

我们在上一章将生成器的时候最后写了,在Python2中生成器还扮演了一个重要的角色——实现Python的协程.那什么是协程呢? 协程 协程是实现并发编程的一种方式.提到并发,肯很多人都会想到多线程/多进程模型,这就是解决并发问题的经典模型之一.在最初的互联网世界中,多线程/多进程就在服务器并发中起到举足轻重的作用. 但是随着互联网的发展,慢慢很多场合都会遇到C10K瓶颈,也就是同时连接到服务器的客户达到1W,于是,很多代码就跑崩溃,因为进程的上下文切换占用了大量的资源,线程也顶不住如此巨大的压力

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

我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? 什么是上下文管理器 在任何一种编程语言里,文件的输入输出.数据库的建立连接和断开等操作,都是很常见的资源管理操作.但是资源是有限的,在写程序的时候,我们必须保证这些资源在使用后得到释放,不然就容易造成资源泄漏,轻者系统处理缓慢,重则系统崩溃. 我们看一个例子: for i in range(100

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

python中的函数使用较简单,这里列出值得注意的几点:   内嵌函数   例如: # coding: utf-8 def foo(): def bar(): print 'bar() called.' print 'foo() called.' foo() bar() 对bar的调用是非法的,因为bar的作用域仅限于foo内,除非使用闭包将其返回. # coding: utf-8 def foo(): def bar(): print 'bar() called.' print 'foo()

python学习笔记(七)函数

原链接:http://www.cnblogs.com/vamei/archive/2012/06/01/2529500.html#!comments 函数学习遇到了问题 1 #!/usr/bin/env python 2 #coding=utf-8 3 #今天开始学习函数 4 def square_sum(a, b): 5 c = a**2 + b**2 6 return c 7 #其实学习python 过来,一直没有很好的编程的思维,思维总是会受到最初yi脚本的限制 8 #期待突破吧 9 10

Python核心技术与实战——十三|Python中参数传递机制

我们在前面的章节里学习了Python的函数基础以及应用,那么现在想一想:传参,也就是把一些参数从一个函数传递到另一个函数,从而使其执行相应的任务,这个过程的底层是如何工作的,原理又是怎样的呢? 在实际过程中,我们写完了代码测试时候发现结果和预期值不一样,在一次次debug后发现是传参过程中数据结构发生了改变,导致程序出错.比富我们把一个列表作为实参传递给另一个函数,但是我们并不希望列表再函数运行结束后发生变化.但往往事与愿违,由于某些额外的操作改变了他的值,那就导致后续程序一系列错误的发生.因此

Python 核心技术与实战 --01 列表与元祖

2019-12-21 本文章主要讲述Python的列表和元组. 高级内容: 列表与元组存储方式的差异 了解 dir() 函数的概念:    dir() 函数不带参数时,返回当前范围内的变量.方法和定义的类型列表:带参数时,返回参数的属性.方法列表. l = [1,3,3,4,8] print(dir(l)) ['__add__', '__class__', '__contains__', \ '__delattr__', '__delitem__', '__dir__', \ '__doc__'