zoukankan      html  css  js  c++  java
  • Python学习笔记之面对象与错误处理

    反射

    __import__()函数用于加载类和函数
    
    __import__(name[, globals[, locals[, fromlist[, level]]]])
        参数说明:
            name -- 模块名
    
    getattr() 函数用于返回一个对象属性值。
    
    getattr(object, name[, default])
        参数
            object -- 对象。
            name -- 字符串,对象属性。
            default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
    
    执行 func()
    
    data = input("请输入地址:")
    array = data.split('/')
    userspace = __import__('backend'+array[0])
    model = getattr(userspance, array[0])
    func = getattr(model, array[1])
    func()
    
    
    # 应用于路由反射
    # Django扩展
    def activator(request, viewfile, view, action, arg):
        namespace = __import__(viewfile)
        module = getattr(namespace.Views, view)
        func = func(module, arg)
        result = func(action, arg)
        return result

    面对象

    # 理解Python之self
        首先明确的是self只有在类的方法中才会有,独立的函数或方法时不必带有self的。
        self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
        self名称不是必须的,在Python中self不是关键词,你可以定义成a或b或其他的名字都是可以的,
        但是和约定成俗,不要搞另类,大家会不明白的。
    
    
    ·self指的是类实例对象本身(注意:不是类本身)
    
    
    # __init__() 实例化一个动作,初始化类的属性
      类实例创建之后调用,对当前对象的实例的一些初始化,没有返回值
        ·这个方法一般用于初始一个类
        ·但是 当实例化一个类的时候,__init__并不是一个被调用的,第一个被调用的是__new__
    
    # __str__()
        ·这是一个内置方法,只能返回字符串,并且只能有一个参数self
    
    # __new__()  静态方法
        ·创建类实例的方法,创建对象时调用,返回当前对象的一个实例
        object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供
        __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法
    # -----------------------------------------
        1.__init__ 
        通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
        2.__new__     
        通常用于控制生成一个新实例的过程。它是类级别的方法。
        
        三、__new__ 的作用
            依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 
            提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass
            
        __init__方法通常用在设置不变数据类型的子类,注意在使用new方法的时候,调用了父类的new方法,并且返回了这个值,使用return语句 
        当不使用return的时候,那么此值会变成为None,也就是默认情况下返回值为None
    
    class PositiveInteger(int):
    
      def __new__(cls, value):
    
        return super(PositiveInteger, cls).__new__(cls, abs(value))
    
    i = PositiveInteger(-3)
    print(i)
        
    # __str__
        如果要把一个类的实例变成str,就需要实现特殊方法__str__()
        
    class Person(object):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
        def __str__(self):
            return '(Person: %s, %s)' % (self.name, self.gender)
        
    
    尽管str(),repr()和``运算在特性和功能方面都非常相似,事实上repr()和``做的是完全一样的事情,它们返回的是一个对象的“官方”字符串表示,
    也就是说绝大多数情况下可以通过求值运算(使用内建函数eval())重新得到该对象,但str()则有所不同。str()致力于生成一个对象的可读性好的字符串表示,
    它的返回结果通常无法用于eval()求值,但很适合用于print语句输出。需要再次提醒的是,并不是所有repr()返回的字符串都能够用 eval()内建函数得到原来的对象。 
    也就是说 repr() 输出对 Python比较友好,而str()的输出对用户比较友好。虽然如此,很多情况下这三者的输出仍然都是完全一样的。 
    
    str与repr区别:
    1、python中str函数通常把对象转换成字符串,即生成对象的可读性好的字符串,一般在输出文本时使用,或者用于合成字符串。str的输出对用户比较友好适合print输出。
    2、pyton中repr函数将一个对象转成类似源代码的字符串,只用于显示。repr的输出对python友好,适合eval函数得到原来的对象。
    3、在类中实现__str__和__repr__方法,就可以得到不同的返回
    
    #__setitem__  安装索引赋值
    
    # __getitem__ 按照索引获取值
    
    class A:
    
        def __init__(self):
            self.dict_num = {}
    
        def __setitem__(self, key, value):
            self.dict_num[key] = value
            return self.dict_num
    
        def __getitem__(self, item):
            return self.dict_num[item]
    
    
    a = A()
    a['name'] = 'jack'
    print(a.dict_num)
    print(a.dict_num['name'])
    
    》》》{'name': 'jack'}
    》》》jack
    
    # __len__ 获取长度
        如果一个类表现的像一个list,要获取多少个元素与,就得用len()函数
        要让len()函数正常工作,类必须提供一个特殊的方法__len__(),它返回元素的个数
    
    class Name(object):
        def __init__(self, *args):
            self.names = args
    
        def __len__(self):
            return len(self.names)
    
    n = Name(1, 2, 3)
    print(len(n))
    
    # __cmp__ 比较运算
        对int、str等内置数据类型排序时, Python的sorted()按照默认的比较函数cmp排序,但是,如果对一组student类的实例排序时,就必须提供我们自己的特殊方法__cmp__
    
    # __add_ 加运算
    
    # __sub__ 减运算
    
    # __mul__ 乘运算
    
    #__div__ 除运算
    
    #__mod__ 求余运算
    
    # __pow__ 乘方
    
    # __call__()
        ·对象通过提供一个__call__(self, *args, **kwargs)方法可以模拟
    函数的行为,如果一个对象提供该方法,可以向函数一样去调用它
    
    # __module__ 表示当前操作的对象在那个模块
    
    # __class__     表示当前操作的对象的类是什么
    
    # isinstance(obj, cls) 检查obj是否是类cls的对象
    class Foo(object):
        pass
    
    f = Foo()
    isinstance(f, Foo)
    
    # issubclass(sub, super) 检查sub类是否是super类的派生类
    class Foo(object):
        pass
    
    class Bar(Foo):
        pass
    
    issubclass(Bar, Foo)
    
    
    # ########################################
    静态字段(属于类的字段)
    动态字段(self.对象)
        ·属于类
        ·self.属于对象
        ·访问类.变量名,访问
    
    静态类不能访问动态字段
    实例化的对象可以访问静态字段
        ·尽量不要用实例化后的对象访问静态字段,造成歧义
    
    
    # #######################################
    静态方法:属于类
        @staticmethod,去掉self创建静态方法
        
    为什么要使用静态方法:
        ·Python 可以直接使用静态方法,而避免了去实例化一个对象。实例化对象需要消耗资源的,静态方法避免了这一切。
    
    实例化后的对象可以访问动态方法
    静态类不能访问动态方法啊、
    
    *****************************************
    Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还是有区别的:
    1)静态方法无需传入self参数,类成员方法需传入代表本类的cls参数;
    2)从第1条,静态方法是无法访问实例变量的,而类成员方法也同样无法访问实例变量,但可以访问类变量;
    3)静态方法有点像函数工具库的作用,而类成员方法则更接近类似Java面向对象概念中的静态方法。
    
    # #######################################
    特性/属性: @property把方法访问形式变成字段的访问形式
    方法 hb.bar()
    字段 hb.bar
        ·将类方法转换为只读属性
        ·重新实现一个属性的setter和getter方法
    
    # ######################################
    私有字段:self.__thailand = flag
    类外部无法访问
        AttributeError: 'A' object has no attribute '__thailand'
    
    私有方法:def __print():
                print('hello world')
    
    ***************************************
    
    class A:
        this_num = '123'
    
        def __init__(self, name, flag):
            self.__thailand = flag
            self.name = name
    
        def show(self):
            print(self.__thailand)
    
        @staticmethod
        def __print():
            print('hello world')
    
        def show_print(self):
            self.__print()
    
    if __name__ == '__main__':
        a = A('sx', True)
        print(a.name)
        a.show()
        a.show_print()
    
    ***************************************
        # 直接在外部调用私有方法字段
        a._A__print()
    
    # #####################################
    # 只读只写特性 
    class RW(object):
    
        def __init__(self, name):
            self.__name = name
    
        @property
        def show_name(self):
            """可读"""
            return self.__name
    
        @show_name.setter
        def show_name(self, value):
            """可写"""
            self.__name = value
    
    if __name__ == '__main__':
        jack = RW('JACK')
        print(jack.show_name)
        jack.show_name = 'KEVIN'
        print(jack.show_name)
    
    # ####################################
    
    垃圾回收机制
    Python 采用垃圾回收机制来清理不再使用的对象;Python 提供gc模块释放
    不再使用的对象,Python 采用‘引用计数’ 的算法方式来处理回收,
    即:当某个对象在其作用域内不再被其他对象引用的时候,Python 就自动清除对象;
    Python 的函数collect()可以一次性收集所有待处理的对象(gc.collect())
    
    # ####################################__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。
    __del__()也是可选的,如果不提供,则Python 会在后台提供默认析构函数
    
    注:一般用不上,使用场景:
        操作文件的时候,打开文件获取的句柄,打开之后一直没释放
        释放后销毁,释放的动作可以卸载del里面
    
    __del__:永远是最后执行的
    
    # ####################################
    __call__方法
        对象通过提供__call__(slef, [,*args [,**kwargs]])方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样使用它,
        也就是说x(arg1, arg2...) 等同于调用x.__call__(self, arg1, arg2) 。模拟函数的对象可以用于创建防函数(functor) 或代理(proxy)
    
    class F:
    
        def __init__(self):
            pass
    
        def __call__(self):
            print('call')
    
    if __name__ == '__main__':
        f1 = F()  # f1为实例化的对象
        f1()      # 默认执行Call方法
    
    # ####################################
    
    类的继承
        super()函数
                super() 函数用于调用下一个父类(超类)并返回该父类实例的方法。
                super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
    
    注意:super继承只能用于新式类,用于经典类时就会报错。
    新式类:必须有继承的类,如果没什么想继承的,那就继承object
    
    普通继承与super继承
    它们的内部运行机制不一样,这一点在多重继承时体现得很明显。在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照mro进行的(E.__mro__)。
    注意:super继承只能用于新式类,用于经典类时就会报错。
    新式类:必须有继承的类,如果没什么想继承的,那就继承object
    经典类:没有父类,如果此时调用super就会出现错误:『super() argument 1 must be type, not classobj』
    # ####################################
    python的多态指同一个方法,不通的行为。对于不同的类,可以有同名的两个或多个方法。取决于这些方法分别应用到哪些类,他们可以有不同的行为。
    
    当子类和父类都存在相同的 print_title()方法时,子类的 print_title() 覆盖了父类的 print_title(),在代码运行时,会调用子类的 print_title()
    
        这样,我们就获得了继承的另一个好处:多态。 
    
        多态的好处就是,当我们需要传入更多的子类,例如新增 Teenagers、Grownups 等时,我们只需要继承 Person 类型就可以了,
    而print_title()方法既可以直不重写(即使用Person的),也可以重写一个特有的。这就是多态的意思。调用方只管调用,不管细节,而当我们新增一种Person的子类时,
    只要确保新方法编写正确,而不用管原来的代码。这就是著名的“开闭”原则:
    
        对扩展开放(Open for extension):允许子类重写方法函数
        对修改封闭(Closed for modification):不重写,直接继承父类方法函数
    
    # ####################################
    
    多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
    、在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。
    也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数
    
    其实大家从上面多态性的例子可以看出,我们并没有增加上面新的知识,也就是说Python本身就是支持多态性的,这么做的好处是什么呢?
    (1)增加了程序的灵活性
      以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
    (2)增加了程序额可扩展性
      通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
    
     多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度) 多态性:一种调用方式,不同的执行效果(多态性)
    
    # ####################################
    
    多重继承
    除了从一个父类继承外,Python允许从多个父类继承,称为多重继承。
    
    多重继承的继承链就不是一棵树了,它像这样:
    
    class A(object):
        def __init__(self, a):
            print 'init A...'
            self.a = a
    
    class B(A):
        def __init__(self, a):
            super(B, self).__init__(a)
            print 'init B...'
    
    class C(A):
        def __init__(self, a):
            super(C, self).__init__(a)
            print 'init C...'
    
    class D(B, C):
        def __init__(self, a):
            super(D, self).__init__(a)
            print 'init D...'
    
    # ####################################
    
    “新式类”和“经典类”的区分在Python 3之后就已经不存在,
    在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。
    
    
    经典类和新式类的区别:
        ·继承object,新式类
        ·没有object,经典类
    
    新式类兼容经典类的功能
    新式类修复好了经典类的一个bug(面临经典类多继承的问题)
        1.类是可以多继承的
    
    class A:
    
        def __init__(self):
            print('A class')
    
        def save(self):
            print('A save')
    
    
    class B(A):
    
        def __init__(self):
            print('B class')
    
    
    class C(A):
    
        def __init__(self):
            print('C class')
    
        def save(self):
            """方法重写"""
            print('C save')
    
    
    class D(B, C):
    
        def __init__(self):
            print('D class')
    
    # D这时应该继承C的save方法
    # 经典类从B 到 A 再到C的继承S
    
    if __name__ == '__main__':
        D = D()
        D.save()
    
    经典类是深度优先
    经典类是广度优先
    正确:先B再C再搜A
    
    # ####################################
    抽象类:
        由于python 没有抽象类、接口的概念,所以要实现这种功能得abc.py 这个类库
    
    子类继承抽象类,如果没有抽象类的方法,则报错。
    
    抽象类+抽象方法 = 接口(用作代码规范)
    
    
    from abc import ABCMeta, abstractmethod
    
    
    class Super(metaclass=ABCMeta):
        def delegate(self):
            self.action()
    
        @abstractmethod
        def action(self):
            pass
    
    # X = Super()
    # TypeError: Can't instantiate abstract class Super with abstract methods action
    # 带有抽象方法的类不能继承(即,不能通过它来创建一个实例)
    
    
    class Sub(Super):
        # def action(self):
        #     print('spam')
    
        @staticmethod
        def show_time():
            print('hello')
    
        # TypeError: Can't instantiate abstract class Sub with abstract methods action
        # 子类继承抽象类,如果没有抽象类的方法,则报错。
    s = Sub()
    # s.action()
    s.show_time()

    异常处理

    # ######################################
    异常处理
    AttributeError 试图访问一个对象没有的树形,比如foo.x, 但是foo没有属性x
    IoError 输入/输出异常;基本上无法打开文件
    ImportError 无法引入模块或包;基本上是路径问题或名称错误
    IndentationError 语法错误(的子类); 代码没有正确的对齐
    IndexError 下标索引超出序列边界,比如当X只有三个元素,却试图访问X[5]
    KeyError 试图访问字典里不存在的键
    KeyboardInterrupt Ctrl+C被按下
    NameError 使用一个还未被赋予对象的变量
    SyntaxError Python代码非法,代码不能编译(个人认为这个语法错误,写错了)
    TypeError 传入对象类型与要求的不符合
    UnboundLocalError 试图访问一个还未被设置的局部变量,基本是由另一个同名的全局变量导致你以为正在访问它
    ValueError 传入一个调用者不期望的值,即使值类型是正确的
    
    ***************************************
    
    多个异常捕捉:
    try:
        xxxxx
    except (ValueError, NameError)as e:
        print(e)
    
    捕捉所有异常
    try:
        xxxxx
    except Exception as e:
        print(e)
    
    finally:
        无论出现异常都会执行
    
    ***************************************
    自定义异常:
    class MyException(Exception):
    
        def __init__(self, msg):
            self.error = msg
    
        def __str__(self, *arg, **kwargs):
            return self.error
    
    class DatabaseException(Exception):  
        def __init__(self,err='数据库错误'):  
            Exception.__init__(self,err)  
            
    
    ***************************************
    手动触发异常:
    raise MyException('my error')
  • 相关阅读:
    了解自我
    IT技能栈
    客户端的工作不仅仅只是看起来那么简单
    .NET 基础 一步步 一幕幕[XML基础操作]
    .NET 基础 一步步 一幕幕[Winform应用程序]
    .NET 基础 一步步 一幕幕[面向对象之堆、栈、引用类型、值类型]
    .NET 基础 一步步 一幕幕[面向对象之new、this关键字]
    .NET 基础 一步步 一幕幕[面向对象之静态、非静态]
    .NET 基础 一步步 一幕幕[面向对象之方法、方法的重载、方法的重写、方法的递归]
    .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
  • 原文地址:https://www.cnblogs.com/xiaoxiaolulu/p/8108638.html
Copyright © 2011-2022 走看看