当前位置:首页 » 编程语言 » python经典类和新式类

python经典类和新式类

发布时间: 2023-09-21 22:59:08

python2.7.3和3.3.2的区别

转自:http://my.oschina.net/chihz/blog/123437
这边只说明面向对象方面的,其他方面见上面链接

面向对象
(1) 经典类和新式类
Python OO最神奇的地方就是有两种类,经典类和新式类。
新式类跟经典类的差别主要是以下几点:
1. 新式类对象可以直接通过__class__属性获取自身类型:type
2. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序: 先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动
3. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。
4. 新式类增加了__getattribute__方法
Python 2.x中默认都是经典类,只有显式继承了object才是新式类
Python 3.x中默认都是新式类,不必显式的继承object
python 2.x:
>>> ClassicClass.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
AttributeError: class ClassicClass has no attribute '__class__'
>>> class NewClass(object):
... pass
...
>>> NewClass.__class__

python 3.x:
>>> class NewClass:pass
...
>>> NewClass.__class__
<class 'type'>
(2) 无绑定方法
在Python 2.x中除了类方法和静态方法,其余的方法都必须在第一个参数传递self跟实例绑定,但是在Python 3.x中废除了这条规定,允许方法不绑定实例,这样的方法跟普通的函数没有区别:
Python 2.x:
>>> class MyClass:
... def function():
... print "function"
...
>>> MyClass.function()
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
TypeError: unbound method function() must be called with MyClass instance as first argument (got nothing instead)
>>> m = MyClass()
>>> m.function()
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
TypeError: function() takes no arguments (1 given)
Python 3.x:
>>> class MyClass:
... def function():
... print("function")
...
>>> MyClass.function()
function
>>> m = MyClass()
>>> m.function()
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
TypeError: function() takes no arguments (1 given)
(3) 重要的重载
1. next()和__next__():这应该是继print之后第二大坑爹的不兼容吧,Python程序漫山遍野都是迭代器,但是2和3之间迭代器的实现接口方法名是不同的……嗯,啥都不说了。
2. 分片拦截:Python 3.x之前, 类可以定义__getslice__和__setslice__方法来专门拦截分片,并且这两个方法优先于__getitem__和__setitem__, 但是Python 3.x时代这俩方法再也不存在了,全部的工作都交给了__getitem__和__setitem__,因此在使用这两个方法之前要先判断传递进参数的类型是不是slice对象。
3. __bool__方法:我们知道Python中默认将所有的空对象定义为布尔意义上的False,在自己定义的类中我们也可以加入自定义的布尔判断标准,在2.x中这个方法名叫做__nonzero__, 这个名字显然非常不直观并且不科学!所有考试交白卷的孩子我们都要否定他们的才能么?显然不能!因此Python 3.x中这个方法被重名命为__bool__
4. 3.x 取消了用于大小比较的__cmp__方法,取而代之的是:__lt__、__gt__、__le__、__ge__、__eq__、__ne__,嗯,我感觉这个想法真是不能苟同……有谁能说服我给我洗脑让我爱上这一堆__lt__、__gt__、__le__、__ge__、__eq__、__ne__么。。。
(4) 类修饰器
在我的上一篇博客中秀了一把函数装饰器在表单验证中的使用,http://my.oschina.net/chihz/blog/122897
在3.x的时代,类也有装饰器了,这个装饰器威力巨大,能把装饰的类搞的面目全非,总之想怎么搞就怎么搞,用法同函数装饰器基本一致,只不过传递的参数是类型:
>>> def shutdown(cls):
... def shutdown_func(self):
... print("do something...")
... cls.shutdown = shutdown_func
... return cls
...
>>> @shutdown
... class Test:pass
...
>>> t = Test()
>>> t.shutdown()
do something...

异常

先来看一段代码
python 2.x:
>>> class Person:
... def __init__(self, msg):
... self.msg = msg
...
>>> try:
... raise Person, "woca"
... except Person as p:
... print p.msg
...
woca
python 3.x:
>>> class Person:
... def __init__(self, msg):
... self.msg = msg
...
>>> try:
... raise Person("woca")
... except Person as p:
... print(p.msg)
Traceback (most recent call last):
File "<stdin>", line 2, in <mole>
TypeError: exceptions must derive from BaseException

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 3, in <mole>
TypeError: catching classes that do not inherit from BaseException is not allowed
>>>
接下来说不同:
1. 在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。
2. 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。
在2.x时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在3.x中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。

❷ python中①class a: pass ②class a(): pass ③class a(object): pass 这三种有什么区别吗

没有区别,只是语法比较自由,类默认就是继承于 object对象的。

❸ python入门需要学哪些

初学者学习Python需循序渐进,可以从以下内容入手学习:

1.Python基础知识

学习任何一门编程语言都需要学习相关语法知识,Python基础知识的学习主要包括Python解释器执行原理、字符编码、注释、变量、缩进、流程控制、文件操作、数据类型、数据类型内置方法、字符串格式化、运算符、输入输出、三元运算、collections、列表、字典、元组、集合、IO操作、文件增删改查、函数等。

5.数据库缓存、队列

Python数据库、缓存、队列学习内容为Python操作redis、Python操作memcache、rabbitMQ消息队列、数据库介绍、mysql数据库安装使用、mysql管理、mysql数据类型、常用mysql命令、创建数据库、外键、增删改查表、权限、事务、索引、Python操作mysql等。

6.Web开发基础

