二十四、反射,元类和__call__方法,__new__方法,单例模式

一、isinstance和issubclass

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

class Foo(object):
     pass
  
obj = Foo()
  
isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)

二、反射

反射:是用字符串类型的名字,去操作变量
反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力 
"""反射:是用字符串类型的名字,去操作变量"""


# name = 1
# eval("print(name)")  # 1 容易出现安全隐患


# 反射  就没有安全问题


# 反射对象的属性和方法  hasattr getattr setattr delattr
class A:
    price = 200

    def func(self):
        print("in func")


a = A()
a.name = "alex"
a.age = 18
# 反射对象的属性
# ret = getattr(a, "name")  # alex 通过变量名的字符串形式取到的值
# print(ret)  # alex
# # 反射对象的方法
# """里面是字符串,变成函数和对象的内存地址,加个()就可以调用方法"""
# ret = getattr(a, "func")
# print(ret)  # <bound method A.func of <__main__.A object at 0x00000299778143C8>>
# ret()  # in func

#
# class A:
#     price = 200
#
#     @classmethod
#     def func(cls):
#         print("in func")
#
#
# # 反射类的属性
# # A.price
# ret = getattr(A, "price")
# print(ret)  # 200
# # 反射类的方法 classmethod 和staticmethod
# # A.func()
# if hasattr(A,"func"):  # 如果成立我就执行,不会报错
#     ret = getattr(A, "func")()
# ret() # in func

# 反射模块的属性
# print(res)
# import my
# #
# # print(my.girl)
# ret = getattr(my, "girl")
# print(ret)
#
# # 反射模块的方法
# my.eva()
# if hasattr(my, "eva"):
#     ret = getattr(my, "eva")()
# print(ret)

# 内置模块也能用
import time

# time.sleep()
ret = getattr(time, "sleep")
ret(2)

import sys

year = 2019
print(sys.modules)  # '__main__': <module '__main__'
print(sys.modules["__main__"].year)


def eva():
    print("eva我喜欢听你讲课")


# 反射自己模块中的变量
getattr(sys.modules["__main__"], "year")

# 反射自己模块中的方法
if hasattr(sys.modules["__main__"], "eva"):
    getattr(sys.modules["__main__"], "eva")()

name = input(">>>>>>>>>>:")
print(getattr(sys.modules[__name__], "name"))


# setattr 设置修改变量,没有就添加
class A:
    pass


a = A()
setattr(a, "name", "nezha")
setattr(A, "name", "eva")
print(a.name)
print(A.name)

# delattr  删除
delattr(a, "name")
delattr(A, "name")
# print(a.name)
反射所有

 

二、元类

元类:创建类的类

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

定义类的规则都是从元类那来的

默认情况下所有类的元类都是type,但是type是继承object

创建类的三个要素;

class Person(object):
    name =123
    pass

#1.类名 (字符类型)2.类的父类或基类(元组或列表)3.类的名称空间(字典类型)

 

1.type是继承object

class Person:
    pass


p = Person()
print(type(p))  # <class '__main__.Person'>
print(p.__class__)  # <class '__main__.Person'>
print(type(Person))  # <class 'type'>  元类

type()  #<class 'type'>

2.只要继承了type 那么这个类就变成了一个元类

""" 学习元类的目的:高度自定义一个类
    只要继承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("名字不会写?类名要大写,sb")


# 指定元类
class Pig(metaclass=MyType):
    pass
# 通过__init__方法控制类名(类的属性)
# MyType("pig", (), {})  初始化方法

三、__call__方法的应用

1.自定义__call__方法

class MyMeta(type):
    def __init__(self, name, bases, dict):
        super().__init__(name, bases, dict)
        print("你个铺盖仔")

    def __call__(self, *args, **kwargs):  # 可变参数爱传不传
        print("元类 call run")
        print(self)  # <class '__main__.Dog'>Dog类
        print(args)  # ()('大帅',)把对象属性传参传进来了
        print(kwargs)  # {}字典,传进来
        return super().__call__(*args, **kwargs)


class Dog(metaclass=MyMeta):  # 会走元类init方法  Dog =MyMeta("Dog",(),{})
    def __init__(self, name):
        self.name = name

    def __call__(self, *args, **kwargs):
        print("call run")


d = Dog("大帅")  # 类是元类的对象
print(d.name)
# 当你把类实例化会自动触发元类call方法,*args是位置传参列表元祖,*kwargs是字典"""

2.需求把对象属性改为大写

# 创建元类
class MyType(type):
    def __call__(self, *args, **kwargs):
        new_args = []
        for i in args:
            new_args.append(i.upper())

        # print(new_args)
        print(kwargs)
        return super().__call__(*new_args, **kwargs)  # 执行或覆盖call方法


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


p = Person("wukai", "man")
print(p.name, p.gender)  # WUKAI ,MAN
# 调用自定义元类__call__方法可以修改对象属性
# 注意自定义元类中,重点在于覆盖父类__call__方法,并返回其值
class MyType(type):
    def __call__(self, *args, **kwargs):
       if args:
           raise Exception("顶你的费,不允许,用位置参数传参")

        # print(new_args)
       print(kwargs)
       return super().__call__(*args, **kwargs)  # 执行或覆盖call方法


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


p = Person(name="wukai",gender="man")
p = Person("wukai", "man")
print(p.name, p.gender)
案列:不允许位置参数传参

 

四、__new__方法

当你要创建类对象时,会首先执行元类中__new__方法,先新创建“类对象”,然后自动调用__init__方法,对这个类进行初始化
注意:new方法必须有返回值且必须是 对应的对象"
# 自定义元类
class Meta(type):

    def __new__(cls, *args, **kwargs):
        print(cls)  # 元类自己
        print(args)  # 创建类需要的几个参数:类名 基类 名称空间
        print(kwargs)  # 空字典
        print("run new")
        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("run init")


class A(metaclass=Meta):
    pass


print(A)
# 总结:new方法和init方法都可以实现控制类的创建过程,init更简单些
# a = A()

五、单例模式

设计模式:用于解决某种固定问题的套路
单例:指的是一个类只能产生一个对象
单例目的:单例是为了节省资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象,浪费资源
 单例元类
class Single(type):
    def __call__(self, *args, **kwargs):
        if hasattr(self, "obj"):
            return getattr(self, "obj")
        obj = super().__call__(*args, **kwargs)   # 初始化call方法
        print("new 了")
        self.obj = obj
        return obj


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


stu = Student("jack", 18)
stu = Student("jack", 18)
stu = Student("jack", 18)

 

 

 

 

 

 

posted @ 2019-08-06 18:18  凯帅  阅读(214)  评论(0编辑  收藏  举报