美文网首页初学者python
7、深入类和对象

7、深入类和对象

作者: python与数据分析 | 来源:发表于2019-08-15 13:56 被阅读0次

    1、with语句(上下文管理器)

    Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。

    #上下文管理器
    class Sample:
        def __enter__(self):
            print('enter')
            #获取资源
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            #释放资源
            print('exit')
    
        def do_something(self):
            print('doing something')
    
    #会自动执行enter和exit方法
    with Sample() as sample:
        sample.do_something()
    
    
    # 运行结果
    enter
    doing something
    exit
    

    python中with可以明显改进代码友好度,比如:

    with open('a.txt') as f:
        print f.readlines()
    

    为了我们自己的类也可以使用with, 只要给这个类增加两个函数enter, exit即可:

    class A:
        def __enter__(self):
            print 'in enter'
        def __exit__(self, e_t, e_v, t_b):
            print 'in exit'
     
    with A() as a:
        print 'in with'
    
    
    # 运行结果
    in enter
    in with
    in exit
    

    另外python库中还有一个模块contextlib,使你不用构造含有enter, exit的类就可以使用with:

    from contextlib import contextmanager
    from __future__ import with_statement
    
    
     @contextmanager
     def context():
         print 'entering the zone'
         try:
             yield
         except Exception, e:
             print 'with an error %s'%e
             raise e
         else:
             print 'with no error'
    
     with context():
         print '----in context call------'
    
    
    # 运行结果
    entering the zone
    ----in context call------
    with no error
    

    使用的最多的就是这个contextmanager, 另外还有一个closing 用处不大

    from contextlib import closing
    import urllib
     
    with closing(urllib.urlopen('http://www.python.org')) as page:
        for line in page:
            print line
    

    2、super函数

    2.1、super() 函数是用于调用父类(超类)的一个方法

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
     
    class FooParent(object):
        def __init__(self):
            self.parent = 'I\'m the parent.'
            print ('Parent')
        
        def bar(self,message):
            print ("%s from Parent" % message)
     
    class FooChild(FooParent):
        def __init__(self):
            # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象
            super(FooChild,self).__init__()    
            print ('Child')
            
        def bar(self,message):
            super(FooChild, self).bar(message)
            print ('Child bar fuction')
            print (self.parent)
     
    if __name__ == '__main__':
        fooChild = FooChild()
        fooChild.bar('HelloWorld')
    
    # 运行结果
    Parent
    Child
    HelloWorld from Parent
    Child bar fuction
    I'm the parent.
    

    2.2、使用 super() 可以很好地避免构造函数被调用两次。

    class A():
        def __init__(self):
            print('enter A')
            print('leave A')
    
    
    class B(A):
        def __init__(self):
            print('enter B')
            super().__init__()
            print('leave B')
    
    
    class C(A):
        def __init__(self):
            print('enter C')
            super().__init__()
            print('leave C')
    
    
    class D(B, C):
        def __init__(self):
            print('enter D')
            super().__init__()
            print('leave D')
    
    
    d = D()
    print(D.__mro__)      #(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
        
    #执行结果
    D
    B
    C
    A
    

    3、python对象的自省机制

    检查某些事物以确定它是什么、它知道什么以及它能做什么,运行时能够获得对象的类型。

    type() :一个参数返回对象类型, 三个参数,返回新的类型对象
    dir() : 用于返回参数的属性和方法列表
    getattr() : 用于返回一个对象属性值
    hasattr() : 用于判断对象是否包含对应的属性
    isinstance() : 用于判断一个对象是否是一个已知的类型

    # class type(name, bases, dict)
    # 参数
    # name -- 类的名称。
    # bases -- 基类的元组。
    # dict -- 字典,类内定义的命名空间变量。
    # 一个参数实例
    >>> type(1)
    <type 'int'>
    >>> type('runoob')
    <type 'str'>
    >>> type([2])
    <type 'list'>
    >>> type({0:'zero'})
    <type 'dict'>
    >>> x = 1         
    >>> type( x ) == int    # 判断类型是否相等
    True
      
    # 三个参数
    >>> class X(object):
    ...     a = 1
    ...
    >>> X = type('X', (object,), dict(a=1))  # 产生一个新的类型 X
    >>> X
    <class '__main__.X'>
    
    # type() 和isinstance()区别
    1. type() 不会认为子类是一种父类类型,不考虑继承关系。
    2. isinstance() 会认为子类是一种父类类型,考虑继承关系。
    # 如果要判断两个类型是否相同推荐使用 isinstance()。
    示例:
        class A:
            pass
        class B(A):
            pass
    
        isinstance(A(), A)    # returns True
        type(A()) == A        # returns True
        isinstance(B(), A)    # returns True
        type(B()) == A        # returns False
    
    class Student(Person): def __init__(self,school_name):
            self.school_name = school_name if __name__ == "__main__":
    
        user = Student('仙剑') #通过 __dict__ 查询有哪些属性
        print(user.__dict__)        #{'school_name': '仙剑'}
    
        print(Person.__dict__)      #{'__module__': '__main__', '__doc__': '人类', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
    
        print(Person.__doc__)       #人类
    
        #可以添加属性
        user.__dict__['school_addr'] = '北京'
        print(user.school_addr)     #北京
    
        #dir也可以查看属性,比__dict__功能更强大
        print(dir(user)) #['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_addr', 'school_name']</pre>
    
    

    4、类方法,静态方法,和实例方法

    class Date():
        #构造函数
        def __init__(self,year,month,day):
            self.year = year
            self.month = month
            self.day = day
    
        #实例方法
        def tomorrow(self):
            self.day += 1
    
        # 静态方法不用写self
        @staticmethod
        def parse_from_string(date_str):
            year, month, day = tuple(date_str.split("-"))
            # 静态方法不好的地方是采用硬编码,如果用类方法的话就不会了
            return Date(int(year), int(month), int(day))
    
        #类方法
        @classmethod
        def from_string(cls, date_str):
            year, month, day = tuple(date_str.split("-"))
            # cls:传进来的类,而不是像静态方法把类写死了
            return cls(int(year), int(month), int(day))
    
        def __str__(self):
            return '%s/%s/%s'%(self.year,self.month,self.day)
    
    if __name__ == "__main__":
        new_day = Date(2018,5,9)
        #实例方法
        new_day.tomorrow()
        print(new_day)       #2018/5/10
    
        #静态方法
        date_str = '2018-05-09'
        new_day = Date.parse_from_string(date_str)
        print(new_day)       #2018/5/9
    
        # 类方法
        date_str = '2018-05-09'
        new_day = Date.from_string(date_str)
        print(new_day)  # 2018/5/9
    

    5、类和实例属性的查找顺序

    image
    class C(D):
        pass
    
    class B(D): 
        pass
    
    class A(B,C): 
         pass
    
    #顺序:A,B,C,D #__mro__,类的属性查找顺序
    print(A.__mro__)      #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)</pre>
    
    
    image
    class E:
       pass
    
    class C(E): 
       pass
    
    class B(D): 
       pass
    
    class A(B,C): 
       pass
    
    #顺序:A,B,D,C,E #__mro__,类的属性查找顺序
    print(A.__mro__) #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)</pre>
    

    6、类变量和实例变量

    python的类变量和实例变量,顾名思义,类变量是指跟类的变量,而实例变量,指跟类的具体实例相关联的变量

    class A:
        #类变量
        bb = 11
        def __init__(self,x,y): #实例变量
            self.x = x
            self.y = y
    
    a = A(2,3)
    A.bb = 111111
    print(a.x,a.y,a.bb)    # 2 3 111111
    print(A.bb)            # 111111
     a.bb = 2222     #实际上会在实例对象a里面新建一个属性bb
    print(a.bb)          # 2222
    print(A.bb)          # 111111</pre>
    
    

    7、使用isinstance而不是type

    7.1、语法:

     isinstance(object, classinfo)
    

    其中,object 是变量,classinfo 是类型即 (tuple,dict,int,float,list,bool等) 和 class类

    若参数 object 是 classinfo 类的实例,或者 object 是 classinfo 类的子类的一个实例, 返回 True。
    若 object 不是一个给定类型的的对象, 则返回结果总是False。

    若 classinfo 不是一种数据类型或者由数据类型构成的元组,将引发一个 TypeError 异常。

    7.2、isinstance简单用法

    >>> isinstance(1,int)
    True
    >>> 
    >>> isinstance('1',str)
    True
    >>> 
    >>> isinstance(1,list)
    False
    

    7.3、type()与isinstance()的区别:

    • 共同点两者都可以判断对象类型
    • 不同点对于一个 class 类的子类对象类型判断,type就不行了,而 isinstance 可以。
    class A:
        pass
    
    class B(A):
        pass
    
    b = B()
    
    #判断b是不是B的类型
    print(isinstance(b,B))        #True
    # b是不是A的类型呢,也是的
    #因为B继承A,isinstance内部会去检查继承链
    print(isinstance(b,A))        #True
    
    print(type(b) is B)           #True
    #b指向了B()对象,虽然A是B的父类,但是A是另外一个对象,它们的id是不相等的
    print(type(b) is A)           #False
    

    相关文章

      网友评论

        本文标题:7、深入类和对象

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