目錄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)