Python新类
Ⅰ python中的旧样式类和新样式类有什么区别
在Python 2.1之前,旧式类是用户可用的唯一样式。
(旧式)类的概念与类型的概念无关:如果x是旧式类的实例,则x.__class__指定的类x,但type(x)始终为<type
'instance'>。这反映了这样一个事实,即所有旧式实例(独立于其类)均使用称为实例的单个内置类型实现。在Python 2.2中引入了新的类,以统一class和type的概念。新型类只是用户定义的类型,不多也不少。如果x是新样式类的实例,则type(x)通常与x 相同x.__class__(尽管不能保证–允许新样式类实例覆盖为返回的值x.__class__)。
引入新型类的主要动机是提供具有完整元模型的统一对象模型。
它还具有许多直接的好处,例如能够对大多数内置类型进行子类化,或者引入了“描述符”,以启用计算属性。出于兼容性原因,默认情况下,类仍为旧样式。通过将另一个新样式类(即一种类型)指定为父类或“顶级类型”对象(如果不需要其他父类)来创建新样式类。
新样式类的行为与旧样式类的行为不同,除了返回什么类型外,还有许多重要的细节。其中一些更改是新对象模型的基础,例如调用特殊方法的方式。其他是出于兼容性考虑而无法实现的“修复程序”,例如在多重继承的情况下的方法解析顺序。
Python 3仅具有新型类。无论是否从中继承子类object,类都是Python 3中的新型样式。
Ⅱ 关于python的实例方法问题
题主你好,
python中创建新实例的时候, 如果相应的类中定义了__init__()方法的话, 会自动调用这个方法. 你可能认为名称"init"和"__init__"差不多, 但计算机其实是个很笨的东西, 它会完全按照设计去执行. 也就是说,在设计的时候就已经定死了, 默认情况下, 创建新实例的时候, 会自动调用类中定义的__init__()方法, 只要你的方法名和__init__有一点不一样也不行.
下图是我在官网上找的关于__init__()调用的简单说明:

