python3知识点杂记(六)

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也不会重新导入。
image.png

使用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']

未完待续…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值