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
不能跨平台。 - models:
- 优酷
- 用户视图层
- 接口层
- 数据层
- 存储对象 ---> dict ---> Json ---> MySQL
- MySQL ---> Json ---> dict ---> 获取对象
3.ORM: 对象关系映射