程序员Python语言自学Python入门与进阶

Python高级知识点学习(三)

2018-10-21  本文已影响7人  kakarotto

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

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

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

静待方法:

类方法:

    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内部会做一些逻辑,其实是利用了生成器的特性。

上一篇下一篇

猜你喜欢

热点阅读