3-7 数据封装和私有属性
私有属性:
在属性前加上双下划线__, python内部会对该属性名称进行转换,转换为:_类名__私有属性名。使得外部对象不能直接调用__私有属性,实质上并没有做到数据安全。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "David"
# Date: 2019-04-07
import time
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return f"{self.year}/{self.month}/{self.day}"
class User:
def __init__(self, birthday):
self.__birthday = birthday # self.__birthday <==> self._User__birthday
def get_age(self):
return time.localtime().tm_year - self.__birthday.year
class Student(User):
def __init__(self, birthday):
super().__init__(birthday)
self.__birthday = birthday # self.__birthday <==> self._Student__birthday
user = User(Date(1995, 12, 12))
print(user.get_age())
print(user._User__birthday)
stu = Student(Date(1997, 8, 4))
print(stu.get_age())
print(stu._Student__birthday)
"""
私有属性:
在属性前加上双下划线__, python内部会对该属性名称进行转换,转换为:_类名__私有属性名
"""
3-8 python对象的内省机制
如果需要看到类和对象内部的结构时,可以使用__dict__和dir来查看。
class Person:
kind = 'person'
class Student(Person):
def __init__(self, name):
self.name = name
if __name__ == '__main__':
stu = Student('david')
print(stu.__dict__) # {'name': 'david'}
print(Person.__dict__)
"""
{'__module__': '__main__', 'kind': 'person', '__dict__': <attribute '__dict__' of 'Person' objects>,
'__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
"""
# 直接操作对象的__dict__
stu.__dict__['age'] = 18
print(stu.age) # 18
# 列出对象的所有属性和方法,比__dict__强大
print(dir(stu))
"""
['__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__', 'age', 'kind', 'name']
"""
# 对列表进行__dict__和dir
li = [1, 2, 3]
print(dir(li))
print(li.__dict__) # 会报错
3-9 super真的是调用父类吗?
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "David"
# Date: 2019-04-07
"""
问题1:既然重写了构造函数,为什么还要去调用super
"""
from threading import Thread
class MyThread(Thread):
def __init__(self, name, user):
self.user = user
# super(MyThread, self).__init__(name=name) # Python2的写法
super().__init__(name=name) # python3的写法,针对问题1,调用super可以避免重复造轮子的问题发生。此处,父类中已实现name属性
"""
问题2:super的执行顺序是怎样的?
"""
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__()
d = D()
print(D.__mro__)
"""
super不是简单的去调用父类的__init__方法,而是根据__mro__顺序,去调用类中的__init__方法。
D
B
C
A
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
"""
3-10 mixin模式特点
Mixin模式
- mixin类功能单一;
- 不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功;
- 在mixin中不要使用super这种用法;
3-11 python中的with语句
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "David"
# Date: 2019-04-07
def exe_try():
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
if __name__ == '__main__':
ret = exe_try()
print(ret)
"""
code started
key error
finally
4 # 此处返回4原因是,代码被捕获到KeyError进入逻辑中,本该返回2,此时会放入一个堆栈中,直到走到finally,将4放入栈顶,取栈顶返回。
"""
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "David"
# Date: 2019-04-07
class Sample:
"""
上下文管理器协议:需要实现__enter__和__exit__,二者组成了上下文协议,可以通过with调用
"""
def __enter__(self):
print('enter')
# 获取资源
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# 释放资源
print('exit')
def do_something(self):
print('do something')
with Sample() as sample:
sample.do_something()
"""
enter # 首先调用__enter__获取资源
do something # 对资源进行操作
exit # 最后调用__exit__释放资源
"""
3-12 contextlib简化上下文管理器
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "David"
# Date: 2019-04-07
import contextlib
@contextlib.contextmanager
def file_open(file_name):
print('file open') # 可以理解为实现__enter__
yield {} # 此处必须要实现生成器, 可以理解为实现do_something
print('file end') # 可以理解为实现__exit__
with file_open('david.txt') as f:
print('file processing')
"""
file open
file processing
file end
"""