• python学习心得(三)


    一,面向对象编程

    1,类和实例,

    class Student(object):#括号里面的是继承的类
        def __init__(self, name, score):初始化对象时,参数个数
            self.name = name
            self.score = score
        def print_score(self):
            print '%s: %s' % (self.name, self.score)

    2,访问限制

    1,如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__

    2,但是如果外部代码要获取name和score怎么办?可以给Student类增加get_nameget_score这样的方法,,好处:可以对参数做检查,避免传入无效的参数:

    lass Student(object):
        def __init__(self, name, score):
            self.__name = name       #双下划线,外部无法直接访问
            self.__score = score
        def print_score(self):
            print '%s: %s' % (self.__name, self.__score)
         def set_score(self, score):    #通过set_来做筛选
            if 0 <= score <= 100:
                self.__score = score
            else:
                raise ValueError('bad score')
        def get_name(self):            #通过get_来获取参数
            return self.__name
    
        def get_score(self):
            return self.__score

    3,继承和多态

    1,继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;默认继承object

    2,有了继承,才能有多态。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;如猫,狗等都属于动物,即为一种多态表现

    4,获取对象信息

    1,type方法;

    >>> import types
    >>> type(int)==types.TypeType
    True
    >>> type(int)
    <type 'type'>
    >>> type(int)==type(str)
    True

    2,isinstance()方法:>>> isinstance('abc',str)   True

    3,dir():获取对象所有方法和属性

    >>> dir('o1')
    ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

    (二),面向对象编程

    1,绑定

    对象和类动态绑定属性和方法:

    >>> class Student(object):
    ...     pass
    ...
    >>> s = Student()
    >>> s.name = 'Michael' # 动态给实例绑定一个属性
    >>> print s.name
    Michael
    >>> def set_age(self, age): # 定义一个函数作为实例方法
    ...     self.age = age
    ...
    >>> from types import MethodType
    >>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法
    >>> s.set_age(25) # 调用实例方法
    >>> s.age # 测试结果
    25
    >>> def set_score(self, score):
    ...     self.score = score
    ...
    >>> Student.set_score = MethodType(set_score, None, Student)
    >>> s.set_score(100)
    >>> s.score
    100
    >>> s2.set_score(99)
    >>> s2.score
    99
    # 关键方法MethodTypes(方法名,对象(所有为None),类名)
    View Code

    2,限制

      但是,如果我们想要限制class的属性怎么办?比如,只允许对Student实例(而非对象)添加nameage属性。

      除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__

    >>> class Student(object):
    ...     __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    ...
    >>> class GraduateStudent(Student):#新建子类,子类可以为继承父类的__slots__
    # 除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。  如添加__slots__=('sex'),即子类被限制为name,age,sex了
    ...     pass
    ...
    >>> g = GraduateStudent()
    >>> g.score = 9999

    3,@property

    作用:既能检查参数,又可以用类似属性这样简单的方式来访问类的变量,即对参数二次开发。

    class Student(object):
        @property  #相当于 score.getter  表示读
        def score(self):
            return self._score
    
        @score.setter   #对属性进行先验,附加条件  表示写
        def score(self, value):
            if not isinstance(value, int):
                raise ValueError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value
    >>> s = Student()
    >>> s.set_score(60)     # ok!
    >>> s.get_score()
    60
    >>> s.set_score(9999)   #get raise异常
    Traceback (most recent call last):
      ...
    ValueError: score must between 0 ~ 100!
    View Code

    4,多重继承

    继承的方法按照深度优先的情况选择:如

    class Grandfa(object):
        def hair(self):
            print 'no hair'
    
    class Father(Grandfa):
         pass
    
    class Mother(Grandfa):
         def hair(self):
            print 'long hair'
    
    class Tom(Father,Mother):
        pass
    
    me = Tom()
    me.hair()
    #  输出long hair

    关系从上到下为:object→Grandfa→father  and  mother →Tom:深度优先遍历顺序为:Tom→father(没有hair方法)→mother(有hair方法,返回值,遍历结束) 相当于先左子树,再右子树,最后父类寻找方式。

    5,定制类

    1,__str__和__repr__():两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。

    >>> class student(object):
    ...     def __str__(self):
    ...             return 'is str'
    ...     def __repr__(self):
    ...             return 'is repr'
    ... 
    >>> s=student()
    >>> s
    is repr
    >>> print s
    is str
    # 通常__str__()和__repr__()代码都是一样的

    2,__iter__:如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环

      __getitem__:可以按下标获取指定值,或可以向集合一样切片

    class Fib(object):
        def __init__(self):
            self.a, self.b = 0, 1 # 初始化两个计数器a,b
        def __iter__(self):
            return self # 实例本身就是迭代对象,故返回自己
        def next(self):
            self.a, self.b = self.b, self.a + self.b # 计算下一个值
            if self.a > 100000: # 退出循环的条件
                raise StopIteration();
            return self.a # 返回下一个值
    >>> for n in Fib():
    ...     print n
    ...
    class Fib(object):
        def __getitem__(self, n):
            if isinstance(n, int):
                a, b = 1, 1
                for x in range(n):
                    a, b = b, a + b
                return a
            if isinstance(n, slice):
                start = n.start
                stop = n.stop
                a, b = 1, 1
                L = []
                for x in range(stop):
                    if x >= start:
                        L.append(a)
                    a, b = b, a + b
                return L
    >>> f = Fib()
    >>> f[0:5]
    [1, 1, 2, 3, 5]
    View Code

    3,__getattr__:防止正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错的情况,

    4,__call__:任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。__call__()还可以定义参数,判断一个对象是否能被调用。

    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            print('My name is %s.' % self.name)
    >>> s = Student('Michael')
    >>> s()
    My name is Michael.
    >>> callable(max)
    True    #能被调用
    >>> callable([1, 2, 3])
    False    #不能被调用

    6,使用元类

    :不会碰到需要使用metaclass的情况,暂不了解

    (三) 错误调试

    1,错误处理

    try...except...finally...:finally重会执行:但是finally如果有,则一定会被执行(可以没有finally语句)

    raise:raise语句抛出一个错误的实例,print异常,代价大,增加吞吐量,所以用raise抛出即可

    抛出异常:如果程序中出现了异常,没有办法将具体的异常打印出来,不做任何处理

    捕获异常:如果程序出现了异常,就能够详细的打印是什么原因导致了异常并且能够做出相应的处理,能够显示详细的Log

    logging:出错,但程序打印完错误信息后会继续执行,并正常退出。

    try:
        foo()
    except StandardError, e:
        print 'StandardError'
    except ValueError, e:
        print 'ValueError'
    # StandardError是ValueError,的父类,所以第二个except永远也捕获不到,子类要重写父类中的方法,如果父类的方法有异常声明,子类异常小于等于父类异常

    2,调试

    1,assert  断言 来辅助查看的地方

    # err.py
    def foo(s):
        n = int(s)
        assert n != 0, 'n is zero!'
        return 10 / n
    
    def main():
        foo('0')
    # 
    $ python err.py
    Traceback (most recent call last):
      ...
    AssertionError: n is zero!
    #关闭assert  python -O err.py, 按默认情况抛异常
    View Code

    2,logging    日志相关操作

    import logging
    logging.basicConfig(level=logging.INFO)#它允许你指定记录信息的级别,有debug,info,warning,error等几个级别
    s='0'
    n=int(s)
    logging.info('n =%d' %n)
    print 10/n
    #通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。

    3,单元测试

    单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。

    单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。

    单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。

    单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。

    #测试功能
    class Dict(dict):
    
        def __init__(self, **kw):
            super(Dict, self).__init__(**kw)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
    
        def __setattr__(self, key, value):
            self[key] = value
    #测试函数
    import unittest
    
    from mydict import Dict
    
    class TestDict(unittest.TestCase):
    
        def test_init(self):
            d = Dict(a=1, b='test')
            self.assertEquals(d.a, 1)
            self.assertEquals(d.b, 'test')
            self.assertTrue(isinstance(d, dict))
    
        def test_key(self):
            d = Dict()
            d['key'] = 'value'
            self.assertEquals(d.key, 'value')
    
        def test_attr(self):
            d = Dict()
            d.key = 'value'
            self.assertTrue('key' in d)
            self.assertEquals(d['key'], 'value')
    
        def test_keyerror(self):
            d = Dict()
            with self.assertRaises(KeyError):
                value = d['empty']
    
        def test_attrerror(self):
            d = Dict()
            with self.assertRaises(AttributeError):
                value = d.empty
    
        if __name__ == '__main__':
            unittest.main()
    # 测试原理还是不太清楚,以后有需要再去了解下
    python -m unittest mydict_test
    .....
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    OK
    View Code

    4,文档测试

    doctest非常有用,不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest。

    class Dict(dict):
        '''
        Simple dict but also support access as x.y style.
    
        >>> d1 = Dict()
        >>> d1['x'] = 100
        >>> d1.x
        100
        >>> d1.y = 200
        >>> d1['y']
        200
        >>> d2 = Dict(a=1, b=2, c='3')
        >>> d2.c
        '3'
        >>> d2['empty']
        Traceback (most recent call last):
            ...
        KeyError: 'empty'
        >>> d2.empty
        Traceback (most recent call last):
            ...
        AttributeError: 'Dict' object has no attribute 'empty'
        '''
    
        def __init__(self, **kw):
            super(Dict, self).__init__(**kw)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
    
        def __setattr__(self, key, value):
            self[key] = value
    
    if __name__=='__main__':
        import doctest
        doctest.testmod()
    # python Dict.py 没结果输出,表示运行正常。
  • 相关阅读:
    C++对象模型与内存位对齐的简单分析(GNU GCC&VS2015编译器)
    [GeekBand] C++学习笔记(2)——BigThree、OOP
    [GeekBand] C++ 高级编程技术 (1)
    [GeekBand]C++高级编程技术(2)
    C++中引用的本质分析
    函数的重载(1)
    C++的特点
    布尔类型和三目运算符
    Linux客户端下的latex相关操作
    无光驱上网本上安装win7
  • 原文地址:https://www.cnblogs.com/ksWorld/p/7045501.html
Copyright © 2020-2023  润新知