目录python
exec 模块 是Python内置的一个模块数据库
exec 模块能够把 “字符串形式的” Python代码 添加到全局名称空间或局部名称空间中app
直接调用 exec()code
须要传三个参数:orm
# 全局名称空间 ''' 文本形式的python代码: 以下: ''' code = ''' global x global y x = 10 y = 20 def func(): pass ''' # 全局名称空间 global_dict = {"x":200} # 局部名称空间 local_dict = {} # 传三个参数: # 参数1:字符串形式的Python代码 # 参数2:全局名称空间 # 参数3:局部名称空间 exec(code,global_dict,local_dict) print(global_dict) # {'x': 10,....} print(local_dict) # {'func': <function func at 0x0000000001D01E18>}
一、 用 class 关键字建立对象
# 建立类的第一种方式: class Test: country = "china" def __init__(self,name,age): self.name = name self.age = age def speak(self): print("speak chinese") p1 = Test("qinyj",18) print(Test)
二、 手动调用 type() 实例化出来获得一个自定义的类继承
# 建立类的第二种方式: class_name = "Test" class_base = (object,) class_dict = {} code = ''' name = "Test" def __init__(self,name,age): self.name = name self.age = age def test(self): print("from Test.test...") ''' # 使用exec 模块,目的:将字符串形式的Python代码执行封装到类的名称空间中 exec(code,{},class_dict) ''' type源码: def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__ """ type(object_or_name, bases, dict) type(object) -> the object's type type(name, bases, dict) -> a new type # (copied from class doc) """ 参数说明: what --> 类名 bases --> 基类/父类 dict --> 类的名称空间 ''' Test = type(class_name,class_base,class_dict) print(Test)
元类就是类的类,咱们自定义的类的类是type,type就是全部类的类,type就是一个元类内存
元类能够帮咱们控制类的建立ci
元类能够帮咱们控制类的调用资源
一、 自定义一个元类,继承type,派生出本身的属性和方法
二、 给须要使用的类,经过metaclass 指定自定义的元类
首先咱们自定义一个元类必需要继承type类,而后重写里面的方法。
# 自定义一个元类 class MyMeta(type): # 子类的方法与父类的方法同样,优先用子类的,子类覆盖父类的__init__方法 # 控制了子类的定义方式 def __init__(self,class_name,class_base,class_dict): if not class_name.istitle(): raise TypeError("类的首字母必须大写") if not class_dict.get("__doc__"): raise TypeError("类的内部必需要写注释") super().__init__(class_name, class_base, class_dict) # 模拟type元类内部作的事情 # 元类触发的__call__能够控制类的调用,调用__call__会触发如下两点: # 一、会调用__new__产生一个空对象 # 二、会执行__init__(),把参数传过去,再将实例化出来的对象返回给自定义的类 def __call__(self, *args, **kwargs): obj = object.__new__(self) obj.__init__(*args, **kwargs) return obj # 能够经过元类内部的__new__控制对象的建立 # def __new__(cls, *args, **kwargs): # pass # 首先自定义一个类, # 由于Foo类继承了元类,必须手动继承object class Foo(object,metaclass=MyMeta): ''' 若是定义的类名首字母没有大写则会报错: TypeError: 类的首字母必须大写 若是不写注释则会报错: TypeError: 类的内部必需要写注释 注释:这是一个Foo类 ''' x = 10 def __init__(self,name,age): self.name = name self.age = age def f1(self): print("from Foo.f1") foo = Foo("qinyj",18) # 调用Foo对象,会触发type的__call__方法 # print(foo.f1())
ORM:对象关系映射 --> 映射到数据库MySQL中的数据表
Python中 | MySQL数据库中 |
---|---|
类名 | 表名 |
对象 | 一条记录 |
对象.属性 | 字段 |
这里模拟Django的ORM,为了将数据库的增、删、改、查,所有封装成一个个方法,好比:save,delete,update,select
''' ORM:对象关系映射:----》映射到数据MySQL中的数据表 类名--》表名 对象--》一条记录 对象.属性--》字段 模拟Django的ORM,为了将数据库的增、删、改、查所有封装成一个个的方法: 好比:save、delete、uptate、select ''' 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 # int类型 class IntegerField(Field): def __init__(self,name,column_type="int",primary_key=False,default=0): super().__init__(name,column_type,primary_key,default) # str类型 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:解决代码冗余问题:好比有100张表,须要写100个__init__ 解决1:使用继承,继承父类,继承一个dict 问题2:没法预测每一张表的字段是什么,没法经过父类的__init__解决问题 解决2:经过继承字典,内部的__init__,能够接受任意个数的关键字参数 问题3:继承字典的类实例化的对象,没法经过对象.属性的方式存值 解决3:对象和字典的属性时两个不一样的名称空间,经过在类内部实现魔法方法 __getattr__、__setattr__ 实现字典与对象的名称空间的属性相通,如出一辙, 而且具有字典原有的特性,取值方式和字典同样 ''' ''' 建立元类,元类须要作的事情: 一、一张表必须有一个表名 二、一张数据表必须有一个主键,而且主键必须是惟一的 三、将数据表中全部的字段对象,都存放在一个独立的字典中 存不是目的,取才是目的 ''' class OrmMetaClass(type): # 元类 实现__new__方法 def __new__(cls, class_name,class_base,class_dict): # 过滤 Models 类 if class_name == "Models": # 什么事情都不作,原路返回 return type.__new__(cls, class_name,class_base,class_dict) # 获取数据表的表名 table_name = class_dict.get("table_name",class_name) # 定义主键的中间变量 primary_key = None # 定义字典,存放数据表的字段对象 mappings = {} # 遍历类名称空间中的全部属性 for key,value in class_dict.items(): # 过滤不想要的属性 if isinstance(value,Field): mappings[key] = value # 判断是不是添加了主键 if value.primary_key: # 判断主键的中间变量是否存在 # 若是已经有了就抛异常,只能有一个主键 if primary_key: raise TypeError("只能有一个主键") # 若主键中间的变量没有值,则给中间变量赋值 primary_key = value.name # 若是上述遍历 发现没有定义主键,则抛异常必须有一个主键 if not primary_key: raise TypeError("必须有一个主键") # 循环遍历 把类的名称空间中多余重复的属性删除掉,节省内存资源 for key in mappings.keys(): class_dict.pop(key) # 给类的名称空间添加表名、主键、存放字段对象 属性。 class_dict["table_name"] = table_name class_dict["primary_key"] = primary_key class_dict["mappings"] = mappings return type.__new__(cls, class_name,class_base,class_dict) class Models(dict,metaclass=OrmMetaClass): def __getattr__(self, item): # print(item,"在调用对象.属性没有属性值得时候触发") return self.get(item) def __setattr__(self, key, value): # print(key,value) self[key] = value # 建立用户表类 class User(Models): user_id = IntegerField(name="user_id",primary_key=True) user_name = StringField(name="name") pwd = StringField(name="pwd") # 建立电影类 class Movies(Models): movie_id = IntegerField(name="movie_id",primary_key=True) movie_name = StringField(name="movie_name") user = User(id="001",name="qinyj",pwd="123") print(user) # 经过在类内部实现魔法方法,让对象.属性获得的值和用字典获得的值名称空间相通,取到的值如出一辙, # print(user.get("id")) # user.age = 18 # print(user.age) movie = Movies(id="002",movie_name="真实写真") print(movie)