美文网首页
Python3学习笔记(二)

Python3学习笔记(二)

作者: 纳尼2号 | 来源:发表于2016-10-31 01:18 被阅读120次

    好久没更新了呀,Python的学习可不能落下!😝

    面向对象编程

    面向对象设计思想:抽象出类(Class),根据类创建实例(Instance)。
    面向对象的三大特点:封装,继承,多态。

    1. 类和实例:

      • 类的定义:class Student(object): pass Student类继承了object
      • 创建实例:yzl = Student() , 创建实例后,可以自由的给实例绑定属性yzl.age = 18, 仅对本实例有效
      • 类的方法定义:def __init__(self, name, age):, 第一个变量必须是self, 但不用传,表示此实例变量。
    2. 访问限制:以__开头的是私有变量,外部访问不到(但其实可以访问到,只是Python解释器把私有变量换了个名字,比如_Student__name,以_开头的虽然可以访问,但也要当做私有变量,不要轻易访问。总之,Python本身没有任何机制阻止你干坏事,一切全靠自觉。

      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))
      
    3. 继承与多态:对于静态语言,比如Java,一个函数的入参类型必须是确定的,而对于动态语言,只要file-like object即可. 鸭子类型:一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
      只要whatever有run()方法就可以。

      def run_twice(whatever):
              whatever.run()
      
    4. 获取对象信息:

      • type() 判断对象类型 type(123): <class 'int'>
      • isinstance() 判断一个对象是否是某种类型 isinstance('abc', str): True
      • dir() 获取一个对象的所有属性和方法,它返回一个包含字符串的list
      • hasattr(obj, 'x') 获取属性 setattr(obj, 'y', 19) 设置属性,注意:只有在不知道对象信息的时候,我们才会去获取对象信息
    5. 实例属性和类属性:不通过__init__()构造,直接在class里定义属性的是类属性。实例属性和类属性名字不要一样,否则类属性在当前实例会被覆盖掉。

    6. 限制实例的属性:__slots__ = ('name', 'age') , 定义一个__slots__ 限制类的实例属性只能在tuple里,否则将报AttributeError错误,注意:__slots__只作用于当前类实例,对子类不起作用,若子类也定义了slots,则还要加上父类的slots。

    7. @property : 相当于 getter,@name.setter : 相当于 setter,这两个decorator的目的是让方法变为属性(调用方法生成了属性),可以写出更简短的代码,同时保证对参数进行必要性的检查。

      class Screen(object):
          @property
          def width(self):
              return self.__width
      
          @width.setter
          def width(self, w):
              self.__width = w
      
      s = Screen()
      print(dir(s))  # 结果为: ['__class__', '__delattr__', '__dict__', ...]
      s.width = 1
      print(dir(s))  # 结果为: ['_Screen__width', '__class__', '__delattr__', '__dict__', ...]
      
    8. 多继承:Python支持多继承,class class Dog(Mammal, Runnable):

    9. 定制类:重写class的函数,使之符合我们的需求,以下是常用的定制类:

      • __str__ : 自定义打印实例,变量调用的是__repr__

        class Student(object):
            def __init__(self, name):
                self.name = name
            def __str__(self):
                return 'Student object (name=%s)' % self.name
            __repr__ = __str__
        
      • __iter__: 返回一个迭代对象,通过__next()__方法循环获取下一个值,知道遇到StopIteration错误时推出循环

        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 # 返回下一个值
        
      • __getitem__: 按照下标或切片取出元素

        # 重写__getitem__ 支持索引和切片
        class Fib(object):
            def __getitem__(self, n):
                if isinstance(n, int):  # n是索引
                    a, b = 1, 1
                    for x in range(n):
                        a, b = b, a + b
                    return a
                if isinstance(n, slice):  # n是切片
                    start = n.start
                    stop = n.stop
                    if start is None:
                        start = 0
                    a, b = 1, 1
                    L = []
                    for x in range(stop):
                        if x >= start:
                            L.append(a)
                        a, b = b, a + b
                    return L
        
        print(Fib()[9])
        print(Fib()[:10])
        
      • __getattr__: 动态返回一个属性, 可以写一个链式调用

        def __getattr__(self, path):
           return Chain('%s/%s' % (self._path, path))
        
      • __call__: 直接在实例本身上调用, 通过callable()函数,可以判断一个对象是否是“可调用”对象。

        class Student(object):
            def __init__(self, name):
                self.name = name
        
            def __call__(self):
                print('My name is %s.' % self.name)
        
        s = Student('DreamYoung')
        if callable(s):
            s()  # self参数不要传入    
        
    10. 枚举类:Enum 枚举类,把一组相关常量定义在一个class中,class不可变,成员可直接比较

      from enum import Enum, unique
      
      @unique  # @unique装饰器用于检查有没有重复值
      class Weekday(Enum):
          Sun = 0  # Sun的value被设定为0
          Mon = 1, 2
          Tue = 2
      
      print(Weekday.Sun)          # Weekday.Sun
      print(Weekday.Sun.value)    # 0
      print(Weekday.Mon.value)    # (1, 2)
      print(Weekday(2))           # Weekday.Tue
      print(Weekday['Tue'])       # Weekday.Tue
      print(Weekday['Tue'].value) # 2
      

      可见,既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量

    11. 元类:Python的class的定义是运行时创建的,创建的方法就是使用type()函数!type()函数既可以返回一个对象的类型,又可以创建出新的类型,无需使用class关键字。

      def fun(self, name='DreamYoung'):
          print('Hello, ' + name)
          
      Hello = type('Hello', (object,), dict(hello=fun))  # 创建Hello class
      
      h = Hello()
      h.hello()
      

      type()函数需要三个参数:函数名称,继承的父类集合(tuple),方法名绑定的函数。
      Python创建类也是扫一下class关键字,然后通过type创建出来类。
      如果要控制类的行为,可以使用元类�metaclass,可以把类理解为metaclass创建的实例。 先定义metaclass,就可以创建类,最后创建实例。metaclass暂时不会用到,如果需要深入了解,可以参考这篇文章

    错误、调试和测试

    1. 错误:Python内置了try...except...finally...用于捕获异常,所有的异常都继承自BaseException, 查看异常继承关系

      注意:

      • except可以有多个,多个except异常 父类会覆盖子类的异常, except后可以跟else
      • finally在最后执行,可以不写
      • 可以使用logging模块记录日志,通过查看调用堆栈,定位排查错误

      写法:

      try:
          print(1/0)
      except ZeroDivisionError as e:
          logging.exception(e)
      else:
          print('else')
      finally:
          print('finally')
      
    2. 调试:要想调试起来爽,要善于使用logging

      logging有debug、info、warning、error几个级别,通过:

      import logging
      logging.basicConfig(level=logging.INFO) # info级别日志,debug日志不会显示
      

      指定当前模块的日志级别,logging的好处是通过简单的配置,日志可以输出到文件等等

    3. 单元测试:编写单元测试需要引入unittest模块,并编写一个从unittest.TestCase继承测试类。
      注意,测试方法必须以test开头(test_xxx()),否则在测试时不会被执行。unittest提供了很多内置条件的判断,比如:assertEqual()assertRaises()等等 用于判断输出值是否是我们的期望值。

      运行前与运行后:编写两个特殊的方法setUp()tearDown(),在每个单元测试方法执行之前执行setUp(),执行之后执行tearDown()。这个用处大大的,比如可以在setUp()方法连接测试库,tearDown()方法关闭连接。

      运行单元测试有两种方法:

      1. 加上两行代码,这样可以当做正常的Python脚步运行:

        if __name__ == '__main__':
            unittest.main()
        
      2. (荐)通过命令行参数直接运行单元测试 :可以批量执行单元测试

        $ python3 -m unittest my_test1.py my_test2.py
        
    4. 文档测试:Python的很多官方文档都是示例代码,通过doctest模块,可以提前并执行文档注释代码。
      比如就绝对值的函数abs()写上这样的注释:

      def abs(n):
          """
          Function to get absolute value of number.
      
          Example:
      
          >>> abs('')
          Traceback (most recent call last):
              ...
          TypeError: unorderable types: str() >= int()
          >>> abs(1)
          1
          >>> abs(-1)
          1
          >>> abs(0)
          0
          """
          return n if n >= 0 else (-n + 1)  # 正确的代码应为: return n if n >= 0 else (-n)
      
      if __name__ == '__main__':
          import doctest
      
          doctest.testmod()
      

      会得到以下输出:


    File "xxxx/demo/dream/young/python/Test.py", line 13, in main.abs
    Failed example:
    abs(-1)
    Expected:
    1
    Got:
    2


    1 items had failures:
    1 of 4 in main.abs
    Test Failed 1 failures.

    
    如果没有输出任何信息,说明注释代码没有错误。注意:当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行。

    相关文章

      网友评论

          本文标题:Python3学习笔记(二)

          本文链接:https://www.haomeiwen.com/subject/gvguuttx.html