day38总结

exec补充

# 全局名称空间
# # 1.文本形式的python代码
code = '''
global x
x = 10
y = 20
'''

# 2.全名的名称空间 {}
global_dict = {'x': 200}

# 3.局部名称空间 {}
local_dict = {}

exec(code, global_dict, local_dict)

print(global_dict)


# 局部名称空间
# 1.文本形式的python代码
code = '''
x = 100
y = 200
def func():
    pass
'''

# 2.全名的名称空间 {}
global_dict = {}

# 3.局部名称空间 {}
local_dict = {}

exec(code, global_dict, local_dict)

# print(global_dict)

print(local_dict)

元类

'''
在python中,一切皆对象。
'''


# class Chinese:
#
#     country = 'China'
#
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
#     def speak(self):
#         print('speak Chinese...')
#
#
# p1 = Chinese('tank', 18)
# print(Chinese)
# print(p1)
# print(type(p1))  # Chinese
# print(type(Chinese))  # <class 'type'>

'''
- 创建类有两种方式:
    1.通过class关键字创建类,内部会自动调用type(),type帮我们创建一个自定义类。
    2.通过手动调用type()实例化得到自定义的类。

'''

# type() ---> Chinese
# type() ---> Chinese() ---> p1
#  what: 类名 --> type对象的名称
#  bases: --> 基类/父类
#  dict: --> 类的名称空间
# class_name = 'Chinese'
# class_base = (object, )
# class_dict = {}
# code = '''
# country = "China"
# def __init__(self, name, age):
#     self.name = name
#     self.age = age
# def speak(self):
#     print("speak Chinese...")
# '''
# exec(code, {}, class_dict)
# Chinese = type(class_name, class_base, class_dict)
# print(Chinese)



'''
1.什么是元类?
    元类就是类的类,Chinese类的类是type,type是所有类的类,type就是一个元类。
    
2.元类的作用?
    元类可以帮我们控制类的创建。

3.怎么自定义创建元类:   
    1) 自定义一个元类,继承type,派生出自己的属性与方法。
    2) 给需要使用的类,通过metaclass指定自定义好的元类。
        - class Chinese(metaclass='自定义的元类'):
'''


# 自定义元类
class MyMeta(type):
    # 子类的方法与父类的方法一样,先用子类的,子类覆盖父类的__init__方法。
    # 控制了类的定义
    def __init__(self, class_name, class_base, class_dict):
        # print(class_name)

        # 判断字符串首字母是否大写
        if not class_name.istitle():
            raise TypeError('类的首字母必须大写!')

        # 控制类中必须要有注释
        if not class_dict.get('__doc__'):
            raise TypeError('类内部必须要写注释!')

        # print(class_base)
        # print(class_dict)
        super().__init__(class_name, class_base, class_dict)

    # 模拟type元类内部做的事情
    # 元类触发的__call__可以控制类的调用。调用__call__会触发以下两点
    def __call__(self, *args, **kwargs):
        # 1.会调用__new__()--> obj, 会创建一个空对象。
        obj = object.__new__(self)
        # 2.会执行__init__(obj, *args, **kwargs),
        obj.__init__(*args, **kwargs)
        return obj

    # 可以通过元类内部的__new__控制对象的创建
    def __new__(cls, *args, **kwargs):
        pass


class Bar:
    pass


# metaclass ---> 自定义的元类
# 因为Foo类继承了元类,必须手动继承object
class Foo(Bar, metaclass=MyMeta):  # MyMeta(Foo, Foo_name, (Bar, ), foo_dict)
    '''
    这是一个Foo类
    '''
    # 摊开坦克
    x = 10

    def __init__(self, y, z):
        self.y = y
        self.z = z

    def f1(self):
        print('from Foo.f1...')


foo = Foo(20, 30)  # 调用Foo对象,会触发__call__

ORM

'''
ORM: 对象关系映射 ---> 映射到数据库MySQL中的数据表

类名 ---> 表名
对象 ---> 一条记录
对象.属性 ---> 字段

模拟Django的ORM,为了,将数据库的 增、删、改、查,全部封装成
一个个的方式,比如: save, delete, update, select。
'''


