Beginning Python Chapter5

  • python用异常对象来表示异常情况,遇到错误后,会引发异常,如果异常对象未被处理或捕捉,程序就会用所谓的回溯(Traceback)种植执行
  • python中可以使用raise抛出一个异常
def raiseerr():
    raise Exception

raiseerr()
  • 内建的异常类型
类名描述
Exception所有异常的基类
AtributeeError特性引用或赋值失败时引发
IOError试图打开不存在的文件时引发
IndexError在使用序列中不存在的索引时引发
KeyError在使用映射中不存在的键时引发
NameError在找不到名字(变量)时引发
SyntaxError在代码为错误形式时引发
TypeError在类型错误时引发
ValueError对象的值不适合时引发
ZeroDivisionError除数为0时引发

* python捕获异常使用try….except来捕获

def raiseerr():
    raise Exception('error')

try:
    raiseerr()
except Exception, e:
    print e.message
finally:
    print 'end'

error
end

如果捕获到异常之后想要重新触发,需要使用不带参数的raise

def raiseerr():
    raise Exception('error')

try:
    raiseerr()
except Exception, e:
    raise
finally:
    print 'end'

捕获异常时可以指定多个except子句。try…except (IOError, KeyError,….) , e:

  • 为了确保类为新型类有两种方法 1.将赋值语句__metaclass__=type放在模块的最开始,2. 类从object继承 class test(object): ....
  • 类的构造方法和其他普通方法的不同之处在于,当一个对象被创建之后会立即调用构造方法,python构造方法的名为 __init__, python中有一个方法叫做__del__这个方法被称为析构函数, 他在对象就要被垃圾回收之前调用,但是具体发生调用的时间不确定,所以需要尽力避免使用__del__

  • 继承
    基类:python中继承时,如果在基类的构造函数中声明 self.a self.b self.c
    派生类: 派生类中继承基类,重写自己的构造函数时,基类的构造函数会被覆盖

class A:
    def __init__(self):
        self.a=None
        self.b=None
    def fun(self):
        print self.a

class B(A):
    def __init__(self):
        self.c=None
    def test():
        print self.c

b=B()
b.fun()
调用函数时报错,提示self.a未定义 AttributeError: B instance has no attribute 'a'

为了解决这个问题,B的构造方法必须调用它的基类的构造方法。有两种方式可以实现,直接调用基类的构造函数,或者使用supper函数

class A:
    def __init__(self):
        self.a=None
        self.b=None
    def fun(self):
        print self.a

class B(A):
    def __init__(self):
        A.__init__(self) #self这个参数不能少
        self.c=None
        def test():
            print self.c

b = B()
b.fun()
__metaclass__=type
class A:
    def __init__(self):
        self.a=None
        self.b=None
    def fun(self):
        print self.a

class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.c=None
        def test():
            print self.c

b = B()
b.fun()

使用super函数必须指定__metaclass__=type 否则 super(B, self).__init__()
TypeError: must be type, not classobj
. 在多继承时使用super比较方便,super函数实际上是很智能的,因此即使类已经继承多个超类,他也只需要使用一次super函数。

__metaclass__=type
class A:
    def __init__(self):
        self.a = None
class B:
    def __init__(self):
        self.b = None
class C(A, B):
    def __init__(self):
        super(C, self).__init__()
        self.c = None
    def fun(self):
        print self.a, self.b, self.c


c = C()
c.fun()
AttributeError: 'C' object has no attribute 'b' 
并没有执行成功,如果不输出b的值程序正常运行,这样开来super只调用了A的构造函数,那该如何解决这个问题呢?
__metaclass__=type
class A:
    def __init__(self):
        super(A, self).__init__()
        self.a = None
class B:
    def __init__(self):
        super(B, self).__init__()
        self.b = None
class C(A, B):
    def __init__(self):
        super(C, self).__init__()
        self.c = None
    def fun(self):
        print self.a, self.b, self.c


c = C()
c.fun()

下面对Python多重继承的异构构造进行说明,下面说明引用http://blog.ptsang.net/constructors_with_different_arguments_in_python_multiinheri_class
下面是说明的详细内容

WhatPython里面,如果你使用上QtSQLAlchemyTwisted之类各种大型类库时候,有时候多重继承Multiple Inheritance是个简单的解决方法,但是多重继承的复杂性总容易造成误解和疑惑。

一般“常识”说,使用super访问父类的属性/方法,这种说法在多重继承里面是不成立的,多重继承的类并没有父类的概念(There is no superclass in a MI world)。类似的博客在过去几年被人写了无数遍了,因为过去版本里面python官方文档对super的解释非常有限而且有误导解释,直到2.6以后的文档,才详细说明了super在单继承和多继承的两种不同工作方式。当时苦逼的程序员甚至不得不去翻看Python源码才搞清楚是什么回事。以致几年来很多人对python的多重继承保持怀疑态度。

Python多重继承使用Method Resolution Order的动态算法来解决一个方法名的调用顺序,mro其实说来简单,就是一个深度优先的继承列表,很易理解,但随之来的是遇到互不相同的构造器__init__参数的问题。

class A(object):
    def __init__(self, arg1):
        print "init func in A, with arg1 '%s'" % arg1
        super(A, self).__init__()

class B(object):
    def __init__(self, arg1, arg2):
        print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        super(B, self).__init__(arg1)

