Python进阶-自定义函数基础

来源:http://www.sh-fengwen.com 作者:鲜果干果 人气:182 发布时间:2019-11-07
摘要:1、判断字符串,内容是否为数字 本文为《爬着学Python》系列第十篇文章。 我们用python;xlrd读Excel内容时,本来只是输入的整数字,经常读出来的是float类型 我们需要自动转成整型,意

1、判断字符串,内容是否为数字

本文为《爬着学Python》系列第十篇文章。

我们用python;xlrd读Excel内容时,本来只是输入的整数字,经常读出来的是float类型


我们需要自动转成整型,意思就是说,读出来的和我们输入的一样,但是,我们不能直接用int转换,原因呢,我们无法确定读的每个单元格的值都是数字

在实际操作中,可能函数是我们几乎唯一的实现操作的方式,这是因为函数能够构造一个高度集中的变量环境,在合理的设计下,它能使程序思路更加清晰的同时更利于调整与修改。几乎没有哪个程序设计语言会不涉及自定义函数的。

那么我们自己,定认一个函数如下:

图片 1

def isNumeric(value):
    try:
        tv = float(value)
        return int(tv)
    except ValueError:
        return value

在上一篇文章中我们留了许多内容说要在本文中介绍,它们是一些和函数参数相关的问题。函数是我们的对操作方式的一种整合,因此我们会通过函数来进行运算或者完成某些功能,这些功能涉及到变量时,我们必须清楚到底发生了哪些事情。废话少说吧。

 

创建自定义函数

Python的自定义函数格式中规中矩

def func_name(arg1):
    pass

def引导自定义函数名,用括号给出该函数的参数,在冒号后换行通过缩进确定函数体。在格式上和条件判断语句有些相似。

当然,我们从简单的开始讲起,这是Python自定义函数的简单形式。一般能“动手脚”的地方只有三个,一个是def前面可以用装饰器(详见我的另一篇文章Python精进-装饰器与函数对象),一个是函数参数,一个是执行语句。

关于执行语句部分,主要是函数的嵌套以及控制结构的组合,这种内容作为知识讲解没什么意思。大多数人都知道可以这么做,但很多人做不好,是不是因为没学好呢?我觉得不是的,是练少了,积累项目经验以后就会逐渐强化这方面的能力。而装饰器之前专门提前讲过,因此本文的重点会放在函数参数上。之后也会在深入了解Python自定义函数参数设计的基础上去认识如何正确设置函数返回值。

2、获取当前系统时间

自定义函数的参数

首先我要声明一点,我决定不讲一般意义上的形参(形式参数)和实参(实际参数)的知识。按道理来说,即使Python不严格要求定义函数参数,但这方面的知识有助于理解自定义函数中参数操作的情况,还是应该说明一下的。但是我仔细想了一下在Python编程中不知道这两个概念真的完全没有任何关系,我们可以简单地理解为在定义函数时括号中声明的参数是我们在函数使用中会用到的参数,在调用函数时括号中的变量就是参加函数运算用到的变量。是的,换个名字,参数(用于定义)和变量(用于调用)就足以理解了。

可能完全没有基础的同学看上面一段话还是有些不明白,这很正常,我们还没有讲过函数的调用。没关系再接下来的例子中我们会见到。不过这一节我们重点是看看函数定义时参数有哪些形式。

import time

    #获取当前系统时间
    def getCurTime(self):
        curTimeStr = time.strftime('%Y-%m-%d_%H-%M-%S',time.localtime()).decode('utf-8')
        return curTimeStr

最普通的参数

最普通的自定义函数参数就是在括号中列出一系列我们要用的参数。

def print_times(_string, _time):
    for i in range(_time):
        print(_string)

print_times('Hello!', 3)

在这个例子中我们定义函数时定义了两个变量,分别是_string_time。这个函数的作用不用我过多说明,函数体只有一个循环语句,目的是重复输出一个字符串。首先要注意的是为什么我要在"string"和“time”前加下划线呢,这是为了防止和其他变量出现冲突。如“string”有可能和内置关键字冲突(其实不会,Python字符串内置关键字是str,这里是为了保险起见),“date”有可能在使用了标准库datetime与其中的方法冲突。为了减少歧义,在定义函数的时候给变量前面加上下划线是比较稳妥的办法。这个技巧是面向对象编程时类设计常用的手段,在自定义函数中一样可以用。在后面的例子中,有时我会用比较长的不太可能冲突的变量就可以不这么做了。

接下来就是函数的作用的问题,我们需要重复输出一个字符串,所以理所当然的情况下我们只需要简单地涉及两个操作对象,一个是要输出的字符串,一个是这个字符串输出的次数。这是比较好理解的。所以我们调用函数的时候,我们给出的字符串是Hello,次数是3,这个函数就会输出Hello三次。

但是可能会有疑惑的是,我们有必要自定义一个函数这么做吗?我们直接用一个循环语句不是一样可以完成这样的工作吗?这也就是我们为什么需要自定义函数的问题。

在文章开头我简单讲了一下自定义函数可以把操作进行整合,可以集中变量环境,这里我们仔细说明一下这些话是什么意思。

诚然我们可以通过一个循环语句来完成重复输出字符串的工作。但是,如果我们在程序中需要多次用到这个功能呢,是不是我们每次都要再写一个循环语句呢?情况更糟的是,如果代码写完了好几天以后,我突然想要在每次输出这个字符串以后再输出一个另一个字符串呢?如果我们使用了函数,这时候我们可以把函数改成这样

def print_times(_string, _time, fix_string=None):
    if fix_string is None:
        for i in range(_time):
            print(_string)
    else:
        for i in range(_time):
            print(_string)
            print(fix_string)