# 1.创建字段的类型, 对应数据表中的一个个字段的创建规范
# class Field:
#     def __init__(self, name, column_type, primary_key, default):
#         self.name = name
#         self.column_type = column_type
#         self.primary_key = primary_key
#         self.default = default
#
#
# # Integer
# class IntegerField(Field):
#     def __init__(self, name, column_type='int', primary_key=False, default=0):
#         super().__init__(name, column_type, primary_key, default)
#
#
# # String
# class StringField(Field):
#     def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
#         super().__init__(name, column_type, primary_key, default)
#
#
# # class Father:
# #     def __init__(self, *args, **kwargs):
# #         self.id = id
# #         self.username = args[0]
# #         self.password = args[1]
# #         self.photo = args[2]
#
#
# class Models(dict):
#
#     # 会在 对象.属性 没有时 触发
#     def __getattr__(self, item):
#         print(item, '调用没有的属性时会触发...')
#         # 将字典中key对应的值,返回给对象
#         return self.get(item)  # dict_obj.get(key)
#
#     # 在 对象.属性=值 时触发
#     def __setattr__(self, key, value):
#         print(key, value)
#         # 给字典对象本身赋值
#         self[key] = value
#
#
# # 创建数据表类
# # 用户表类
# class User(Models):  # ---> 表名
#     # 强调: 最好与字段类型的name属性同名
#     user_id = IntegerField(name='user_id')
#     user_name = StringField(name='name')  # tank
#     pwd = StringField(name='pwd')  # 123
#     pass
#
#
# # 电影表类
# class Movie(Models):
#     pass
#
#
# user = User(id='007', name='tank', pwd='123')  # ---> 一条记录
# # print(user)
# # print(type(user))
#
# movie = Movie(m_id='1', movie_name='jason真实写真')
# print(movie)
# print(type(movie))

# 字典的取、存值方式
# print(user['id'])
# user['age'] = 18
# print(user.get('id'))
# print(user.get('age'))

# user.age = 18  # {key: value}
# print(user.age)
#
# user.sex = 'male'
# print(user.sex)  # None ---> return self.get(sex) --> 'male'
# print(user['sex'])  # male
# print(user.__dict__)


'''
问题1: 解决代码荣誉问题,比如有100张表,需要写100次__init__。
解决1: 继承一个父类,父类中定义一个__init__。

问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。
解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。

问题3: 继承字典的类实例化的对象,无法通过“对象.属性”的方式存取值。
解决3: 通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性。
    
'''



'''
元类需要处理的问题:
    1.给数据表类,强制必须要有一个主键。
    2.主键必须是唯一的。
    3.
'''

# user_obj = User(user_id=1, user_name='tank', age=18)
# # insert into User(name, age) values('tank', 18);
# user_obj.save()
#
# list1 = []
#
# obj.save()  # obj.table_name,
# sql = 'insert into Movie(name, age, 3, 4, 5, ...) values('tank', 18, 3, 4, 5)'
# # insert into obj.table_name(name, age, 3, 4, 5, ...) values('tank', 18, 3, 4, 5);


# 1.创建字段的类型, 对应数据表中的一个个字段的创建规范
class Field:
    def __init__(self, name, column_type, primary_key, default):
        self.name = name
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default


# Integer
class IntegerField(Field):
    def __init__(self, name, column_type='int', primary_key=False, default=0):
        super().__init__(name, column_type, primary_key, default)


# String
class StringField(Field):
    def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
        super().__init__(name, column_type, primary_key, default)


'''
元类需要处理的问题:
    1.一张表必须要有一个表名。
    2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
    3.将数据表中,所有的字段对象,都存放在一个独立的字典中
        存不是目的,目的是为了取值方便。
'''