class C(B, A):
    def __init__(self, arg1, arg2):
        print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        super(C, self).__init__(arg1, arg2)
        print C.__mro__

c = C("C's arg1", "C's arg2")

执行结果:

init func in C, with arg1'C's arg1', arg2 'C's arg2'
init func in B, with arg1'C's arg1', arg2 'C's arg2'
init func in A, with arg1 'C's arg1'
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
可见几个类的构造器的执行顺序正是mro列表的顺序。重点是多重继承的各个类的构造器__init__之所以能够执行,是因为每个构造器里面都有一句super(),这个super完成mro列表中下一个类的构造器的调用。

这个事实听起来似乎很自然,但看代码,B的构造器还得必须知道A的构造器的参数?B需要知道自己将会被C同时继承A,并且调用A的构造?!!很荒谬,但不幸的这是mro的特点。代码是可以这么写,但不应该,为另一个不知道什么时候会被一起继承的类特地地写代码,跟面对对象设计的解耦原则相违背。

How

在mro方式的基础上,这个问题是不可能有效解决的,只能避免。概括起来大概有这么 两种方式。

1.使用传统类的方式,显式调用被继承类的构造器,避开super的mro自动化工作。


class A(object):
    def __init__(self, arg1):
        print "init func in A, with arg1 '%s'" % arg1

class B(object):
    def __init__(self, arg1, arg2):
        print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)

class C(A, B):
    def __init__(self, arg1, arg2):
        print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        #super(C, self).__init__(arg1) #这两行
        A.__init__(self, arg1)       #等价
        B.__init__(self, arg1, arg2)
        print C.__mro__

c = C("C's arg1", "C's arg2")
注意 C继承A,B的顺序已经改变。

要排除一个容易产生的误解。Python文档里面的super有个很显著的Note:super() only works for new-style classes. super只适用于新类。但新类并不必须使用super。

直接调用被继承类的__init__作为unbound方法调用,需要指定一个实例,如self作为参数,依次调用各个被继承类。缺点是若果这几个被继承类也在构造方法里面使用这样调用了同一个上级被继承类,会出现“爷爷类”的构造方法被调用多次的情况。

如果一定使用super,要注意继承列表的顺序。super(TYPE, self).method调用的是mro列表中第一个,也即继承列表第一个类的方法。

PyQt里面的类内部一般(未细究)都使用__init__的方式来初始化代码,因而很多PyQt的例子代码都是使用QtGui.QMainWindow.__init__(self)这样的代码来初始化。当然在单继承时候和super的写法是等价的,但最好使用统一的原则:

一个简单好记的原则:

如果"被继承类"都使用__init__,"继承类"就使用__init__来初始化;
如果"被继承类"都使用super,"继承类"就使用super来初始化;
2.使用Composition / Association Pattern的设计模式(即'Is-A'转换成'Has-A')来实现相同功能,避免多重继承。

这个方法听起来未免有点让人不快(破坏了原有设计思维),但实际上很可能这是更好的方式,更清晰的代码,尤其是要继承的类里面混合了使用super,__init__两种初始化方式的时候。
  • 在python中直接跟在类名后面的变量认为是静态变量,在__init__中定义的为类的内部变量。
__metaclass__=type
class A:
    a = 1
    b = 2
    def __init__(self):
        self.c = '111'
        self.d = '222'
    def fun(self):
        print self.a, self.b, self.c, self.d, A.a, A.b
    def fun2(self):
        print A.c, A.d

a = A()
b = A()

a.fun()
b.fun()

A.a = 111
A.b = 222

a.fun()
b.fun()

a.a = 111
a.b = 222

a.fun()
b.fun()

a.fun2() # AttributeError: type object 'A' has no attribute 'c'

1 2 111 222 1 2
1 2 111 222 1 2
111 222 111 222 111 222
111 222 111 222 111 222
111 222 111 222 111 222
111 222 111 222 111 222
  • 在导入模块的时候可以增加python的搜索路径,

    import sys
    sys.path.append('C:/python')
    这句话的作用是告诉编译器除了在默认路径下搜索模块以外还要在C:/python目录下搜索导入的模块,
    • python中的模块支持重复导入,但是效果只有一次,具体操作方法
      reload(modelname) reload在python3.0里已经丢弃了
      在编写模块时可能需要使用测试语句,那测试语句的格式if __name__ == '__main__': ....
  • 查看模块中包含的内容可以使用dir(modelname)
    这里写图片描述
    这里写图片描述
    在copy模块中可以看到__all__属性, copy.__all__输出结果只有 Error, copy,deepcopy三个
    在使用from copy import *时候,可以导入的只有__all__的输出信息。其他函数并不能导入,之前也有提过,下划线开头的函数不能被其他模块导入

  • 文件操作
    input 只能输出数字,输入非数字类型,异常
    raw_input 输入数据会被转换为字符串处理

  • open函数def open(name, mode=None, buffering=None)
    open函数可以指定缓冲区大小,如果第三个参数为0,或者是False,表示无缓冲,
    如果是1或者True,标识有缓冲,使用flush或者close时会将数据刷入文件
    如果参数大于1标识缓冲区的大小, 单位是字节
    如果参数为-1 标识默认的缓冲区大小
  • tell 返回当前文件的位置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值