Python高级知识点学习(三)

作者: kakarotto | 来源:发表于2018-10-21 05:18 被阅读7次

    mro算法

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

    • 何为类属性:定义在类内部的的一些变量或者方法,都统称为类属性
    • 何为实例属性:定义在对象内部的的一些变量或者方法,都统称为实例属性

    对象也就是实例的意思。

    class A:
        aa = 1
        def __init__(self, x, y):
            self.x = x
            self.y = y
    a = A(2, 3)
    

    类也是对象,看上边代码,实际上有两个空间,A 和 a 两个不同的空间。
    单继承时,属性查找方式,向上查找,首先查找对象里,再查找类中

    在多继承时,会很复杂

    python2.2之前,python里的类叫经典类,经典类继承方式如果不显式继承object,实际上是不会自动继承object,Python3中,经典类已经不存在了,都叫做新式类。
    经典类中,深度优先查找 。

    Python2.3之后,广度优先也没有了,至今都采用C3算法
    Python3多重继承C3算法:

    #新式类
    class D:
        pass
    
    class E:
        pass
    
    class C(E):
        pass
    
    class B(D):
        pass
    
    class A(B, C):
        pass
    
    print(A.__mro__)
    

    打印结果:
    (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
    可以看到继承顺序是 A - B - D - C - E - object

    类方法静态方法和实例方法

    实例方法:实例方法很常见,通常我们在类里定义的都是实例方法,

    • 只是针对于实例进行操作,实例方法中第一个参数:self,self代表的就是实例本身

    静待方法:

    • 带@staticmethod装饰器的方法叫静态方法,静态方法不需要接受cls或self,和普通的函数用法一样

    类方法:

    • 带@classmethod装饰器的方法叫做类方法,类方法第一个参数是cls,代表的是类本身,(这里的cls可以修改为任意形式的代表)
        def a(self):
            pass
        
        @staticmethod
        def b():
            pass
        
        @classmethod
        def c(cls):
            pass
    

    Python中的私有属性

    双下划綫开头表示私有属性,私有属性的访问,只能在类中的公共方法中访问,类外部防问不到,无法通过实例访问。

    私有属性不仅仅是变量 还可以是函数。

    class User:
        def __init__(self, birthday):
            self.__birthday = birthday
    
    user = User(2000)
    print(user.birthday)
    
    运行结果:
    AttributeError: 'User' object has no attribute 'birthday'
    

    以上代码块结果就是访问不到私有属性。

    但是,私有不是绝对的,只是加了一个小技巧,Python中将私有属性的访问变形成这种:

    class User:
        def __init__(self, birthday):
            self.__birthday = birthday
        
    
    user = User(2000)
    print(user._User__birthday)
    
    运行结果:
    2000
    

    可以看到,通过变量_User__birthday这个就可以访问到私有属性。

    Java中的反射机制也是无法做到绝对安全的,从语言层面讲,没有绝对的私有属性,Python简单一些 Java麻烦一些。

    Python自省

    Python对象自省
    何为自省?
    自省是通过一定的机制查询到对象的内部结构
    使用__dict__魔法函数,dict是用C语言写的 性能高,做了很多优化,推荐使用。

    也可以使用dir() ,dir()会列出类中所有属性,推荐使用。

    class Student():
        def __init__(self, scool_name):
            self.scool_name = scool_name
    
    
    if __name__ == "__main__":
        user = Student("zhao")
    
        #通过__dict__查询属性
        print(user.__dict__)
    
    打印结果:
    {'scool_name': 'zhao'}
    
    class Student():
        def __init__(self, name):
            self.name = name
    
    
    if __name__ == "__main__":
        user = Student("zhao")
        user.__dict__["school_addr"] = "北京市"
        print(user.school_addr)
        print(user.name)
        a = [1, 2]
        print(dir(a))
        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', 'scool_name']
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    

    Python中super()函数

    super()就是调用父类。

    class A:
        def __init__(self):
            print('is A')
    
    class B(A):
        def __init__(self):
            print('is B')
            # 在某些情况下,我们希望在运行完以上代码调用父类的init方法,一般在Python3中使用下面这种方法调用
            super().__init__()
    
    if __name__ == "__main__":
        b = B()
    
    打印结果:
    is B
    is A
    

    super()就是调用父类,其实这样讲并不准确,super()函数调用其实是按照mro查找的顺序调用的。

    class A:
        def __init__(self):
            print("A")
    
    
    class B(A):
        def __init__(self):
            print("B")
            super().__init__()
    
    
    class C(A):
        def __init__(self):
            print("C")
            super().__init__()
    
    
    class D(B, C):
        def __init__(self):
            print("D")
            super().__init__()
    
    
    if __name__ == "__main__":
        print(D.__mro__)
        d = D()
    
    打印结果:
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    D
    B
    C
    A
    

    既然我们重写子类的构造函数, 为什么还要去调用super再次调用父类构造函数?
    有些时候,为了使用父类中的一些已经写好的方法,所以会有使用super的情况。

    上下文管理器

    首先介绍下这种用法:

    try:
        print("code started")
        raise KeyError
        return 1
    except KeyError as e:
        print ("key error")
        return 2
    else:
        print("other error")
        return 3
    finally:
        print ("finally")
        return 4
    
    result = exe_try()
    print (result)
    
    运行结果:
    code started
    key error
    finally
    4
    

    在finally语句块中的代码,不管上边代码是否发生异常都会执行finally中的代码,优先finally中的return,其次return上边的。

    上下文管理器,也就是with语句,实质上就是为了解放try finally这种写法而诞生的。

    上下文管理器是如何完成的呢?
    python是基于协议进行编程的,上下文管理器就是一种协议:上下文管理器协议。

    上下文管理器协议可以使用是因为实现了两个魔法函数:
    __enter____exit__

    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")
    
    
    with Sample() as sample:
        sample.do_something()
    
    运行结果:
    enter
    doing something
    exit
    

    还有一种方法,可以简便的实现上下文管理器的功能:
    @contextlib.contextmanager 可以将一个函数变为上下文管理器

    import contextlib
    
    @contextlib.contextmanager
    def file_open(file_name):
        print ("file open")
        yield {}
        print ("file end")
    
    with file_open("a.txt") as f_opened:
        print("file processing")
    
    运行结果:
    file open
    file processing
    file end
    

    @contextlib.contextmanager内部会做一些逻辑,其实是利用了生成器的特性。

    相关文章

      网友评论

        本文标题:Python高级知识点学习(三)

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