给妹子讲python-S01E17函数的基本特征
微信公众号: python数据科学家
知乎专栏: 《给妹子讲python》
https://zhuanlan.zhihu.com/c_147297848
前文传送门:
给妹子讲python-S01E07字符编码历史观:从ASCII到Unicode
给妹子讲python-S01E08理清python中的字符编码方法
【要点抢先看】
1.开始编写一个简单完整的函数
2.函数也是对象
3.函数的多态内涵
今天开始,我们来讲讲函数,简而言之一个函数就是将一些语句集合在一起的部件,它们能够不止一次的在程序中运行。函数还能计算出一个返回值,并能够改变作为函数输入的参数,而这些参数在代码运行时也许每次“代入”的值都不相同。函数是python为了代码最大程度的重用和最小化代码冗余而提供的最基本的程序结构。
函数有关的内容主要分为函数的基本概念、作用域以及参数传递,还有一些相关的高级概念,如装饰器。
【妹子说】那这一节我们先学习函数的最基本用法吧
首先我们先学习一下在python中如何去编写一个函数。今天我们先抛出点儿理论:需要注意的是,函数在python中同在C语言中是有所不同的。
第一:def引导一段可执行的代码:
def本身是一个可执行的语句,函数此时并不存在,直到python运行了def后,函数才存在,def后面包含的就是函数语句。在典型的操作中,def语句在模块文件中编写,并自然而然的在模块文件第一次被导入的时候生成定义的函数。
第二:函数也是对象。def创建了一个对象并将其赋值给某一变量名。
当python运行到def语句时,它将会生成一个新的函数对象并将其赋值给这个函数名。和普通对象赋值一样,函数名就成了某一个函数的引用。python中,万物皆对象,因此函数也是一种对象,他可以赋值给其他的变量名,并且可以保存在列表之中。
第三:函数是通过赋值语句(对象引用)传递的。
在python中,参数通过赋值传递给了函数(也就是说,就像我们所学过的,使用对象引用),在python中,调用者以及函数通过引用共享对象,但是改变传递的可变对象可以改变调用者共享的那个对象。
第四:函数的多态性。可以传递任意类型的参数给函数,函数也可以返回任意类型的对象。
其结果就是,函数常常可以用在很多类型的对象身上,任意支持兼容接口(方法和表达式)的对象都能使用。
【妹子说】哎呀,说了这么些理论,也够枯燥的,那我们来看实际的例子吧:
没问题
def func(a,b):
return a+b
other_name = func
print(other_name(1,2))
3
在这里我们可以看到如何定义一个最简单的函数,重要的是我们还将函数赋值给一个不同的变量名,并通过新的变量名进行了调用。这说明了一点,在python中函数也是对象。
python的函数使用还是非常简单的,我们再举一个例子:主要描述了两个方面:def定义(即函数的创建)和函数的调用(表达式告诉python去运行函数主体)
def func(x,y):
return x * y
print(func(2,4))
8
结合前面的例子我们可以看到,在例子中,参数x被赋值为2,y被赋值为4,经过函数主体运算,return返回结果对象。
【妹子说】这和上面的例子不是一模一样吗?
别急,我们接着看:
def func(x,y):
return x * y
print(func(3.14,8))
25.12
-
def func(x,y):
return x * y
print(func('Ab',8))
AbAbAbAbAbAbAbAb
出现这种现象非常重要,我们在函数声明时并没有对参数和返回值进行类型声明,因此实际上,这些数据类型是依托调用者的传入类型,即传入什么就是什么,函数体的执行过程可能会因为参数类型的改变而发生变化。因此这里出现了数字的乘法和字符串的重复这两种似乎截然不同的现象。换句话说func函数的运行结果取决于传递给他的值。
函数中x *y表达式的意义完全取决于x和y的对象类型,在一个实例下执行时数值乘法,在另一个实例下执行是字符串的重复,python将对某一对象在某种语法下的合理性交由对象自身来判断。
这种依赖于类型的行为称为多态,其含义就是一个操作的意义取决于被操作对象的类型,因为python是动态类型语言,所以多态在python中随处可见。
如果传递的对象不支持这种预期的接口,那么python会在*表达式运行时进行检测,并自动抛出一个异常:
def func(x,y):
return x * y
print(func('Ab','aa'))
Traceback (most recent call last):
File "E:/12homework/12homework.py", line 4, in <module>
print(func('Ab','aa'))
File "E:/12homework/12homework.py", line 2, in func
return x * y
TypeError: can't multiply sequence by non-int of type 'str'
因此,这种多态的编程模型意味着必须测试代码去检测错误。
我们看一个例子:
def func(seq1, seq2):
res = []
for x in seq1:
if x in seq2:
res.append(x)
return res
模型中我们可以看到,调用者可以传递任何类型的参数,通过遍历两个序列,寻找他们的交集,因此函数中使用任意可迭代对象作为参数都是合适的。并在最后将运算结果的列表对象返给调用者
print(func([1,2,3,4,5,6], (5,6,7,8)))
[5, 6]
print(func('spam', ('s','p','c','m')))
['s', 'p', 'm']
甚至使用列表解析式也可以
print(func([1,2,3,4], [x for x in (2,3,5)]))
[2, 3]
可以看出,这个函数也是多态的,他支持多种参数类型,记住,只要支持对象接口----可进行数据迭代即可,第一个参数支持for循环,第二个参数支持成员测试,满足上述条件的任意对象都可以使得函数正常工作,包括实际存在的物理序列,字符串、列表等,以及可迭代对象,文件和字典等等,都可以传入使用。
同时我们需要注意,函数的参数是通过赋值而被传入的,所以seq1和seq2是本地变量,结果列表对象是通过赋值得到的,也是本地对象,所有的本地变量都在函数调用时出现,在函数退出时消失。
另外需要专门说明一点,return语句返回结果对象给调用者,但是res对象本身会在函数调用结束时消失。
【妹子说】恩,今天介绍了“函数也是对象”这个的概念,在示范函数如何创建的过程中谈了下多态的问题,值得好好消化和体会。
Python爱好者社区历史文章大合集:
Python爱好者社区历史文章列表(每周append更新一次)
关注后在公众号内回复“课程”即可获取:
小编的Python入门免费视频课程!!!
【最新免费微课】小编的Python快速上手matplotlib可视化库!!!
崔老师爬虫实战案例免费学习视频。
陈老师数据分析报告制作免费学习视频。
玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。