python类中的初始化问题
来源:互联网 发布:傻瓜p图软件 编辑:程序博客网 时间:2024/05/02 04:45
最近在学python的GUI编程,遇到一个问题。
报错内容: super(Application,self).__init__(master)
TypeError: must be type, not classobj
代码如下:
from Tkinter import *
#基于Frame框架的Application类
class Application(Frame):
def __init__(self,master):
super(Application,self).__init__(master)
self.grid()
root = Tk()
root.geometry("800x600")
app =Application(root)
#调用根窗口的时间循环,目的是启动GUI并保持其运行状态
root.mainloop()
查了资料发现的原因是:
早期的python继承体系中,对父类初始化并没有使用super(Application,self).__init__(master)这种方式,相对于其上例子,而是直接使用Frame.__init__(self,master)方式。
这是为什么?看Tkinter库的源代码,Frame类是继承Widget类,而Widget是继承类BaseWidget, Pack, Place,Grid,这四个类所继承的基类都有类似class Clazz:这样的写法
在Python早期中以这样形式(super(Application,self).__init__(master))执行父类初始化工作是不存在的。stackoverflow上说:Old-style classes (also known as"classic" classes) are always of type classobj; new-styleclasses are of type type.
就是说早期类是classobj类型的,而新类是type类型的。而super()返回一个特殊对象,这个对象类型与以前的对象类型是不兼容的,所以才会报错。从这都可以看出来,Tkinter是多么的古老。
看看这两种构造初始化方法的区别:
1. Frame.__init__(self,master)。
2. super(Application,self).__init__(master)
像第一种方法,指明父类进行初始化,显示出对不同父类初始化,这种语法更加的明确,但是却是有问题的:
class Test0(object):
def __init__(self):
print("这是Test0的初始化方法")
class Test1(Test0):
def __init__(self):
Test0.__init__(self)
print("这是Test1的初始化方法")
class Test2(Test0):
def __init__(self):
Test0.__init__(self)
print("这是Test2的初始化方法")
class Test3(Test2,Test1):
def __init__(self):
Test2.__init__(self)
Test1.__init__(self)
test = Test3()
输出结果:
这是Test0的初始化方法
这是Test2的初始化方法
这是Test0的初始化方法
这是Test1的初始化方法
注意: 基类(Test0)进行了两次初始化,这就是多继承产生的问题,也就是钻石形状问题。
而super()这种方式正好解决了钻石形状问题,如下代码所示:
class Test0(object):
def __init__(self):
super(Test0,self).__init__()
print("这是Test0的初始化方法")
class Test1(Test0):
def __init__(self):
super(Test1,self).__init__()
print("这是Test1的初始化方法")
class Test2(Test0):
def __init__(self):
super(Test2,self).__init__()
print("这是Test2的初始化方法")
class Test3(Test2,Test1):
def __init__(self):
super(Test3,self).__init__()
test = Test3()
输出结果:
这是Test0的初始化方法
这是Test1的初始化方法
这是Test2的初始化方法
从上面的这个例子看出,在多继承的初始化过程中,会生成一个列表,这个列表里有该类继承的所有父类,但是每个类只会出现一次。所以解决了父类重复初始化的问题。
这个方法虽然解决了问题,但是,当继承多个类时,就无法对所有的父类统一进行初始化了,如下代码:
class Test0(object):def __init__(self,name0):
self.name0 = name0
class Test1(object):
def __init__(self,name):
self.name = name
class Test2(Test1,Test0):
def __init__(self,master):
super(Test2,self).__init__(master)
test2 = Test2("name2")
print (test2.name)
print (test2.name0)
输出显示:
Traceback (most recent call last):
File "F:\new_android_workspace\firstpro\src\main\test4.py", line 18, in <module>
实例
print (test2.name0)
AttributeError: 'Test2' object has no attribute 'name0'
以上代码使用super()初始化,只会默认执行继承列表中的第一个类的init方法,所以特性name是有值的,name0是没有值的。
在多继承的初始化过程中,生成一个列表时,这个列表里有该类继承的所有父类,当访问父类的成员时(例如__init__()方法),会从这个列表里进行查找,直到找到某个父类拥有这个成员为止,执行这种查找也有一个条件,即每一个init方法中必须要有一个super()方法“启动“列表中下一个类的init方法。
如下代码所示:
class Test0(object):
def __init__(self):
super(Test0,self).__init__()
print "执行了Test0的初始化"
class Test1(object):
def __init__(self):
#super(Test1,self).__init__()
print "执行了test1的初始化"
class Test2(Test1,Test0):
def __init__(self):
super(Test2,self).__init__()
test2 = Test2()
输出显示:
#执行了Test0的初始化
执行了test1的初始化
注意: 如果隐藏了绿色的这行代码,那么输出结果中的绿色代码也不会显示了。
如下代码:
class Test0(object):
def __init__(self,name0,name1):
self.name0 = name0
self.name1 = name1
class Test1(object):
def __init__(self,name):
self.name = name
class Test2(Test1,Test0):
def __init__(self,name1,name2):
super(Test2,self).__init__(name1,name2)
test2 = Test2("name0","name2")
print test2.name0
print test2.name1
输出显示:
Traceback (most recent call last):
File "F:\new_android_workspace\firstpro\src\main\test4.py", line 18, in <module>
test2 = Test2("name0","name2")
File "F:\new_android_workspace\firstpro\src\main\test4.py", line 17, in __init__
super(Test2,self).__init__(master,master1)
TypeError: __init__() takes exactly 2 arguments (3 given)
错误提示表明test2= Test2("name0","name2")语句只调用了Test1的init方法,想通过类似java的方法重载来实现调用相应的父类初始化是不可行的。
如果你看到Test1中缺少了super语句,确实,在python的多继承体系中,super方法在以上所说的生成的父类列表中还充当连接下一个类的角色,但是,如果在Test1中加入super语句,那么该super语句,将需要严格按照列表中下一个类的参数进行匹配。也就是如下所示的更改:
class Test0(object):
def __init__(self,name0,name1):
self.name0 = name0
self.name1 = name1
class Test1(object):
def __init__(self,name1,name2):
super(Test1,self).__init__(name1,name2)
class Test2(Test1,Test0):
def __init__(self,name1,name2):
super(Test2,self).__init__(name1,name2)
test2 = Test2("name0","name1")
print test2.name0
print test2.name1
输出显示:
name0
name1
如果是这样就执行了初始化,但感觉还是有点别扭,不过使用单继承会好一些。
- python类中的初始化问题
- 类文件中的stage初始化问题
- java中的初始化问题
- 继承中的初始化问题
- java中的初始化问题
- 转载 c++中的初始化问题
- java中的初始化次序问题
- 学习python出现的问题_类初始化
- Struts2之ActionContext在Action类中的初始化问题
- python初始化二维数组的小问题
- 类的初始化问题
- 类的初始化问题
- 类的初始化问题
- ArcIMS 中的javaConnector初始化Map问题
- 谈谈JAVA中的循环初始化问题
- NxOgre中的TimeController初始化位置问题
- 谈谈JAVA中的循环初始化问题
- C语言中的数组初始化问题
- jdk/java版本与Android源码编译中的错误
- equals方法
- Volley解析
- 归并排序求逆序数
- Hdu 1877 又一版 A+B【水题+1】
- python类中的初始化问题
- 通过回调,Fragment向Activity传递信息
- 空间索引结构比较RTree R* Tree TPR Tree TPR* Tree
- 网络连接——WebView
- NIOS开发遇到的error整理
- 道德绑架,人情绑架
- java中instanceof用法
- jvm里面有两个存储区,一个是暂存区,另一个是变量区。而C++只有一个
- AJAX传值时,返回值类型