或者这样

def print_times(_string, _time, fix_string=None):
    def print_times_former(_string, _time):
        for i in range(_time):
            print(_string)

    if fix_string is not None:
        _string += 'n' + fix_string
    print_times_former(_string, _time)

或者我们可以写一个装饰器(功能会更局限,在此不演示了),总之方法有很多。

注意到我给新参数一个默认值并且使用了一个判断语句,这样原来调用print_times函数的地方不会报错,会像原来一样完成工作(有默认值的参数会在下面介绍)。我们可以去调用了print_times函数的地方加上我们需要使用的函数,它们就可以完成新功能了。

可能你还可以反驳,就算我写了几遍循环,我就去用了循环的地方添上不就行了吗。那好,我的问题是,如果一个文件代码量很大,那么多for语句,你要找出来是重复输出字符串的地方恐怕也挺费劲吧,不小心改到别的循环运行有问题是不是还得回来找?如果用了函数,在任何编辑器中ctrl+F查找print_times结果就一目了然了(在编辑器如VS Code中你只要选中这个字段就能清楚看到,甚至不需要搜索,而且可以复选进行同步修改)。

而且试想一下,这只是一个简单的重复输出字符串的功能而已,如果是更复杂的功能,函数的优势就更明显了。这还是没有返回值的函数,涉及到返回值时,函数的优势非常大,下面我们会谈到。函数还可以在别的文件中引用,而不是直接复制粘贴一大段代码过来。

言归正传,我们来看看最开始的简单的print_times函数是怎么工作的。我们把_string_time作为参数,在函数体的执行语句中定义了一些操作,但是如果我们不调用这个函数,那么什么都不会发生。其实自定义函数就像是一个模板,我们给出要操作的对象的典型(就是参数),在函数体中给出它的操作语句。定义自定义函数的时候它是不会真的对这些参数进行操作的,它只是用来规定我们操作参数的方法。我们定义了一些对这些参数的操作,然后把它打包成一个函数。意思就是,要是以后要对一些变量用这个函数,那么程序就请按这样操作吧。

于是,当我们print_times('Hello!', 3)这样调用print_times函数的时候,程序就会完成我们规定好了的工作。要注意的是,仅仅是print_times的话一般代表这个函数本身,它有可能是函数变量,也有可能是函数对象。而如果函数后面加上括号,在括号里面给出作为参数的变量,print_times('Hello!', 3)就是调用这个函数。这些知识还是参考Python精进-装饰器与函数对象。

需要说明的是,函数调用的时候,变量的顺序是要和函数参数定义的时候声明参数的数量相等且顺序一致的。除非我们在给定参数的时候指明参数名,如

print_times(_time=3, _string='Hello!',)

这样即使顺序和参数声明的时候的顺序不一致,解释器也能完成正常完成功能。但是这个方法非常不推荐大家使用,原因在后面会再提。之所以要说函数参数的顺序问题,因为这涉及到其他形式的函数参数,包括有默认值的参数和可选参数。

接下来我们先介绍有默认值的函数参数。

 

参数的初始值

其实参数有默认值的函数我们在上面就见过一个,但是在这里我们先不去管他。我们先来看看这个所谓的参数默认值是什么样的。

def func_defualt(a=3)
    print(a)

func()
func(2)

注意到形式其实很简单,就是在声明函数参数的时候用赋值语句给参数一个初始值。在这样的情况下,我们本来调用函数是需要给出变量作为参数的,但是如果我们的参数有默认值,那么如果我们在调用这个函数时不实例化这个参数,那么程序就会用参数的默认值进行操作。上面的两条调用语句,分别会输出32

接下来要说的,就是刚才我们所说过的参数顺序的问题。直接先说结论,有默认值的参数要放在所有没有默认值的参数后面。这个规定不像之前涉及过的编程习惯问题,这是默认Python解释器规定的出错类型。

>>> def func_default2(a=1,b):
...     print(a, b)
...
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
>>>

Python之所以要这样规定,是为了减少程序出错的可能性,是出于safety的考虑。在程序中safety和security是不一样的概念,security一般指程序抵御外部攻击的能力,safety则一般指程序运行的稳定性。

试想一下,如果我们能够用def func(a=1,b):这样的形式定义函数,那么调用这个函数的时候就可能会出现问题。首先,如果你按照顺序给出了所有参数的值,或者虽然打乱顺序但是对应好参数名用变量赋值了,那么你有什么必要给这个参数一个默认值呢?那到了想让参数默认值发挥作用的场景,你也只能把除了有默认值的参数以外的其他参数都对应好参数名用变量赋值,这不仅麻烦而且容易出现纰漏,如果有某个参数没有值,程序就会报错。而且,在实际编程中,函数参数有可能远远不止两个,如果其中一部分有默认值一部分没有,但是顺序又被打乱了,那么调用这个函数将会是非常糟糕的一件事情。所以,为了省去不必要的麻烦,Python解释器将这个按道理来说也是编程习惯的做法变成了强制的规定。

当然,以上一大段都不重要,只要记住一点,有默认值的参数要放在所有没有默认值的参数后面。

另外值得一提的是,一般参数在函数调用时,如果不给出参数名,不能置于有默认值的参数之后

>>> def func_default2(a, b=1):
...     print(a, b)
...
>>> func_default2(b=2, 3)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>>

本文由美高梅游戏平台网站发布于鲜果干果,转载请注明出处:Python进阶-自定义函数基础

关键词:

上一篇:python 中双端队列的使用

下一篇:没有了

最火资讯