描述符(__get__和__set__和__delete__)

一、描述符

  • 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),set(),delete()中的一个,这也被称为描述符协议

    • __get__():调用一个属性时,触发
    • __set__():为一个属性赋值时,触发
    • __delete__():采用del删除属性时,触发
  • 定义一个描述符
  1. class Foo: # 在python3中Foo是新式类,它实现了__get__(),__set__(),__delete__()中的一个三种方法的一个,这个类就被称作一个描述符
  2. def __get__(self, instance, owner):
  3. pass
  4. def __set__(self, instance, value):
  5. pass
  6. def __delete__(self, instance):
  7. pass

二、描述符的作用

  • 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的,必须把描述符定义成这个类的类属性,不能定义到构造函数中
  1. class Foo:
  2. def __get__(self, instance, owner):
  3. print('触发get')
  4. def __set__(self, instance, value):
  5. print('触发set')
  6. def __delete__(self, instance):
  7. print('触发delete')
  8. f1 = Foo()
  • 包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
  1. f1.name = 'randy'
  2. f1.name
  3. del f1.name

2.1 何时,何地,会触发这三个方法的执行

  1. class Str:
  2. """描述符Str"""
  3. def __get__(self, instance, owner):
  4. print('Str调用')
  5. def __set__(self, instance, value):
  6. print('Str设置...')
  7. def __delete__(self, instance):
  8. print('Str删除...')
  9. class Int:
  10. """描述符Int"""
  11. def __get__(self, instance, owner):
  12. print('Int调用')
  13. def __set__(self, instance, value):
  14. print('Int设置...')
  15. def __delete__(self, instance):
  16. print('Int删除...')
  17. class People:
  18. name = Str()
  19. age = Int()
  20. def __init__(self, name, age): # name被Str类代理,age被Int类代理
  21. self.name = name
  22. self.age = age
  23. # 何地?:定义成另外一个类的类属性
  24. # 何时?:且看下列演示
  25. p1 = People('alex', 18)

Str设置...

Int设置...

  • 描述符Str的使用
  1. p1.name
  2. p1.name = 'randy'
  3. del p1.name

Str调用

Str设置...

Str删除...

  • 描述符Int的使用
  1. p1.age
  2. p1.age = 18
  3. del p1.age

Int调用

Int设置...

