# -*- coding: utf-8 -*-
"""
Created on Fri May 20 01:48:27 2017
@author: zhangll
"""
函数也是p对象,学过java的同学都知道“方法”的概念,“方法”在java的表现中是指一段程序流程的封装,而python函数可以在这个概念上与java的“方法”概念相呼应。但是java
方法调用的参数分为实参和形参,java中并没有传递“方法”参数这一说法,一般是通过
包装好的类、变量作为参数来实现程序的转移的。在python中却可以利用“函数”作为参数来传递的,可以说python把“函数”作为一个“对象”来考虑的。如下:我们看一个简单的例子:
def pythagorean(a,b):
return sum((a**2,b**2))**0.5
def pythagoreandouble(funcation,c):
return funcation(c[0]*2,c[1]*2)
if__name__=='__main__':
pythagoreandouble(pythagorean,(3,4))
其中pythagorean是勾股定理,我们把pythagorean函数作为一个参数传入pythagoreandouble(计算勾股的两倍)函数中,作为一个函数来使用,结果为,扩充了一倍,结果:
Out[361]: 10.0
接下来对python函数做几个补充,希望对大家在之后的学习中有所帮助:
1.函数基本组成
由“def”关键字作为定义头:def(define)相当于是一个定义,
格式为---------------------------------
def(arg1,arg2,...,argn):
[function body]
[return object]
跟绝大多数语言一样,都是以
方法名(参数)(方法体)[返回值(可有可无)]
构成的。一般情况下在不赋值的情况下,会生成一个“匿名对象”,而一旦以
place=方法名(参数)
如上表达式出现的时候,python就会产生一个新的“p对象”,并把这个对象“赋值”给place。place在这里就成了一个变量,是一个特殊的对象,该对象具有指向“p对象”的指针。
2.把“函数”作为一个对象来使用,因此“函数”的编写可以处于代码模块中的任何一个位置,这种写法非常自由,可以说秉承了python里一切都是对象的逻辑。举个栗子:
test=True
if test:
def funct1(a,b):
return sum((a**2,b**2))**0.5
else:
def funct2(a,b):
return sum((a**2,b**2))**1
如果运行这段代码,根据test==true的逻辑,只有funct1被加载了,而funct2并未被加载(为被定义),这样大家可以灵活使用python函数,编写自己想要的结构模式。
3.python的函数传递的是任何类型的对象“引用”,一旦对象在函数体中处于被操作修改,那么被传递进去的源“对象”将被修改,甚至只要对象符合函数体中的计算逻辑运算,那么所传递的参数对象并不受数据类型(int,list,tuple,dict,array)的限制,这个比Java函数定义宽容了许多,比如下面这段代码:
def funct3(a,b):
return a*b
if __name__='__main__':
funct3(1,2) #Out[*]: 2
funct3("c",2) #Out[*]: 'cc'
也就是说"*"操作不仅可以作为整数之间的“乘法”作用,也可以作为整数与字符串之间的合并操作,这个是一种python“多态”的行为。但这种“多态”与java中的“多态”却不一样。我们知道java是强类型语言,注定与python这种弱类型语言在语法上的规定有着较大的差异。
java的多态体现在下面三个条件上
1.继承
2.重写
3.父类引用指向子类对象
三种条件完备的情况下,才能称为java“多态”,符合第1、2条件的语言顶多叫做“基于对象”的语言,而真正能够实现第三个条件的才能在真正意义上来讲属于“面向对象”的语言。而且第1、2两点是第三点(最重要特性)的基础,这样才能出现“多态”的特征。
多态相关内容看http://www.cnblogs.com/tanqiantot/archive/2013/03/27/3126818.html
而python中的“变量”首先是弱类型定义的,就在先天无法实现第三个条件,即无法实现父类变量的声明来指向子类的对象。那么即使这样,难道python就不具有“多态”特性了吗?让我们继续分析一下,我们知道python本身是可以实现继承和重写的,如下例子:
class Animal:
def __init__(self, name):
self.name = name
def talk(self):
raise NotImplementedError("Subclass must implement abstractmethod")
def eat(self):
return '吃饭了'
class Cat(Animal):
def talk(self):
return 'Meow!'
class Dog(Animal):
def talk(self):
return 'Woof! Woof!'
if __name__='__main__':
animals = [Cat('Missy'),Cat('Mr. Mistoffelees'),Dog('Lassie')]
for animal in animals:
print animal.name + ': ' + animal.talk()
print animal.name + ': ' + animal.eat()
输出结果:
Missy: Meow!
Missy:吃饭了
Mr. Mistoffelees: Meow!
Mr. Mistoffelees:吃饭了
Lassie: Woof! Woof!
Lassie:吃饭了
在Cat和Dog类中并没有声明eat函数,但是我们用Cat(父类)的方式实现了子类对父类的继承,所以子类本身就具有了eat函数功能,就想父亲需要吃饭一样,继承的子类也需要有吃的动作。
然而通过查看python的一些学习手册和编程指南以及各位python大咖对python程序的设计心得方面的内容,始终无法找到能够满足第三个条件特性代码,有些人觉得python因为无法体现第三个条件而认为python没有“多态”的特性,更有甚者认为python缺乏多态特性而认为python并不是一个面向对象的程序设计语言。
通过wiki对多态解释来了解一下什么是多态(polymorphism),个人也倾向于wiki的解释,其认为对同一操作的行为(*,len())的合理性意义会根据传递的对象类型的不同来判断的。或者用多态的原意:同一操作作用于不同对象,可以有不同的解释,生成不一样的结果。这样的描述同样适用于java多态的第三个条件:即同一类(父类)引用不同的对象(不同子类,但是子类有相同方法),对父类的同一操作(方法)实质是作用于不同对象,得到不一样的结果。这视乎很绕,但是我们要理解”多态“的本质,就比较容易。当初定义”多态“,其实是为“程序设计”作服务的,因为有了这个概念,才能很好地实现java中的父类引用指向子类对象的程序设计,才能理解并自己开发这样的程序。同样的,基于此,我们对python的”多态“理解也是为了python程序设计需求而提出的一种概念,我以三种不同的程序流来表示python的”多态“概念:
a) 利用*号做运算(就如我们刚才提到的勾股定理程序),我们可以输入1*10得到10,也可以输入“a”*3得到“aaa”,前者做了类似于相加的运算,而后者做了相当于拼接字符的运算,虽然我们做了同样的操作却得到了不同地解释或运算方式,而这种不同依据传入的对象的数据类型的不同而表现出不同的特性。
b) 利用len()函数分别对元组(1,2,3)和列表[1,2,3]
len((1,2,3)) #Out[6]: 3
len([1,2,3]) #Out[7]: 3
其实质是元组和列表本身就带有__len__的特殊方法,实现了不同的计算原则,而len函数(同一操作)调用了不同对象的__len__方法所存储的值,实现了对不同数据类型对象的同一操作(读取)的功能,而并没有做计数的操作。这里我们也发现,一般使用内置函数比自己编写函数效率高的原因通过这个方法的理解可见一斑。
c)通过定义不同类来实现对不同对象做同一操作:(分别定义三个类,每个类中都有eat函数,并通过循环对不同对象进行操作)
class A:
def eat(self):
return "A"
class B:
def eat(self):
return "B"
class C:
def eat(self):
return "C"
if __name__='__main__':
list1=[A(),B(),C()]
[x.eat() for x in list1] #Out[11]: ['A', 'B', 'C']
如上三个例子充分地展现了python的“多态”针对的是“同一操作”可以对不同对象产生不一样的结果,而java等语言的“操作”更偏向于正对“同一父类”使用相同操作实现不一样的方式,而本质上这“同一父类”其实指向的是不同子类对象。在这个层面上来说,python可以被认为是具有“多态”特性的。
4.形参与实参的概念
一般计算机语言把定义函数或方法(被调用函数或方法)上(括号中所包含的定义)关键字
5.函数的参数*args与**kwargs的区别
后续更新吧