37、import导入模块
1、import搜索路径
import sys
sys.path
从上面的目录中依次查找要导入的模块文件,列表中的路径的先后顺序代表了python解释器在搜索模块时的先后顺序。
程序执行时添加新的模块路径
sys.path.append("/xx/oo")
sys.path.insert(0, "/yy/zz")
sys.path
import aa
- 1、让python解释器加载 aa .py
- 2、在当前模块定义一个aa变量指向刚刚加载的模块
import aa as AA --> 这样是为了防止程序有其他变量与aa重名,所以导入时给他换了一个名字。
2、重新导入模块
模块被导入之后,import module 不能重新导入模块,重新导入需要reload
import xxoo
xxoo.test()
----test----2
导入xxoo.py模块,模块中包括一个test函数
import xxoo
xxoo.test()
----test----2
对xxoo.py的test函数进行修改后,在进行导入,执行test函数,返现结果并没有改变,这是因为import只会导入一次,即使模块进行了修改,import也不会重新导入。
使用reload进行重新导入
from imp import reload
reload(xxoo)
xxoo.test()
----test----2
多模块开发时模块导入的一个错误案例
from common import RECV_DATA_LIST
from common import HANDLE_FLAG
print(HANDLE_FLAG)
print("HANDLE_FLAG地址:", id(HANDLE_FLAG))
def handle_msg():
"""模拟处理数据"""
print(">>handle_msg")
for i in RECV_DATA_LIST:
print(i)
# HANDLE_FLAG = True # 这样,HANDLE_FLAG就是handle_msg()函数里的一个局部变量,别的函数无法访问
global HANDLE_FLAG
print("全局变量HANDLE_FLAG的地址:", id(HANDLE_FLAG))
HANDLE_FLAG = True
print("修改HANDLE_FLAG值后的地址:", id(HANDLE_FLAG))
def test_handle_msg():
"""模拟测试处理数据"""
print(">>test_handle_msg")
if HANDLE_FLAG: # 无法访问handle_msg里的HANDLE_FLAG,除非在handle_msg里的HANDLE_FLAG前加上global
print("已经处理完")
else:
print("未处理完")
handle_msg()
test_handle_msg()
False
HANDLE_FLAG地址: 1399397680
>>handle_msg
全局变量HANDLE_FLAG的地址: 1399397680
修改HANDLE_FLAG值后的地址: 1399397648
>>test_handle_msg
已经处理完
正确案例,部分代码见下图
from handle_msg import *
from recv_msg import *
from imp import reload
reload(common)
recv_msg()
test_recv_msg()
recv_msg_next()
handle_msg()
test_handle_msg()
recv_msg_next()
>>recv_msg
>>test_recv_msg
[0, 1, 2, 3, 4]
>>recv_msg_next
数据未处理完,等待中....
>>handle_msg
0
1
2
3
4
>>test_handle_msg
已经处理完
>>recv_msg_next
数据处理完,准备接收其他信息
38、元类
类是创建一个对象的代码块。同样,类也是一个对象,python中一切皆对象。元类就是创建类的“东西”。
元类(万物之主)–>类对象–>实例对象
1、动态创建类
# 使用class关键字
def choose_class(name):
if name == "foo":
class Foo():
pass
return Foo
else:
class Boo():
pass
return Boo
myclass = choose_class("foo")
print(myclass)
print(myclass())
<class '__main__.choose_class.<locals>.Foo'>
<__main__.choose_class.<locals>.Foo object at 0x000001C13558F1D0>
# 使用type创建类
# type还有一个完全不同的特性,动态创建类,格式:type(类名,(针对继承问题,由父类名组成的元组,可以为空),{包含属性的字典,名称和值})
Myclass = type("Myclass", (), {})
print(Myclass)
<class '__main__.Myclass'>
使用type创建一个带属性的类
class Foo():
pass
Myclass = type("Myclass", (Foo, ), {"name": "zhangsan", "age": 18})
print(hasattr(Myclass, "name"))
Myclass.__dict__
True
mappingproxy({'__doc__': None,
'__module__': '__main__',
'age': 18,
'name': 'zhangsan'})
使用type创建带方法的类
# 实例方法
def instance_f(self):
print("this is instance function")
# 静态方法
@staticmethod
def static_f():
print("this is static function")
# 类方法
@classmethod
def class_f(cls):
print("this is class function")
Myclass = type("Myclass", (), {"instance_f": instance_f, "static_f": static_f, "class_f": class_f})
mc = Myclass()
mc.instance_f()
mc.static_f()
mc.class_f()
print(Myclass.__dict__)
this is instance function
this is static function
this is class function
{'class_f': <classmethod object at 0x000001C135598358>, '__doc__': None, 'static_f': <staticmethod object at 0x000001C135598320>, '__module__': '__main__', 'instance_f': <function instance_f at 0x000001C135569B70>, '__dict__': <attribute '__dict__' of 'Myclass' objects>, '__weakref__': <attribute '__weakref__' of 'Myclass' objects>}
使用__metaclass__属性创建一个类
class Foo():
__metaclass__ = someting...
...
python创建类Foo的过程:在执行class Foo()这句时,Foo类还没有在内存中创建,python会在类中寻找__metaclass__属性,
如果找到了,python会用它创建类,如果没有找到,就会用内建的type来创建这个类。class
Foo(Bar):
pass
python做了如下的操作:
- 1、Foo中有__metaclass__这个属性吗?如果是,python会通过__metaclass__创建一个名字为Foo的类(对象)
2、如果python没有找到__metaclass__,他会继续在Bar(父类)中寻找__metaclass__属性,并尝试做前面的同样操作
3、如果在任何父类中都找不到__metaclass__,他就会在模块层次中去寻找__metaclass__,并尝试做同样的操作
4、还是没找到的话,python就会用内置的type来创建这个类对象
# python2中
def upper_attr(class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
return type(class_name, class_parents, new_attr)
class Foo():
__metaclass__ = upper_attr
name = "zhangsan"
age = 18
f = Foo()
print(Foo.__dict__)
{'age': 18, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__doc__': None, '__module__': '__main__', 'name': 'zhangsan', '__metaclass__': <function upper_attr at 0x000001C135569BF8>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
# python3中
def upper_attr(class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
return type(class_name, class_parents, new_attr)
# 在创建Foo类对象之间,python会先执行metaclass指向的方法,<==> upper_attr("Foo", (Bar,), {"name": "zhangsan", "age": 18})
class Foo(metaclass=upper_attr):
name = "zhangsan"
age = 18
f = Foo()
print(hasattr(Foo, "name"))
print(hasattr(Foo, "NAME"))
print(f.NAME)
print(Foo.__dict__)
False
True
zhangsan
{'NAME': 'zhangsan', 'AGE': 18, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
上例中使用函数当作元类,可以使用类来当作元类
class Upper_attr_class(type):
def __new__(cls, class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
return super().__new__(cls, class_name, class_parents, new_attr) # super继承type类
# return type(class_name, class_parents, new_attr) # 这个不是oop,因为直接调用了type
# return type.__new__(cls, class_name, class_parents, new_attr) # 复用type.__new__()方法
class Foo(metaclass=Upper_attr_class): # Foo<==>Upper_attr_class("Foo", (), {"name": "lisi", "age": 30})
name = "lisi"
age = 30
foo = Foo()
print(hasattr(Foo, "name"))
print(hasattr(Foo, "AGE"))
print(foo.AGE)
print(Foo.__dict__)
False
True
30
{'NAME': 'lisi', 'AGE': 30, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
ORM模型
ORM模型是在python编程语言后端web框架Django的核心思想,“Object Relational Mapping”,即对象-关系映射。
简单的说,创建一个实例对象,用创建它的类名当作数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能执行对应MySQL语句。
使用元类实现ORM模型
1、创建一个Field类,用于保存数据表的字段名和字段类型
class Field():
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self): # 使用print时,返回下面的形式
return "<%s: %s>" % (self.__class__.__name__, self.name)
class StringField(Field):
def __init__(self, name):
super().__init__(name, "varchar(100)")
class IntegerField(Field):
def __init__(self, name):
super().__init__(name, "bigint")
s = StringField('name')
print(s.__class__.__name__) # 打印创建s实例对象的类的名字
print(s.__str__) # 打印s时,会调用父类的__str__方法
StringField
<bound method Field.__str__ of <__main__.StringField object at 0x000001C135581208>>
2、定义元类,用于创建Model对象
class Modelmetaclass(type):
def __new__(cls, class_name, class_parents, class_attr):
if class_name == "Model":
return super().__new__(cls, class_name, class_parents, class_attr)
mappings = {}
for key, val in class_attr.items():
if isinstance(val, Field): # isinstance() 会认为子类是一种父类类型,考虑继承关系。
# 保存类属性和列的映射关系到mappings字典
print("Found mapping: %s ==> %s" % (key, val)) # 因为val=IntegerField('uid'),会调用Field类里的__str__方法
mappings[key] = val
for k in mappings.keys():
# 将类属性移除,使定义的类字段不污染User类属性,只在实例中可以访问这些key
class_attr.pop(k)
class_attr['__mappings__'] = mappings
class_attr['__table__'] = class_name.lower()
return super().__new__(cls, class_name, class_parents, class_attr)
a = {"key": 12}
print(a.items())
print(a.keys())
print(a.values())
dict_items([('key', 12)])
dict_keys(['key'])
dict_values([12])
class Model(dict, metaclass=Modelmetaclass):
def __init__(self, **kwargs):
# print(kwargs) # {'password': '123', 'email': '110@sina.com', 'name': 'laozhao', 'uid': 1}
super().__init__(**kwargs)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError("'Model' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
for k, v in self.__mappings__.items():
# print(k,v) # email <StringField: email> password <StringField: password> uid <IntegerField: uid> name <StringField: username>
# print(getattr(self, k, None)) # 1 110@sina.com 123 laozhao
fields.append(k)
params.append(getattr(self, k, None))
sql = "insert into {0} {1} values {2}".format(self.__table__, tuple(fields), tuple(params))
print("SQL: %s" % sql)
print("params: %s" % str(params))
使用定义好的ORM接口
class User(Model): # User = Modelmetaclass("User", (Model,), {"uid": IntegerField('uid'), "name": StringField('username'), ...})
uid = IntegerField('uid')
name = StringField('username')
email = StringField('email')
password = StringField('password')
u = User(uid=1, name='laozhao', email="110@sina.com", password="123") # 因为Model继承了dict类,这些值都会以字典格式保存
u.save()
Found mapping: password ==> <StringField: password>
Found mapping: email ==> <StringField: email>
Found mapping: name ==> <StringField: username>
Found mapping: uid ==> <IntegerField: uid>
SQL: insert into user ('email', 'name', 'uid', 'password') values ('110@sina.com', 'laozhao', 1, '123')
params: ['110@sina.com', 'laozhao', 1, '123']