第4章 面向对象

参考: 面向对象编程, 封装, 继承与派生, 多态与鸭子类型, 绑定方法与非绑定方法, 反射, 内置方法, 元类

一. 列举你所知道的面相对象中的__开头__结尾的方法及作用,越多越好.

"""
__call__: 调用对象触发其类 或者 父类
__new__:  调用类时触发. 在__init__之前
__init__: 调用类时触发. 

__str__: 打印对象时触发
__del__: 对象被回收前触发

__getattr__: 使用点调用属性时属性不存在时触发
__setattr__: 添加/修改属性时触发
__delattr__: 删除属性的时触发

__getattribute__: 使用点调用属性时属性存在或者不存在都触发

__next__: 对迭代器对象进行取值
__iter__: 将可迭代对象转化为迭代器对象(迭代器对象也是可迭代对象)

__enter__: with操作时自动触发, 返回值赋值给as后面的句柄对象
__exit__:  with子代码块执行完毕以后自动触发. 
    三个参数: exc_type, exc_val, exc_db
    第一个参数: 异常类型
    第二个参数: 异常值
    第三个参数: 异常追随信息
    如果返回True则在with语句执行的过程中抛出异常不会影响with之后的语句的正常执行

__getitem__: `对象['属性']`    时自动触发
__setitem__: `对象['属性']=值` 时自动触发
__delitem__: `del ['属性']`   时自动触发

__class__:  获取当前类
__module__: 获取当前模块

__eq__: ==比较时自动触发. 等于号右边对象当作参数传入.
__lt__, __gt__

__doc__: 获取文档描述. (提示: 子类继承, 无法获取)
"""

二. 你所知道的能够实现单例模式的方式有哪些,尝试着手写几个?

"""
定义类方法, 利用类实例化对象自动触发__new__方法, 自定义元类, 函数装饰器, 类装饰器, 导入模块
"""

1. 定义类方法

# settings.py文件内容如下:
"""
host = '127.0.0.1'
port = 8080
"""

import settings
class MySQL:
    _instance = None
    def __init__(self, host, port):
        self.host = host
        self.port = port

    @classmethod
    def singleton(cls):
        if not MySQL._instance:
            MySQL._instance = MySQL(settings.host, settings.port)
        return MySQL._instance

obj1 = MySQL('127.0.0.1', 8080)
obj2 = MySQL('127.0.0.1', 8080)
print(obj1 is obj2)  # False

obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
print(obj1 is obj2)  # True

2. 利用类实例化对象自动触发__new__方法

class MySQL:
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
        return cls._instance


obj1 = MySQL()
obj2 = MySQL()
print(obj1 is obj2)  # True

3. 自定义元类

# settings.py文件内容如下:
"""
host = '127.0.0.1'
port = 8080
"""

import settings
class MyMeta(type):
    def __init__(self, class_name, class_bases, class_dict):
        # self._instance = object.__new__(self)
        # self.__init__(self._instance, settings.host, settings.port)
        self._instance = super().__call__(settings.host, settings.port)
        super().__init__(class_name, class_bases, class_dict)

    def __call__(self, *args, **kwargs):
        if args or kwargs:
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
        return self._instance

class MySQL(metaclass=MyMeta):
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

obj1 = MySQL('127.0.0.1', 8080)
obj2 = MySQL('127.0.0.1', 8080)
print(obj1 is obj2)  # False

obj1 = MySQL()
obj2 = MySQL()
print(obj1 is obj2)  # True

4. 函数装饰器

# settings.py文件内容如下:
"""
host = '127.0.0.1'
port = 8080
"""

import settings
def singleton(cls):
    _instance = cls(settings.host, settings.port)
    def wrapper(*args, **kwargs):
        if args or kwargs:
            return cls(*args, **kwargs)
        return _instance
    return wrapper

@singleton  # MySQL=singleton(MySQL)
class MySQL():
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

obj1 = MySQL('127.0.0.1', 8080)
obj2 = MySQL('127.0.0.1', 8080)
print(obj1 is obj2)  # False

obj1 = MySQL()
obj2 = MySQL()
print(obj1 is obj2)  # True

5. 类装饰器

# settings.py文件内容如下:
"""
host = '127.0.0.1'
port = 8080
"""

import settings
class Singleton:
    _instance = None
    def __init__(self, cls):
        self.cls = cls

    def __call__(self, *args, **kwargs):
        if args or kwargs:
            return self.cls(*args, **kwargs)
        if not self._instance:
            self._instance = self.cls(settings.host, settings.port)
        return self._instance

@Singleton   # MySQL=Singleton(MySQL)
class MySQL():
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

obj1 = MySQL('127.0.0.1', 8080)
obj2 = MySQL('127.0.0.1', 8080)
print(obj1 is obj2)  # False

obj1 = MySQL()
obj2 = MySQL()
print(obj1 is obj2)  # True

6. 导入模块

# singleton.py文件内容如下
"""
class MySQL:
    def __init__(self, host, port):
        self.host = host
        self.port = port

instance = MySQL('127.0.0.1', 8080)
"""

import singleton
obj1 = singleton.MySQL('127.0.0.1', 8080)
obj2 = singleton.MySQL('127.0.0.1', 8080)
print(obj1 is obj2)  # False

obj1 = singleton.instance
obj2 = singleton.instance
print(obj1 is obj2)  # True

三. 什么是元类?元类的应用场景有哪些,能具体说说吗?

"""
什么是元类?
    python之中一切皆对象, 类也是对象. 即可调用类实例化产出对象, 那也可调用元类实例化产生类(type)

应用场景: 
    1. 自定义元类来控制类的产生
    2. 自定义元类控制类的调用(类的对象的产生)    
"""

四. 以下代码输出是什么?请给出答案并解释

class Parent:
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Child1.x = 3
print(Parent.x, Child1.x, Child2.x)

# 答案
'''
1 1 1
1 2 1
1 3 1
'''

五. 简述面相对象的三大特性及特点,其中你认为哪个特性使用频率最高,为什么?

# 面相对象的三大特性及特点
    # 继承: 继承是一种新建类的方式, 新建的类可以继承一个或多个父类. 那么这个新建的类就被称之为子类或者派生类, 子类就可以继承父类的所有属性.
    # 封装: 把数据与功能整合到一起
    # 多态: 同一种事物有多种形态. 多态性可以在不考虑对象具体使用情况的前提下直接使用对象

# 我认为继承使用频率最高
    因为我们书写新建的类继承就不需要写更多的重复代码, 并且最重要的是, 还可以完完全全继承父类的所有属性和方法

六. AOP, OOP, POP

AOP Aspect Oriented Programming  面向切面编程(装饰器)
OOP Object Oriented Programming  面向对象编程(class)
POP Process-oriented programming 面向过程编程 

七. type和object的关系

# 前言: python3中所有的类都继承自object. (包括type)

# 1. type是object的类(object是由type实例化得到)
print(type(object))  # <class 'type'>

# 2. type是type的类  (CPython是基于C语言写的, 通过type的指针指向自己, 来明确自己是自己的类的关系)
print(type(type))   # <class 'type'>

# 3. type继承了object()
class type(object):
    ...
    
# 拓展: 类似于int这种内置的类, 也是由type实例化得到的, 即它们的类就是type
print(type(int))   # <class 'type'>
print(type(dict))  # <class 'type'>    
posted @ 2020-05-11 20:29  给你加马桶唱疏通  阅读(138)  评论(0编辑  收藏  举报