面向对象(五)

一、反射

  1.什么是反射

    反省,自省的意思

    反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力

    反射就是通过字符串操作属性

  2.涉及四个函数,这四个函数就是普通的内置函数,没有双下划线,与print等等没有区别

    (1)hasattr:判断某个对象是否存在某个属性

    (2)getattr:从对象中取出属性,第三个值为默认值,当属性不能存在时返回默认值

    (3)setattr:为对象添加新的属性

    (4)delattr:从对象中删除属性

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

p = Person("jack", 18, "man")

if hasattr(p, "name"):
    print(getattr(p, "name", None))

setattr(p, "id", 123)
print(p.id)

delattr(p, "id")
print(p.id)

  3.使用场景

    反射其实就是对属性的增删改查,也被称之为框架的基石

    因为框架设计者不可能提前知道你的对象到底是怎么设计的

    所以你提供给框架的对象,必须通过判断验证后才能正常使用

    而这判断验证就是反射要做的事情

  4.例子

# 需求:要实现一个用于处理用户的终端指令的小框架
# 框架就是已经实现了最基础的构架,就是所有项目都一样的部分
import importlib

from day24 import plugins
from day24 import settings
def run(plugin):
    while True:
        cmd = input("请输入指令:")
        if cmd == 'exit':
            break
        # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测
        # 判断对象是否具备处理这个指令的方法
        if hasattr(plugin,cmd):
            # 取出对应方法
            func = getattr(plugin,cmd)
            func()  # 执行方法处理指令
        else:
            print("该指令不受支持")
    print("see you la la")

# 创建一个插件对象,调用框架来使用它
wincmd = plugins.WinCMD()
# 框架之外的部分就有自定义对象来完成linux = plugins.LinuxCMD()
run(linux) # 框架得根据配置文件拿到需要的类 path = settings.CLASS_PATH # 从配置中单独拿出来模块路径和类名称 module_path,class_name = path.split(".",1) # 拿到模块 mk = importlib.import_module(module_path) # 拿到类 cls = getattr(mk,class_name) # 实例化对象 obj = cls() # 调用框架 run(obj)

  插件部分

class WinCMD:
    def cd(self):
        print("wincmd 切换目录...")
    def delete(self):
        print("wincmd 要不要删库跑路...")
    def dir(self):
        print("mycmd 切换目录...")

class LinuxCMD:
    def cd(self):
        print("Linuxcmd 切换目录...")
    def rm(self):
        print("Linuxcmd 要不要删库跑路...")
    def ls(self):
        print("Linuxcmd 列出所有文件...")

  配置文件

CLASS_PATH = "libs.pliugins.LinuxCMD"

二、元类

  1.元类是什么

    用于创建类的类,万物皆对象,类当然也是对象

    对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的

  2.默认情况下所有类的元类都是type

class Person:
    pass
p = Person()

print(type(p))
print(type(Person))

Person类是通过type类实例化产生的 

  3.一个类的三个基本组成部分

    (1)类的名字(字符类型)

    (2)类的父类们(是一个元组或列表)

    (3)类的名称空间(字典类型)

cls_obj = type("dog",(),{})
print(cls_obj)

  4.目的

    高度的自定义一个类,例如控制类的名字必须以大驼峰的方式来书写

    类也是对象,也有自己的类

    我们的需求是创建类对象做一些限制

    想到了初始化方法 我们只要找到类对象的类(元类),覆盖其中init方法就能实现需求

    当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

"""
只要继承了type 那么这个类就变成了一个元类
"""
# 定义了一个元类
class MyType(type):
    def __init__(self,clss_name,bases,dict):
        super().__init__(clss_name,bases,dict)
        print(clss_name,bases,dict)
        if not clss_name.istitle():
            raise Exception("你丫的 类名不会写...")

# 为pig类指定了元类为MyType
class Pig(metaclass=MyType):
    pass

class Duck(metaclass=MyType):
    pass

  5.元类中call方法

    当你调用类对象时会自动执行元类中的__call__方法,并将这个类本身作为第一个参数传入,以及后面的一堆参数

    覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建并返回其返回值

  6.使用场景

    当你想要控制对象的创建过程时,就覆盖call方法

    当你想要控制类的创建过程时,就是覆盖init方法

  7.例子

# 实现将对象的所有属性名称转为大写

class MyType(type):
    def __call__(self, *args, **kwargs):
        new_args = []
        for a in args:
            new_args.append(a.upper())

        print(new_args)
        print(kwargs)
        return super().__call__(*new_args,**kwargs)

class Person(metaclass=MyType):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

p = Person("jack",gender="woman")
print(p.name)
print(p.gender)

  注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

三、new方法

  1.当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作

    注意:如果你覆盖了该方法则必须保证new方法必须有返回值且必须是对应的类对象

  2.测试

class Meta(type):

    def __new__(cls, *args, **kwargs):
        print(cls) # 元类自己
        print(args) # 创建类需要的几个参数  类名,基类,名称空间
        print(kwargs) #空的
        print("new run")
        # return super().__new__(cls,*args,**kwargs)
        obj = type.__new__(cls,*args,**kwargs)
        return obj
    def __init__(self,a,b,c):
        super().__init__(a,b,c)
        print("init run")
class A(metaclass=Meta):
    pass
print(A)

  总结new方法和init都可以实现控制类的创建过程,init更简单

四、单例设计模式

  1.设计模式

    用于解决某种固定问题的套路

    例如:MVCMTV等

  2.单例

    指的是一个类产生一个对象

  3.为什么要使用单例

    单例是为了节省资源,当一个类的所有属性全部相同时,则没有必要创建多个对象

  4.元类实现

class Single(type):
    def __call__(self, *args, **kwargs):
        if hasattr(self,"obj"): #判断是否存在已经有的对象
            return getattr(self,"obj") # 有就返回

        obj = super().__call__(*args,**kwargs) # 没有则创建
        print("new 了")
        self.obj = obj # 并存入类中
        return obj

class Student(metaclass=Single):
    def __init__(self,name):
        self.name = name

class Person(metaclass=Single):
    pass

# 只会创建一个对象
Person()
Person()

  5.冒泡算法 

    总结规律
    圈数 是元素个数减一
    次数 元素个数 - 1 - (圈数索引)

ls = [2,1,3,5,100,24,12,12,1,2,1,1,4,32]
for i in range(len(ls)-1):
    for j in range(len(ls)-1-i):
        # 如果前面的小于后面的则交换位置
        if ls[j] > ls[j+1]:
            ls[j],ls[j+1] = ls[j+1],ls[j]
print(ls)

  6.选择算法

ls = [2,1,3,5,100,24,12,12,1,2,1,1,4,32]
for i in range(len(ls)-1):
    for j in range(i,len(ls)):
        # 如果前面的小于后面的则交换位置
        if ls[i] > ls[j]:
            ls[i],ls[j] = ls[j],ls[i]
print(ls)

 

posted @ 2019-07-30 19:36  静心学  阅读(126)  评论(0)    收藏  举报