Int删除...

  • 我们来瞅瞅到底发生了什么
  1. print(p1.__dict__)
  2. print(People.__dict__)
  1. {}
  2. {'__module__': '__main__', 'name': <__main__.Str object at 0x107a86940>, 'age': <__main__.Int object at 0x107a863c8>, '__init__': <function People.__init__ at 0x107ba2ae8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
  • 补充
  1. print(type(p1) == People) # type(obj)其实是查看obj是由哪个类实例化来的
  2. print(type(p1).__dict__ == People.__dict__)

True

True

三、两种描述符

3.1 数据描述符

  • 至少实现了__get__()和__set__()
  1. class Foo:
  2. def __set__(self, instance, value):
  3. print('set')
  4. def __get__(self, instance, owner):
  5. print('get')

3.2 非数据描述符

  • 没有实现__set__()
  1. class Foo:
  2. def __get__(self, instance, owner):
  3. print('get')

四、描述符注意事项

  1. 描述符本身应该定义成新式类,被代理的类也应该是新式类

  2. 必须把描述符定义成这个类的类属性,不能为定义到构造函数中

  3. 要严格遵循该优先级,优先级由高到底分别是

    1.类属性

    2.数据描述符

    3.实例属性

    4.非数据描述符

    5.找不到的属性触发__getattr__()

五、使用描述符

  • 众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能

5.1 牛刀小试

  1. class Str:
  2. def __init__(self, name):
  3. self.name = name
  4. def __get__(self, instance, owner):
  5. print('get--->', instance, owner)
  6. return instance.__dict__[self.name]
  7. def __set__(self, instance, value):
  8. print('set--->', instance, value)
  9. instance.__dict__[self.name] = value
  10. def __delete__(self, instance):
  11. print('delete--->', instance)
  12. instance.__dict__.pop(self.name)
  13. class People:
  14. name = Str('name')
  15. def __init__(self, name, age, salary):
  16. self.name = name # 触发__set__
  17. self.age = age
  18. self.salary = salary
  19. p1 = People('randy', 18, 3231.3)

set---> <__main__.People object at 0x107a86198> randy

  • 调用
  1. print(p1.__dict__)
  2. print(p1.name)

{'name': 'randy', 'age': 18, 'salary': 3231.3}

get---> <__main__.People object at 0x107a86198> <class '__main__.People'>

randy

  • 赋值
  1. print(p1.__dict__)
  2. p1.name = 'randysun'
  3. print(p1.__dict__)

{'name': 'randy', 'age': 18, 'salary': 3231.3}

set---> <__main__.People object at 0x107a86198> randysun

{'name': 'randysun', 'age': 18, 'salary': 3231.3}

  • 删除
  1. print(p1.__dict__)
  2. del p1.name
  3. print(p1.__dict__)

{'name': 'randysun', 'age': 18, 'salary': 3231.3}

delete---> <__main__.People object at 0x107a86198>

{'age': 18, 'salary': 3231.3}

5.2 拔刀相助

  1. class Str:
  2. def __init__(self, name):
  3. self.name = name
  4. def __get__(self, instance, owner):
  5. print('get--->', instance, owner)
  6. return instance.__dict__[self.name]
  7. def __set__(self, instance, value):
  8. print('set--->', instance, value)
  9. instance.__dict__[self.name] = value
  10. def __delete__(self, instance):
  11. print('delete--->', instance)
  12. instance.__dict__.pop(self.name)
  13. class People:
  14. name = Str('name')
  15. def __init__(self, name, age, salary):
  16. self.name = name
  17. self.age = age
  18. self.salary = salary
  19. # 疑问:如果我用类名去操作属性呢
  20. try:
  21. People.name # 报错,错误的根源在于类去操作属性时,会把None传给instance
  22. except Exception as e:
  23. print(e)

get---> None <class '__main__.People'>

'NoneType' object has no attribute '__dict__'

  • 修订__get__方法
  1. class Str:
  2. def __init__(self, name):
  3. self.name = name
  4. def __get__(self, instance, owner):
  5. print('get--->', instance, owner)
  6. if instance is None:
  7. return self
  8. return instance.__dict__[self.name]
  9. def __set__(self, instance, value):
  10. print('set--->', instance, value)
  11. instance.__dict__[self.name] = value
  12. def __delete__(self, instance):
  13. print('delete--->', instance)
  14. instance.__dict__.pop(self.name)
  15. class People:
  16. name = Str('name')
  17. def __init__(self, name, age, salary):
  18. self.name = name
  19. self.age = age
  20. self.salary = salary
  21. print(People.name) # 完美,解决

get---> None <class '__main__.People'>

<__main__.Str object at 0x107a86da0>

5.3 磨刀霍霍

  1. class Str:
  2. def __init__(self, name, expected_type):
  3. self.name = name
  4. self.expected_type = expected_type
  5. def __get__(self, instance, owner):
  6. print('get--->', instance, owner)
  7. if instance is None:
  8. return self
  9. return instance.__dict__[self.name]
  10. def __set__(self, instance, value):
  11. print('set--->', instance, value)
  12. if not isinstance(value, self.expected_type): # 如果不是期望的类型,则抛出异常
  13. raise TypeError('Expected %s' % str(self.expected_type))
  14. instance.__dict__[self.name] = value
  15. def __delete__(self, instance):
  16. print('delete--->', instance)
  17. instance.__dict__.pop(self.name)
  18. class People:
  19. name = Str('name', str) # 新增类型限制str
  20. def __init__(self, name, age, salary):
  21. self.name = name
  22. self.age = age
  23. self.salary = salary
  24. try:
  25. p1 = People(123, 18, 3333.3) # 传入的name因不是字符串类型而抛出异常
  26. except Exception as e:
  27. print(e)

set---> <__main__.People object at 0x1084cd940> 123

Expected <class 'str'>

5.4 大刀阔斧

  1. class Typed:
  2. def __init__(self, name, expected_type):
  3. self.name = name
  4. self.expected_type = expected_type
  5. def __get__(self, instance, owner):
  6. print('get--->', instance, owner)
  7. if instance is None:
  8. return self
  9. return instance.__dict__[self.name]
  10. def __set__(self, instance, value):
  11. print('set--->', instance, value)
  12. if not isinstance(value, self.expected_type):
  13. raise TypeError('Expected %s' % str(self.expected_type))
  14. instance.__dict__[self.name] = value
  15. def __delete__(self, instance):
  16. print('delete--->', instance)
  17. instance.__dict__.pop(self.name)
  18. class People:
  19. name = Typed('name', str)
  20. age = Typed('name', int)
  21. salary = Typed('name', float)
  22. def __init__(self, name, age, salary):
  23. self.name = name
  24. self.age = age
  25. self.salary = salary
  1. try:
  2. p1 = People(123, 18, 3333.3)
  3. except Exception as e:
  4. print(e)

set---> <__main__.People object at 0x1082c7908> 123

Expected <class 'str'>

  1. try:
  2. p1 = People('randy', '18', 3333.3)
  3. except Exception as e:
  4. print(e)

set---> <__main__.People object at 0x1078dd438> randy

set---> <__main__.People object at 0x1078dd438> 18

Expected <class 'int'>

  1. p1 = People('randy', 18, 3333.3)

set---> <__main__.People object at 0x1081b3da0> randy

set---> <__main__.People object at 0x1081b3da0> 18

set---> <__main__.People object at 0x1081b3da0> 3333.3

  • 大刀阔斧之后我们已然能实现功能了,但是问题是,如果我们的类有很多属性,你仍然采用在定义一堆类属性的方式去实现,low,这时候我需要教你一招:独孤九剑

5.4.1 类的装饰器:无参

  1. def decorate(cls):
  2. print('类的装饰器开始运行啦------>')
  3. return cls
  4. @decorate # 无参:People = decorate(People)
  5. class People:
  6. def __init__(self, name, age, salary):
  7. self.name = name
  8. self.age = age
  9. self.salary = salary
  10. p1 = People('randy', 18, 3333.3)
  11. 类的装饰器开始运行啦------>

5.4.2 类的装饰器:有参

  1. def typeassert(**kwargs):
  2. def decorate(cls):
  3. print('类的装饰器开始运行啦------>', kwargs)
  4. return cls
  5. return decorate
  6. @typeassert(
  7. name=str, age=int, salary=float
  8. ) # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
  9. class People:
  10. def __init__(self, name, age, salary):
  11. self.name = name
  12. self.age = age
  13. self.salary = salary
  14. p1 = People('randy', 18, 3333.3)
  15. 类的装饰器开始运行啦------> {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>}

5.5 刀光剑影

  1. class Typed:
  2. def __init__(self, name, expected_type):
  3. self.name = name
  4. self.expected_type = expected_type
  5. def __get__(self, instance, owner):
  6. print('get--->', instance, owner)
  7. if instance is None:
  8. return self
  9. return instance.__dict__[self.name]
  10. def __set__(self, instance, value):
  11. print('set--->', instance, value)
  12. if not isinstance(value, self.expected_type):
  13. raise TypeError('Expected %s' % str(self.expected_type))
  14. instance.__dict__[self.name] = value
  15. def __delete__(self, instance):
  16. print('delete--->', instance)
  17. instance.__dict__.pop(self.name)
  18. def typeassert(**kwargs):
  19. def decorate(cls):
  20. print('类的装饰器开始运行啦------>', kwargs)
  21. for name, expected_type in kwargs.items():
  22. setattr(cls, name, Typed(name, expected_type))
  23. return cls
  24. return decorate
  25. @typeassert(
  26. name=str, age=int, salary=float
  27. ) # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
  28. class People:
  29. def __init__(self, name, age, salary):
  30. self.name = name
  31. self.age = age
  32. self.salary = salary
  33. print(People.__dict__)
  34. p1 = People('randy', 18, 3333.3)
  35. 类的装饰器开始运行啦------> {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>}
  36. {'__module__': '__main__', '__init__': <function People.__init__ at 0x10797a400>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'name': <__main__.Typed object at 0x1080b2a58>, 'age': <__main__.Typed object at 0x1080b2ef0>, 'salary': <__main__.Typed object at 0x1080b2c18>}
  37. set---> <__main__.People object at 0x1080b22e8> randy
  38. set---> <__main__.People object at 0x1080b22e8> 18
  39. set---> <__main__.People object at 0x1080b22e8> 3333.3

六、描述符总结

  • 描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
  • 描述父是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件.

七、自定制@property

  • 利用描述符原理完成一个自定制@property,实现延迟计算(本质就是把一个函数属性利用装饰器原理做成一个描述符:类的属性字典中函数名为key,value为描述符类产生的对象)

7.1 property回顾

  1. class Room:
  2. def __init__(self, name, width, length):
  3. self.name = name
  4. self.width = width
  5. self.length = length
  6. @property
  7. def area(self):
  8. return self.width * self.length
  9. r1 = Room('alex', 1, 1)
  10. print(r1.area)
  11. 1

7.2 自定制property

  1. class Lazyproperty:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(self, instance, owner):
  5. print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
  6. if instance is None:
  7. return self
  8. return self.func(instance) # 此时你应该明白,到底是谁在为你做自动传递self的事情
  9. class Room:
  10. def __init__(self, name, width, length):
  11. self.name = name
  12. self.width = width
  13. self.length = length
  14. @Lazyproperty # area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
  15. def area(self):
  16. return self.width * self.length
  17. r1 = Room('alex', 1, 1)
  18. print(r1.area)
  19. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  20. 1

7.3 实现延迟计算功能

  1. class Lazyproperty:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(self, instance, owner):
  5. print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
  6. if instance is None:
  7. return self
  8. else:
  9. print('--->')
  10. value = self.func(instance)
  11. setattr(instance, self.func.__name__, value) # 计算一次就缓存到实例的属性字典中
  12. return value
  13. class Room:
  14. def __init__(self, name, width, length):
  15. self.name = name
  16. self.width = width
  17. self.length = length
  18. @Lazyproperty # area=Lazyproperty(area) 相当于'定义了一个类属性,即描述符'
  19. def area(self):
  20. return self.width * self.length
  21. r1 = Room('alex', 1, 1)
  22. print(r1.area) # 先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法
  23. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  24. --->
  25. 1
  26. print(r1.area) # 先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
  27. 1

八、打破延迟计算

  • 一个小的改动,延迟计算的美梦就破碎了
  1. class Lazyproperty:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(self, instance, owner):
  5. print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
  6. if instance is None:
  7. return self
  8. else:
  9. value = self.func(instance)
  10. instance.__dict__[self.func.__name__] = value
  11. return value
  12. # return self.func(instance) # 此时你应该明白,到底是谁在为你做自动传递self的事情
  13. def __set__(self, instance, value):
  14. print('hahahahahah')
  15. class Room:
  16. def __init__(self, name, width, length):
  17. self.name = name
  18. self.width = width
  19. self.length = length
  20. @Lazyproperty # area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
  21. def area(self):
  22. return self.width * self.length
  23. print(Room.__dict__)
  24. {'__module__': '__main__', '__init__': <function Room.__init__ at 0x107d53620>, 'area': <__main__.Lazyproperty object at 0x107ba3860>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
  25. r1 = Room('alex', 1, 1)
  26. print(r1.area)
  27. print(r1.area)
  28. print(r1.area)
  29. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  30. 1
  31. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  32. 1
  33. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  34. 1
  35. print(
  36. r1.area
  37. ) #缓存功能失效,每次都去找描述符了,为何,因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
  38. 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
  39. 1

九、自定制@classmethod

  1. class ClassMethod:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(
  5. self, instance,
  6. owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
  7. def feedback():
  8. print('在这里可以加功能啊...')
  9. return self.func(owner)
  10. return feedback
  11. class People:
  12. name = 'randy'
  13. @ClassMethod # say_hi=ClassMethod(say_hi)
  14. def say_hi(cls):
  15. print('你好啊,帅哥 %s' % cls.name)
  16. People.say_hi()
  17. p1 = People()
  18. 在这里可以加功能啊...
  19. 你好啊,帅哥 randy
  20. p1.say_hi()
  21. 在这里可以加功能啊...
  22. 你好啊,帅哥 randy
  • 疑问,类方法如果有参数呢,好说,好说
  1. class ClassMethod:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(self, instance, owner
  5. ): # 类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
  6. def feedback(*args, **kwargs):
  7. print('在这里可以加功能啊...')
  8. return self.func(owner, *args, **kwargs)
  9. return feedback
  10. class People:
  11. name = 'randy'
  12. @ClassMethod # say_hi=ClassMethod(say_hi)
  13. def say_hi(cls, msg):
  14. print('你好啊,帅哥 %s %s' % (cls.name, msg))
  15. People.say_hi('你是那偷心的贼')
  16. p1 = People()
  17. 在这里可以加功能啊...
  18. 你好啊,帅哥 randy 你是那偷心的贼
  19. p1.say_hi('你是那偷心的贼')
  20. 在这里可以加功能啊...
  21. 你好啊,帅哥 randy 你是那偷心的贼

一十、自定制@staticmethod

  1. class StaticMethod:
  2. def __init__(self, func):
  3. self.func = func
  4. def __get__(
  5. self, instance,
  6. owner): # 类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身
  7. def feedback(*args, **kwargs):
  8. print('在这里可以加功能啊...')
  9. return self.func(*args, **kwargs)
  10. return feedback
  11. class People:
  12. @StaticMethod # say_hi = StaticMethod(say_hi)
  13. def say_hi(x, y, z):
  14. print('------>', x, y, z)
  15. People.say_hi(1, 2, 3)
  16. p1 = People()
  17. 在这里可以加功能啊...
  18. ------> 1 2 3
  19. p1.say_hi(4, 5, 6)
  20. 在这里可以加功能啊...
  21. ------> 4 5 6

描述符(\_\_get\_\_和\_\_set\_\_和\_\_delete\_\_)的更多相关文章

  1. 第3章 文件I/O(2)_文件I/O系统调用及文件描述符

    2. 文件I/O系统调用及文件描述符 2.1 文件I/O系统调用 (1)主要函数 函数 功能 函数 功能 open() 打开文件 read() 读取文件 creat() 创建文件 write() 写入 ...

  2. Python笔记(二十五)_魔法方法_描述符

    描述符的属性方法 __get__(self, instance, owner): 用于访问属性,返回属性的值 __set__(self, instance, value): 用于给属性赋值时,返回属性 ...

  3. Python笔记(4)类__属性与描述符

    部分参考自:http://www.geekfan.net/7862/ 新式类与经典类 2和3不一样,3都是新式类. 新式类和经典类的区别: class A: #classic class " ...

  4. 【转载】Python 描述符简介

    来源:Alex Starostin 链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 关于Python@修饰符的文章可 ...

  5. Python核心编程-描述符

    python中,什么描述符.描述符就是实现了"__get__"."__set__"或"__delete__" 方法中至少一个的对象.什么是非 ...

  6. USB HID报告及报告描述符简介

    在USB中,USB HOST是通过各种描述符来识别设备的,有设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符,报告描述符等等.USB报告描述符(Report Descriptor)是HID ...

  7. python描述符descriptor(一)

    Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作 ...

  8. python高级编程之最佳实践,描述符与属性01

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #最佳实践 """ 为了避免前面所有的 ...

  9. Python面向对象篇(3)-封装、多态、反射及描述符

    1. 多态 多态,最浅显的意识就是同一事物具有多种形态,这很好理解,动物是一个大类,猫类属于动物类,狗类属于动物类,人也是属于动物类,那能理解成,猫.狗.人是一样的吗?当然不是,还有,水,分为液体.固 ...

随机推荐

  1. windows driver 枚举串口

    //枚举串口 NTSTATUS status; HANDLE hKey = NULL; OBJECT_ATTRIBUTES oa; UNICODE_STRING strPath = RTL_CONST ...

  2. 从架构师视角看是否该用Kotlin做服务端开发?

    前言 自从Oracle收购Sun之后,对Java收费或加强控制的尝试从未间断,谷歌与Oracle围绕Java API的官司也跌宕起伏.虽然Oracle只是针对Oracle JDK8的升级收费,并释放了 ...

  3. Java web项目所需技术*(大概)

    实施java 的web项目需要掌握的技术如下: 1.java语言 2.  面向对象分析设计 XML 语言 网页脚本语言 数据库 应用服务器 集成开发环境 .java语言:JSP.Servlet.JDB ...

  4. 自定义View不显示的问题

    问题描述: 我自定义了一个把 SwipeRefreshLayout 和 RecyclerView 封装在一起的 View ,但是发现 List 不能正常的显示出来,本以为是数据源出现问题,debug了 ...

  5. 关于Vue element-ui中诡异问题的解决思路

    最近在做Element-ui项目时总是会出现些异步及其一些诡异问题,关于vue 的异步原理就不多说了,感觉大部分的问题都可以用Vue.nextTick来解决,Vue.nextTick是等DOM二次加载 ...

  6. 201612-2 工资计算 Java

    思路: 税+税后所得A=税前工资S. 因为工资是整百的数,每次减100来判断.好理解但是超时. import java.util.Scanner; //只有90分,超时了 public class M ...

  7. Microsoft SQL server Management Studio工具报错“应用程序的组件中发生了无法处理的异常”

    解决办法 打开目录: C:\Documents and Settings\Administrator\Application Data\Microsoft\Microsoft SQL Server\1 ...

  8. PAT Advanced 1086 Tree Traversals Again (25) [树的遍历]

    题目 An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For exam ...

  9. MySQL--InnoDB 关键特性

    插入缓冲 Insert Buffer 对于非聚集索引的插入或更新操作,不是每一次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入:若不在,则先放入到一个 Insert ...

  10. python pandas写入excel文件

    pandas读取.写入csv数据非常方便,但是有时希望通过excel画个简单的图表看一下数据质量.变化趋势并保存,这时候csv格式的数据就略显不便,因此尝试直接将数据写入excel文件. pandas ...