一个前端开发工程师的Python学习(3)

- 2 mins

上集对比学习了jspython中的数据类型。发现在数据类型这方面,pythonjs略胜一筹,各种方便。

今天再来对比学习一下函数

####函数的定义

在不同的语言中,定义函数的语法不同这个很正常,更何况python是一个摒弃了大括号的语言,所以定义函数跟js完全不同,这里不做展开说明了。在这里主要着重说一说在参数和函数调用等方面,jspython的异同。

####函数的参数

js中,函数的参数分为传值传址。展开来说就是基本类型(string,number,bool等)会采用传值的方式,但是高等类型(object,array,function)等会采用传址的方式,这两张方式的异同在这里就不做展开了,只要明白有这两张方式就好,举个简单传址的例子:

var arg = {"name":"a"}
function change(obj) {
	obj["name"] = "b";
	return obj;
}

console.log(change(arg));		// {"name":"b"}
console.log(arg);				// {"name":"b"}

这里乱入一下php,在php中,传给函数的参数,传值还是传址是可以在定义函数时,进行定义的,例如:

# 传值

$arg = array(
	"name"=>"a"
);
function change($arg) {
	$arg["name"] = "b";
	return $arg;
};

print_r(change($arg));		# ([name]=>b)
print_r($arg);				# ([name]=>a)

# 传址
$arg = array(
	"name"=>"a"
);
function change(&$arg) {
	$arg["name"] = "b";
	return $arg;
};

print_r(change($arg));		// ([name]=>b)
print_r($arg);				// ([name]=>b)

但是在python中,你需要在定义函数调用函数时,确定是要传值还是传址,例如:

# 传址
arg = {"name":"a"}
def change(arg):
	arg["name"] = "b"
	return arg
	
print change(arg)		# {"name":"b"}
print arg				# {"name":"b"}

# 传值
arg = {"name":"a"}
def change(**arg):
	arg["name"] = "b"
	return arg
	
print change(**arg)		# {"name":"b"}
print arg				# {"name":"b"}

看代码可以看到,使用**这个符号,可以将dict这种类型改为传值的方式。在python中,如果一个函数的参数前面加了**,就证明这个函数接收的将是一个key个数不确定的dict,在调用参数时,需要传入name="a"这种类型的数据(也就是字符串),才会将其转换成dict

另一方面,在调用函数时,给参数加上**,会使其声明为name="a"这样的类型,在函数定义参数同样有**时,会变成传值的方式。

####高阶函数

所谓高阶函数,就说指可以将函数本身作为参数的函数。

js中,函数的参数本身就可以是任何类型的数据,所以js本身就带有高阶函数的特征。

python中,是通过mapreduce这两种方法来实现高阶函数的。

先来说说mapmap接收两个参数,第一个是调用的函数,第二个是一个序列,如下:

def foo(x):
	return x * x
	
map(foo,[1,2,3,4,5,6]); # [1,4,9,16,25,36]

再来说说reducereduce的用法比map复杂一些,reduce同样接收两个参数,第一个是要调用的函数,第二个是一个序列。但是不同的是,reduce参数中的函数,也必须接收两个参数,第一个参数是序列中第n-1个值的计算结果,第二个是序列中第n个值,如下所示:

def foo(x,y):
	return x + y
	
reduce(foo,[1,2,3]) # foo(foo(1,2),3); # 6

####高阶函数拓展

上面已经说了,在js中,函数天生具有高阶函数的特征,在js中,很多对象的方法本身就是高阶函数,例如sort方法:

var arr = [5,4,3,2,1];
var arr2 = arr.sort(function (a,b) {
	return a - b;
});

python中,排序的方法也很类似:

def foo (a,b):
	return a - b

arr = [5,4,3,2,1]
arr2 = sorted(foo,arr);

除了参数中可以传入函数之外,高阶函数还可以在返回值中返回参数。这个在js中我们通常叫做闭包,在python中,你也可以这么称呼。

####匿名函数

js中,匿名函数是很常见的使用方式:

var foo = function (a) {
	return a * a;
};

python中,匿名函数的使用不如在js中方便,使用方法如下:

map(lambda a : a * a,range(3));

python的匿名函数只允许有一个表达式,该表达式的结果就是函数的返回值,所以这就限定了匿名函数不可以太复杂,但是这样也有好处,就是可以在需要的地方更加简洁的进行函数计算,例如上述的一行代码,就可以求出[1,2,3]的平方数组,只用一行代码!

####装饰器

装饰器这个概念在js中是不存在的,可以看做是python中一种非常独特的语法糖。

装饰器本身的作用是将某一函数当做参数,在另一函数中调用,从而起到增强或者装饰该函数的作用。

装饰器的用法如下:

@decorator
def foo(a):
	return a + 1

装饰器本身也是一个高阶函数,需要自己定义,例如:

def decorator(fun):
	@functools.wraps(fun)
	def wrapper(*args,**kw):
		return fun(*args,**kw)
	
	return wrapper

使用装饰器,相当于层层调用装饰器的返回值,直到没有return(最后一个return应该是调用被装饰的函数)。

在使用装饰器时,还有一点需要注意,就是要将装饰函数的__name__设置为被装饰函数的__name__,这样才会像直接调用被装饰函数一样。

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora