python-数据封装和私有属性

281 阅读3分钟

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模式

  1. mixin类功能单一;
  2. 不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功;
  3. 在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
"""