Python之Web开发基础学习内容为HTML基础、CSS基础、JavaScript基础、局部变量和全局变量、集合、数组、字典、函数参数、原型、面向对象、作用域、dom编程、jquery介绍、jquery选择器、jquery属性和CSS操作、jquery文档处理、jquery筛选、jquery事件托管、jquery事件、jquery ajax、jquery扩展方法、bootstrap使用、EasyUI介绍和使用等。

7.Web框架学习

Python之Web框架学习内容为Web框架本质、socket服务器、基于反射的路由系统、WSGI介凯闭行绍及原理实现态御、开发自己的Web框架、MVC和MTV、路由系统、模板、django基础学习与使用、普通路由和动态路由、模板引擎、ORM介绍、Django ORM增删改查学习、自定义tag、django进阶学习与使用、模型绑定、Form表单验证、Django ORM进阶学习、ModelForm、自定义Validator等。

❹ 又来求助了,大神求解答 python类继承的问题

老式类就是经典类,不是继承自object类.在多继承时采用深度优先遍历父类.
新式类就是基类继承自object类 class xxx(object).多继承时采用一种新的C3 算法来遍历父类.
实例如下:

新式类的打配绝印结果如下:

1speak: I am mother

旧式类的打印结果如下:

1speak: I am GrandFather

由此我们可以看出新式类的搜索过程为:Son-->Father-->Mother,而旧式类的搜索过程为:Son-->Father-->GrandFather

我们可以看出旧式类和我们预期的继承不太一样。

老式类就是经典类,不是继承自object类.在多继承时采用深度优先遍历父类.
新式类就是基类继承自object类 class xxx(object).多继承时采用一种新的C3 算法来遍历父类.

为什么采用C3算法呢?

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

本地优先级:指声明时父类的顺序,比如C(A,B),如果培亏姿访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。

单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

为了解释C3算法,我们引入了mro(mro即 method resolution order (方法解释顺序),主要用于在多继承时判断属性的路径(来自于哪个类))。

我们可以通过class.mro()来查看python类的mro

C3算法
判断mro要先确定一个线性序列,然后查找路径由由序列中类的顺序决定。所以C3算法就是生成一个线性序列。
如果继承至一个基类:
class B(A)
这时B的mro序列为[B,A]

如果继承至多个基类
class B(A1,A2,A3 ...)
这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])


merge操作就是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。
merge操作后的序列,继续执行merge操作,直到merge操作的序列为空。
如果merge操作的序列无法为空,则说明不合法。

例子:
class A(O):pass
class B(O):pass
class C(O):pass
class E(A,B):pass
class F(B,C):pass
class G(E,F):pass

A、B、C都继承至一个基类,所以mro序列依次为[A,O]、[B,O]、[C,O]
mro(E) = [E] + merge(mro(A), mro(B), [A,B])
= [E] + merge([A,O], [B,O], [A,B])
执行merge操作的序列为[A,O]、[B,O]、[A,B]
A是序列[A,O]中的第空拿一个元素,在序列[B,O]中不出现,在序列[A,B]中也是第一个元素,所以从执行merge操作的序列([A,O]、[B,O]、[A,B])中删除A,合并到当前mro,[E]中。
mro(E) = [E,A] + merge([O], [B,O], [B])
再执行merge操作,O是序列[O]中的第一个元素,但O在序列[B,O]中出现并且不是其中第一个元素。继续查看[B,O]的第一个元素B,B满足条件,所以从执行merge操作的序列中删除B,合并到[E, A]中。
mro(E) = [E,A,B] + merge([O], [O])
= [E,A,B,O]

❺ 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中object has no attribute是什么问题

没有继承Object。

首先什么是新式类 经典类呢:

#新式类是指继承object的类

class A(obect):

#经典类是指没有继承object的类

class A:

Python中推荐大家使用新式类 1.新的肯定好哈,已经兼容经典类

2.修复了经典类中多继承出现的bug

下面我们着重说一下多继承的bug 如图:

BC 为A的子类, D为BC的子类 ,A中有save方法,C对其进行了重写

在经典类中 调用D的save方法 搜索按深度优先 路径B-A-C, 执行的为A中save 显然不合理

在新式类的 调用D的save方法 搜索按广度优先 路径B-C-A, 执行的为C中save

#经典类

class A:

def __init__(self):

print 'this is A'

def save(self):

print 'come from A'

class B(A):

def __init__(self):

print 'this is B'

class C(A):

def __init__(self):

print 'this is C'

def save(self):

print 'come from C'

class D(B,C):

def __init__(self):

print 'this is D'

d1=D()

d1.save() #结果为'come from A

#新式类

class A(object):

def __init__(self):

print 'this is A'

def save(self):

print 'come from A'

class B(A):

def __init__(self):

print 'this is B'

class C(A):

def __init__(self):

print 'this is C'

def save(self):

print 'come from C'

class D(B,C):

def __init__(self):

print 'this is D'

d1=D()

d1.save() #结果为'come from C'

热点内容
大数据与数据库的关系 发布:2025-03-07 08:48:20 浏览:288
取幂C语言 发布:2025-03-07 08:43:10 浏览:488
高考解压性 发布:2025-03-07 08:43:10 浏览:690
搜狐广告服务器是什么 发布:2025-03-07 08:36:45 浏览:147
csgo稳定fps要什么配置 发布:2025-03-07 08:35:01 浏览:404
matlab粒子群优化算法 发布:2025-03-07 08:13:49 浏览:249
编译原理翻译 发布:2025-03-07 08:08:01 浏览:592
安卓光遇测试服为什么服务器错误 发布:2025-03-07 08:05:53 浏览:550
火狐缓存文件夹 发布:2025-03-07 08:05:51 浏览:113
代码编程库 发布:2025-03-07 08:05:09 浏览:182