高亮部分说的大概意思就是上面讲的,如果相应类中定义了__init__()方法,则在创建该类实例的时候会自动调用里面定义的__init__()方法.
-----
希望可以帮到题主, 欢迎追问.
Ⅲ Python类的多重继承问题深入分析
Python类的多重继承问题深入分析
首先得说明的是,Python的类分为经典类 和 新式类
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了
新式类在python2.2之后的版本中都可以使用
经典类和新式类的区别在于:
经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的:
代码如下:
# old style
class A():pass
# new style
class A(obejct):pass
2.经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的..而新式类是采用C3算法(不同于广度优先)进行匹配的
3.经典类是没有__MRO__和instance.mro()调用的,而新式类是有的.
为什么不用经典类,要更换到新式类
因为在经典类中的多重继承会有些问题...可能导致在继承树中的方法查询绕过后面的父类:
代码如下:
class A():
def foo1(self):
print "A"
class B(A):
def foo2(self):
pass
class C(A):
def foo1(self):
print "C"
class D(B, C):
pass
d = D()
d.foo1()
按照经典类的查找顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过.
所以python引入了新式类的厅扒塌概念,每个基类都继承自object并且,他的匹配此姿规则也从深度优先换到扮圆了C3
C3算法
C3算法是怎么做匹配的呢..在问答版块上面讨论之后,归结如下:
C3算法的一个核心是merge.
在merge列表中,如果第一个序列mro的第一个类是出现在其它序列,并且也是第一个,或者不出现其它序列,那么这个类就会从这些序列中删除,并合到访问顺序列表中
比如:(引用问题中zhuangzebo的回答@zhuangzebo)
代码如下:
class A(O):pass
class B(O):pass
class C(O):pass
class D(A,B):pass
class E(C,D):pass
首先需要知道 O(object)的mro(method resolution order)列表是[O,]
那么接下来是:
代码如下:
mro(A) = [A, O]
mro(B) = [B, O]
mro(C) = [C, O]
mro(D) = [D] + merge(mro(A), mro(B), [A, B])
= [D] + merge([A, O], [B, O], [A, B])
= [D, A] + merge([O], [B, O], [B])
= [D, A, B] + merge([O], [O])
= [D, A, B, O]
mro(E) = [E] + merge(mro(C), mro(D), [C, D])
= [E] + merge([C, O], [D, A, B, O], [C, D])
= [E, C] + merge([O], [D, A, B, O], [D])
= [E, C, D] + merge([O], [A, B, O])
= [E, C, D, A, B] + merge([O], [O])
= [E, C, D, A, B, O]
然后还有一种特殊情况:
比如:
merge(DO,CO,C) 先merge的是D
merge(DO,CO,C) 先merge的是C
意思就是.当出现有 一个类出现在两个序列的头(比如C) 这种情况和 这个类只有在一个序列的头(比如D) 这种情况同时出现的时候,按照顺序方式匹配。
新式类生成的访问序列被存储在一个叫MRO的只读列表中..
你可以使用instance.__MRO__或者instance.mro()来访问
最后匹配的时候就按照MRO序列的顺序去匹配了
C3和广度优先的区别:
举个例子就完全明白了:
代码如下:
class A(object):pass
class B(A):pass
class C(B):pass
class D(A):pass
class E(D):pass
class F(C, E):pass
按照广度优先遍历,F的MRO序列应该是[F,C,E,B,D,A]
但是C3是[F,E,D,C,B,A]
意思是你可以当做C3是在一条链路上深度遍历到和另外一条链路的交叉点,然后去深度遍历另外一条链路,最后遍历交叉点
新式类和经典类的super和按类名访问问题
在经典类中,你如果要访问父类的话,是用类名来访问的..
代码如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
A.__init__(self) #python不会默认调用父类的初始化函数的
这样子看起来没三问题,但是如果类的继承结构比较复杂,会导致代码的可维护性很差..
所以新式类推出了super这个东西...
代码如下:
class A():
def __init__(self):
print "A"
class B(A):
def __init__(self):
print "B"
super(B,self).__init__()
这时候,又有一个问题:当类是多重继承的时候,super访问的是哪一个类呢?
super实际上是通过__MRO__序列来确定访问哪一个类的...实际上就是调用__MRO__中此类后面的一个类的方法.
比如序列为[F,E,D,C,B,A]那么F中的super就是E,E的就是D
super和按照类名访问 混合使用带来的坑
代码如下:
class A(object):
def __init__(self):
print "enter A"
print "leave A"
class B(object):
def __init__(self):
print "enter B"
print "leave B"
class C(A):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
class D(A):
def __init__(self):
print "enter D"
super(D, self).__init__()
print "leave D"
class E(B, C):
def __init__(self):
print "enter E"
B.__init__(self)
C.__init__(self)
print "leave E"
class F(E, D):
def __init__(self):
print "enter F"
E.__init__(self)
D.__init__(self)
print "leave F"
这时候打印出来是:
代码如下:
enter F
enter E
enter B
leave B
enter C
enter D
enter A
leave A
leave D
leave C
leave E
enter D
enter A
leave A
leave D
leave F
可以看出来D和A的初始化函数被乱入了两次!
按类名访问就相当于C语言之前的GOTO语句...乱跳,然后再用super按顺序访问..就有问题了
所以建议就是要么一直用super,要么一直用按照类名访问
最佳实现:
避免多重继承
super使用一致
不要混用经典类和新式类
调用父类的时候注意检查类层次
以上便是本人对于python类的继承的认识了,希望对大家能有所帮助
Ⅳ 使用python的super时出现的TypeError: must be type, not classobj 原因及解决
示例如下:
但是运行报错:TypeError: must be type, not classobj
查找资料之后发现,python中super只能应用于袜拿睁新类,而不能应用于经典类
所谓新类 : 就是所有类都必须要有继承的类,如果什么都不想继承,就继承到告岁object类。下面是一个新类的例子
所谓经典类 : 就是什么都不用继承的类,例如:
产上上面的问题,而自己又不知道父类该继承什么,最简单的方法就是让它去继承object类敏谈,例如:
Ⅳ [Python]使用metaclass创建类对象
在Python中,使用metaclass创建类对象的过程可以概括为以下几个关键步骤:
定义元类:
- 创建一个类作为元类,这个类需要继承自type。
- 在这个元类中,可以实现控制类对象创建行为的特定逻辑,例如修改类属性或方法。
实现元类逻辑:
- 元类接收三个参数:类名、基类列表以及类属性字典。
- 通过这些参数,元类可以动态地创建和修改类对象。
指定元类:
- 在需要被元类控制的类定义中,使用metaclass=MyMetaClass来明确指定该类的元类。
创建类对象:
- 当Python解释器遇到指定了元类的类定义时,它会将类定义中的参数传递给元类。
- 元类根据这些参数创建并返回一个新的类对象。
重点内容: 元类是用于创建类对象的类。 自定义元类通常通过继承type类实现。 在类定义中使用metaclass关键字指定自定义元类。
通过自定义元类,可以实现对类创建过程的精细控制,例如动态添加类属性、修改类行为等,从而提高代码的灵活性和扩展性。但需要注意的是,过度使用或不当使用自定义元类可能会导致代码难以理解和维护,因此应谨慎使用。
