eval/exec内置函数、元类、单例实现方法

eval 内置函数

# 将字符串作为执行目标,得到相应结果

eval 内置函数的使用场景:
    1、执行字符串会得到相应的执行结果
    2、一般用于类型转换,得到dict、list,tuple等

# 将这串字符串写到文件 1.txt 中, 文件中是不带引号的,只是读成字符串到python中
dir_str = "{'a': 1, 'b': 2, 'c': 3}"  

with open(1.txt, 'r', encoding='utf-8') as f:
    data_str = f.read()

"{'a': 1, 'b': 2, 'c': 3}"  =>  {'a': 1, 'b': 2, 'c': 3}
res = eval(data_str)
print(res, type(res))
run==>
{'a': 1, 'b': 2, 'c': 3} <class 'str'>

exec 内置函数

exec 内置函数的使用场景:
    1、执行字符串没有执行结果(没有返回值)
    2、将执行的字符串中产生的名字形成对应的局部名称空间
    
source = '''
name = 'Bob'
age = 20
'''
class A:
    pass
a = A()

dic = {}
# 将source中的数据放入到dic的名称空间字典中
exec(source, {}, dic)
# 将存有数据的dic 赋值给 对象 a 的名称空间
a.__dict__ = dic
print(a.__dict__)  # {'name': 'Bob', 'age': 20}
print(a.name)  # Bob
print(a.age)  # 20

type产生类

# 类是type的对象,可以通过type(参数)来创建类
type(name, bases, namespace)

Python中万物皆对象,所有用来创建对象的类,本身也是对象,类是type类的对象
type类叫做元类,是所有元类的基类
元类:造类的类 - 类的类
      -- 控制类的产生
      -- 控制类的对象的产生
s = '''
my_a = 10
my_b = 20
def __init__(self):
    pass
@classmethod
def print_msg(cls, msg):
    print(msg)
'''
 

dic = {}
exec(s, {}, dic)
# 把s中产生的数据放到dic名称空间中,再把这个名称空间给 类C 
C = type('C', (object, ), dic)
print(C, type(C), C.__bases__)
# <class '__main__.C'> | <class 'type'> | (<class 'object'>,)

c1 = C()
print(c1.my_a)  # 10
c1.print_msg('wjw')  # wjw

自定义元类

# 元类:所有自定义的类本身也是对象,是元类的对象,所有自定义的类实质上是由元类实例化出来的
Student = type('student', (object, ), namespace)

class MyMeta(type):  # 继承元类,那么MyMeta也变成了元类
    自定义一个元类,然后重写__init__方法的目的:
    1、最终的工作(如何开辟空间,如何操作内存)还是要借助type中的功能
    2、该__init__方法是从type中继承来的,所以type的__init__接收到的参数是相同的
    3、在交给type最终完成工作之前,可以对类的创建加以限制 *****
    def __init__(self, className, bases, namespace):
        # 需求:由元类控制的类的类型必须首字母大写
        if not className.istitle():  # 目的 3
            # 自定义异常处理,如果不是大写就报错
            raise NameError('名字首字母必须大写')
            
        # super(MyMeta, cls).__init__(class_name, bases, namespace)
        super().__init__(className, bases, namespace)  # 目的 1 和 2
    
    自定义元类,重写__call__方法的目的:
    1、被该元类控制的类 生成对象 时,会调用元类的__call__方法
    2、在call中的返回值就是创建的对象
    3、在call中
        3.1 -- 通过object开辟空间产生对象
        3.2 -- 用被控制的类回调到自己的init方法完成名称空间的赋值
        3.3 -- 将修饰好的对象反馈给外界
    def __call__(cls, *args, **kwargs):  # 目的 1
        obj = object.__new__(cls)  # 目的 3.1
        # 用object中的__new__方法新建一个名称空间给元类所控制的类的对象
        # 需求:所有通过该元类控制的类产生的对象都有mata_name属性
        obj.meta_name = cls.__name__
        # 在obj名称空间中新建一个 meta_name = cls.__name
        
        # 调回当前被控制的类自身的init方法,完成名称空间的赋值
        cls.__init__(obj, *args, **kwargs)  # 目的 3.2
        return obj  # 目的 2 和 3.3
    
class Student(object, metaclass=MyMeta):  # 继承元类MyMeta
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
# class Student:  <==>  MyMeta/type(className, bases, namespace)

# 测试
stu = Student('Bob', 18)
print(stu, stu.name, stu.age)
# <__main__.Student object at 0x000000000254A7F0> | Bob | 18

stu = Student('Tom', 20)
print(stu.meta_name)  # Student  # call中强制定义的属性也生效了

单例

单例:一个类只能产生一个单例
为什么要有单例:
    1、该类需要对象的产生
    2、对象一旦产生,在任何位置再实例化对象, 只能得到第一次实例化出来的对象
    3、在对象唯一创建后,可以通过属性修改或方法间接修改属性,来完成数据的更新,不能通过实例化方式更新数据
    
    
单例化类的方法:
方法一:
约定用 类名() 的方式来实例化对象, 用类方法来获取唯一对象
class clsName():
    __instance = None
    @classmethod  # 用类直接调用
    def getInstance(cls):
        if get.__instance == None:
            cls.instance = cls()  # 示例化出对象
        return cls.instance  # 返回实例化出来的对象
    
s1 = Songs.getInstance()
s2 = songs.getInstance()
print(s1, s2)
<__main__.Songs object at 0x00000000023835F8>
<__main__.Songs object at 0x00000000023835F8>


方法二:
在类中 重写__new__方法来控制类的实例化
class Songs:
    __instance = None
    def __new__(cls, songName, *args, **kwargs):
        if cls.__instance == None:
            # 调用object的__new__为类的对象创建名称空间
            cls.__instance = object.__new__(cls)
            # 往名称空间中创建一个songName属性
            cls.__instance.songName = songName
        return cls.__instance  # 
    
    # 用来修改对象属性的方法
    def change_song(self, songName):
        self.songName = songName

s1 = Songs('不谓侠')
s2 = Songs('如寄')
print(s1.songName, s2.songName)  # 不谓侠 不谓侠

s2.change_song('如寄')
print(s1.songName, s2.songName)  # 如寄 如寄


方法三:
装饰器认证是否实例化过,不是则实例化,是则不重新实例化
def outter(cls):
    _instance = None
    def inner(*args, **kwargs):
        nonlocal _instance
        if _instance == None:
            instance = cls(*args, **kwargs)
            return instance
    return inner

@outter
class Songs:
    pass


s1 = Songs()
s1 = Songs()
print(s1, s2)


方法四:
元类
class SingleMeta(type):
    __instance = None
    def __call__(cls, *args, **kwargs):
        if SingleMeta.__instance == None:
            SingleMeta.__instance = object.__new__(cls)
            cls.__init__(SingleMeta.__instance, *args, **kwargs)
        return SingleMeta.__instance


class Songs(metaclass=SingleMeta):
    def __init__(self):
        pass
    pass


s1 = Songs()
s2 = Songs()
print(s1, s2)
posted @ 2019-04-26 22:32  输诚  阅读(132)  评论(0编辑  收藏  举报