class OrmMetaClass(type):
    # def __new__(cls, *args, **kwargs):
    # print(args, 'args............')
    # print(kwargs, 'kwargs........')

    # OrmMetaClass(class, class_name, class_base, class_dict)

    def __new__(cls, class_name, class_base, class_dict):
        # print(class_name, '类名--》表名')
        # print(class_base, '基类/父类')
        # print(class_dict, '类的名称空间')

        # 过滤Models类
        if class_name == 'Models':
            # models类中,什么都不做,将类原路返回。
            return type.__new__(cls, class_name, class_base, class_dict)

        # 1.一张表必须要有表名
        # 假如table_name没有值,则将类名当做表名
        table_name = class_dict.get('table_name', class_name)  # get--> self.table_name

        # 2.主键名
        primary_key = None

        # 3.定义一个空字典, 专门用来存放字段对象
        mappings = {}

        # 遍历名称空间中所有的属性
        for key, value in class_dict.items():
            # print(key, value)
            # 除了有字段,还有其他字段以外的属性
            # 过滤字段对象以外的内容
            if isinstance(value, Field):
                mappings[key] = value

                # 判断字段对象primary_key是否为True
                if value.primary_key:
                    # 先判断初识的primary_key是否有值
                    # 判断主键是否已存在
                    if primary_key:
                        raise TypeError('只能有一个主键!')

                    # 若主键不存在,则给primary_key赋值
                    primary_key = value.name

        # 节省资源: 因为mappings与原类中名称空间中的属性重复,为了节省内存,剔除重复的属性。
        for key in mappings.keys():
            class_dict.pop(key)

        # 判断是否有主键
        if not primary_key:
            raise TypeError('必须有一个主键')

        # 给类的名称空间添加表名
        class_dict['table_name'] = table_name
        # 给类的名称空间添加主键名
        class_dict['primary_key'] = primary_key
        # 给类的名称空间添加一个mappings字典,字典中拥有所有字段属性
        class_dict['mappings'] = mappings
        # print(class_dict)
        return type.__new__(cls, class_name, class_base, class_dict)


class Models(dict, metaclass=OrmMetaClass):  # OrmMetaClass(Models, Models_name, base, class_dict)
    def __getattr__(self, item):
        print(item, '调用没有的属性时会触发...')
        # 将字典的值,返回
        return self.get(item)

    def __setattr__(self, key, value):
        print(key, value)
        self[key] = value


# 用户表类
class User(Models):  # ---> 表名
    # table_name = 'user_info'
    # 强调: 最好与字段类型的name属性同名
    user_id = IntegerField(name='user_id', primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')
    pass


# 用户表类
# class Movie(Models):  # ---> 表名
#     # table_name = 'user_info'
#     # 强调: 最好与字段类型的name属性同名
#     user_id = IntegerField(name='user_id', primary_key=True)
#     user_name = StringField(name='name')
#     pwd = StringField(name='pwd')
#     pass


if __name__ == '__main__':
    print(User.__dict__)

课堂笔记

本周期内容:
1.元类
2.仿优酷项目

    - 元类

今日内容:
0 exec模块的补充
1.是什么?
exec是一个Python内置模块。

2.exec的作用:
'''
x = 10
def func1():
pass
'''
可以把"字符串形式"的python代码,添加到全局空间或局部名称空间中。

3.怎么用:
# 参数1: 字符串形式的python代码
# 参数2: 全局名称空间字典
# 参数3: 局部名称空间字典
调用exec()

1.元类
1.什么是元类?
元类就是类的类,Chinese类的类是type,type是所有类的类,type就是一个元类。

2.元类的作用?
元类可以帮我们控制类的创建。
元类可以帮我们控制类的调用。

3.怎么自定义创建元类:
1) 自定义一个元类,继承type,派生出自己的属性与方法。
2) 给需要使用的类,通过metaclass指定自定义好的元类。

    - class Chinese(metaclass='自定义的元类'):

2.优酷架构
- ATM
- 用户视图层
- 接口层
- 数据层
- dict
- json
优点:
数据可以跨平台。

缺点:
不能存对象,也不能直接获取对象。 {。。。}
不能通过“对象.属性”的方式 存、取值。
存储速度比pickle慢。

  • 选课系统
    • 用户视图层
    • 接口层
    • 数据层
      • models:
        • obj
      • pickle
        优点:
        可以通过“对象.属性”的方式 存、取值。
        能存对象,也能直接获取对象。
        • pickle
      缺点:
      不能跨平台。
  • 优酷
    • 用户视图层
    • 接口层
    • 数据层
      • 存储对象 ---> dict ---> Json ---> MySQL
      • MySQL ---> Json ---> dict ---> 获取对象

3.ORM: 对象关系映射

扫描二维码关注公众号,回复: 7744536 查看本文章

猜你喜欢

转载自www.cnblogs.com/zhm-cyt/p/11794147.html