python3.5类型参数列表问题,怎么解决

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python3.5类型参数列表问题,怎么解决相关的知识,希望对你有一定的参考价值。

参考技术A 刚开始学习python,python相对于java确实要简洁易用得多。内存回收类似hotspot的可达性分析, 不可变对象也如同java得Integer类型,with函数类似新版本C++的特性,总体来说理解起来比较轻松。只是函数部分参数的"*"与"**",闭包等问题,着实令人迷糊了一把,弄清概念后写下此文记录下来,也希望本文能够帮助其他初学者。
所以本文是一篇学习笔记,着重于使用的细节和理解上,首先分别介绍了函数各种参数类型在调用和声明时的区别,及其在混用时需要注意的一些细节,之后讲了闭包相关的内容。如果有不对的地方欢迎指正。
函数参数不带“*”,"*" 与 "**"的区别
理解这个问题得关键在于要分开理解调用和声明语法中3者得区别.
函数调用区别
1. 不同类型的参数简述
#这里先说明python函数调用得语法为:

复制代码代码如下:

func(positional_args, keyword_args,
*tuple_grp_nonkw_args, **dict_grp_kw_args)

#为了方便说明,之后用以下函数进行举例
def test(a,b,c,d,e):
print a,b,c,d,e

举个例子来说明这4种调用方式得区别:

复制代码代码如下:

#-------------------------------
#positional_args方式
>>> test(1,2,3,4,5)
1 2 3 4 5
#这种调用方式的函数处理等价于
a,b,c,d,e = 1,2,3,4,5
print a,b,c,d,e
#-------------------------------
#keyword_args方式
>>> test(a=1,b=3,c=4,d=2,e=1)
1 3 4 2 1
#这种处理方式得函数处理等价于
a=1
b=3
c=4
d=2
e=1
print a,b,c,d,e
#-------------------------------
#*tuple_grp_nonkw_args方式
>>> x = 1,2,3,4,5
>>> test(*x)
1 2 3 4 5

#这种方式函数处理等价于

复制代码代码如下:

a,b,c,d,e = x
print a,b,c,d,e
#特别说明:x也可以为dict类型,x为dick类型时将键传递给函数
>>> y
'a': 1, 'c': 6, 'b': 2, 'e': 1, 'd': 1
>>> test(*y)
a c b e d
#---------------------------------
#**dict_grp_kw_args方式
>>> y
'a': 1, 'c': 6, 'b': 2, 'e': 1, 'd': 1
>>> test(**y)
1 2 6 1 1
#这种函数处理方式等价于
a = y['a']
b = y['b']
... #c,d,e不再赘述
print a,b,c,d,e

2. 不同类型参数混用需要注意的一些细节
接下来说明不同参数类型混用的情况,要理解不同参数混用得语法需要理解以下几方面内容.
首先要明白,函数调用使用参数类型必须严格按照顺序,不能随意调换顺序,否则会报错. 如 (a=1,2,3,4,5)会引发错误,; (*x,2,3)也会被当成非法.
其次,函数对不同方式处理的顺序也是按照上述的类型顺序.因为#keyword_args方式和**dict_grp_kw_args方式对参数一一指定,所以无所谓顺序.所以只需要考虑顺序赋值(positional_args)和列表赋值(*tuple_grp_nonkw_args)的顺序.因此,可以简单理解为只有#positional_args方式,#*tuple_grp_nonkw_args方式有逻辑先后顺序的.
最后,参数是不允许多次赋值的.
举个例子说明,顺序赋值(positional_args)和列表赋值(*tuple_grp_nonkw_args)的逻辑先后关系:

复制代码代码如下:

#只有在顺序赋值,列表赋值在结果上存在罗辑先后关系
#正确的例子1
>>> x = 3,4,5
>>> test(1,2,*x)
1 2 3 4 5
#正确的例子2
>>> test(1,e=2,*x)
1 3 4 5 2
#错误的例子
>>> test(1,b=2,*x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test() got multiple values for keyword argument 'b'
#正确的例子1,处理等价于
a,b = 1,2 #顺序参数
c,d,e = x #列表参数
print a,b,c,d,e
#正确的例子2,处理等价于
a = 1 #顺序参数
e = 2 #关键字参数
b,c,d = x #列表参数
#错误的例子,处理等价于
a = 1 #顺序参数
b = 2 #关键字参数
b,c,d = x #列表参数
#这里由于b多次赋值导致异常,可见只有顺序参数和列表参数存在罗辑先后关系

函数声明区别
理解了函数调用中不同类型参数得区别之后,再来理解函数声明中不同参数得区别就简单很多了.
1. 函数声明中的参数类型说明
函数声明只有3种类型, arg, *arg , **arg 他们得作用和函数调用刚好相反. 调用时*tuple_grp_nonkw_args将列表转换为顺序参数,而声明中的*arg的作用是将顺序赋值(positional_args)转换为列表. 调用时**dict_grp_kw_args将字典转换为关键字参数,而声明中**arg则反过来将关键字参数(keyword_args)转换为字典.
特别提醒:*arg 和 **arg可以为空值.
以下举例说明上述规则:

复制代码代码如下:

#arg, *arg和**arg作用举例
def test2(a,*b,**c):
print a,b,c
#---------------------------
#*arg 和 **arg可以不传递参数
>>> test2(1)
1 ()
#arg必须传递参数
>>> test2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test2() takes at least 1 argument (0 given)
#----------------------------
#*arg将顺positional_args转换为列表
>>> test2(1,2,[1,2],'a':1,'b':2)
1 (2, [1, 2], 'a': 1, 'b': 2)
#该处理等价于
a = 1 #arg参数处理
b = 2,[1,2],'a':1,'b':2 #*arg参数处理
c = dict() #**arg参数处理
print a,b,c
#-----------------------------
#**arg将keyword_args转换为字典
>>> test2(1,2,3,d=1:2,3:4, c=12, b=1)
1 (2, 3) 'c': 12, 'b': 1, 'd': 1: 2, 3: 4
#该处理等价于
a = 1 #arg参数处理
b= 2,3 #*arg参数处理
#**arg参数处理
c = dict()
c['d'] = 1:2, 3:4
c['c'] = 12
c['b'] = 1
print a,b,c

2. 处理顺序问题
函数总是先处理arg类型参数,再处理*arg和**arg类型的参数. 因为*arg和**arg针对的调用参数类型不同,所以不需要考虑他们得顺序.

复制代码代码如下:

def test2(a,*b,**c):
print a,b,c
>>> test2(1, b=[1,2,3], c=1:2, 3:4,a=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: test2() got multiple values for keyword argument 'a'
#这里会报错得原因是,总是先处理arg类型得参数
#该函数调用等价于
#处理arg类型参数:
a = 1
a = 1 #多次赋值,导致异常
#处理其他类型参数
...
print a,b,c

闭包
python的函数,原本只能访问两个区域的变量:全局,和局部(函数上下文). 实际上,函数本身也是一个对象,也有自己的作用域. 闭包通过函数与引用集合的组合,使得函数可以在它被定义的区域之外执行. 这个集合可以通过func_closure来获取这个引用集合. 这与python处理全局变量得方式一样,只不过全局变量将引用集合存储在__globals__字段中.func_closure是一个存储cell类型的元组,每个cell存储一个上下文变量.
另外,旧版本得python的内部函数不能在其他作用域使用的原因,并不是因为每个作用域的变量严格相互隔离,而是脱离原本的作用域后,函数失去了原本上下文的引用。需要注意的是,闭包存储的上下文信息一样是浅拷贝,所以传递给内部函数的可变对象仍然会被其他拥有该对象引用得变量修改.
举个例子:

复制代码代码如下:

>>> def foo(x,y):
... def bar():
... print x,y
... return bar
...
#查看func_closure的引用信息
>>> a = [1,2]
>>> b = foo(a,0)
>>> b.func_closure[0].cell_contents
[1, 2]
>>> b.func_closure[1].cell_contents
0
>>> b()
[1, 2] 0
#可变对象仍然能被修改
>>> a.append(3)
>>> b.func_closure[0].cell_contents
[1, 2, 3]
>>> b()
[1, 2, 3] 0

JAVA继承问题,实际参数列表与形式参数列表长度不同怎么解决

import java.lang.Math;

class Cylinder
public double radius,height;
public Cylinder(double radius,double height)
this.radius=radius;
this.height=height;

double superficialarea()
return 2*Math.PI*radius*radius+2*Math.PI*radius*height;

double volume()
return Math.PI*radius*radius*height;

void show()
System.out.println("圆柱体的表面积:"+superficialarea()+"圆柱体的体积:"+volume());



class Ringcylinder extends Cylinder
double innerradius;
public Ringcylinder(double radius,double height,double innerradius)
this.radius=radius;
this.height=height;
this.innerradius=innerradius;

void setinnerradius(double innerradius)
this.innerradius=innerradius;

double superficialarea()
return 2*(Math.PI*radius*radius-Math.PI*innerradius*innerradius)+2*Math.PI*(radius+innerradius)*height;

double volume()
return Math.PI*(radius*radius-innerradius*innerradius)*height;

void show()
System.out.println("环柱体的表面积:"+superficialarea()+"环柱体的体积:"+volume());



public class Test
public static void main(String[] args)
Cylinder a=new Cylinder(5,10);
a.show();
Ringcylinder b=new Ringcylinder(5,10,1);
b.show();

public Ringcylinder(double radius,double height,double innerradius)
this.radius=radius;
this.height=height;
this.innerradius=innerradius;


这个构造函数虽然定义了radius, height, innerradius,但在print之前没有给构造函数传入这个几个参数,所以导致出现此问题,再调用print之前,可以设置Ringcylinder(0.5,3,1),这样构造函数才能进行初始化全局变量,全局变量才能计算。不然首先没有参数为空的构造函数,有没有将参数传入,必然会报错。
参考技术A Cylinder缺少一个空参构造函数
public Cylinder()
super();


因为在Ringcylinder的构造函数中会默认调用
super();
而Cylinder不存在该构造函数所以报错。本回答被提问者和网友采纳
参考技术B 首先,构造函数时可以重载的,可以解决你的标题中的问题

而,你的代码中的问题并不像你的标题那样,这是因为继承中,基类没有办法构造造成的(基类没有默认构造函数,或者没有给基类提供参数)。
参考技术C 在Cylinder类中写个什么参数都不带的构造方法就完美了

以上是关于python3.5类型参数列表问题,怎么解决的主要内容,如果未能解决你的问题,请参考以下文章

python3.5中,无法numpy怎么解决?

python3.5中,无法numpy怎么解决

Python3.5学习笔记-列表元组字典

如何切换python版本

Tkinter 和 python3.5 的导入错误

Swift,无法使用类型参数列表调用 objc_setAssociatedObject