python高级

138 阅读17分钟

python 高级

python提高

GIL

  1. Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。

  2. GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。

  3. python 使用多进程是可以利用多核的CPU资源的.

  4. 多线程爬取比单线程有提升, 因为遇到IO阻塞会自动释放GIL锁 .

    eg:多线程客户端向服务器请求多个数据 可以一个个发送后 等待回复.

    ​ 但是单线程只能等上一个任务完成后才能发送另一个任务.

  5. 多进程适合高密度计算的程序

    多线程适合多IO操作的程序

深拷贝 浅拷贝

  1. 浅拷贝是拷贝了引用, 不拷贝内容

  2. 深拷贝是对一个对象所有层次进行了拷贝 这个对象改变, 拷贝来对象不改变

  3. 拷贝的其他方式:

    • 分片表达式可以赋值一个序列 eg: b = a[:]
    • copy.copy 方法可以拷贝
  4. 注意点

    • 浅拷贝对不可变类型和可变类型的copy不同

      1. copy.copy对于可变类型, 会进行浅拷贝 仅仅拷贝第一层 假如列表中的列表改变则 浅拷贝的内容也会改变
      2. copy.copy对于不可变类型, 不会拷贝, 仅仅是指向
      In [88]: a = [11,22,33]   # 可变类型 
      In [89]: b = copy.copy(a)     
      In [90]: id(a)
      Out[90]: 59275144
      In [91]: id(b)
      Out[91]: 59525600
      In [92]: a.append(44)
      In [93]: a
      Out[93]: [11, 22, 33, 44]
      In [94]: b
      Out[94]: [11, 22, 33]
          
      #仅仅拷贝第一层,假如列表中的列表改变则 浅拷贝的内容也会改变 
      In [2]: a = [1, 2, [3, 4]]
      In [3]: b = copy.copy(a)
      In [4]: b
      Out[4]: [1, 2, [3, 4]]
      In [5]: a[2][1] = 2
      In [6]: a
      Out[6]: [1, 2, [3, 2]]
      In [7]: b
      Out[7]: [1, 2, [3, 2]]
      
       # 不可变类型 即不可使用append, extend,sort 等要修改自身的操作
      In [95]: a = (11,22,33)  
      In [96]: b = copy.copy(a)
      In [97]: id(a)
      Out[97]: 58890680
      In [98]: id(b)
      Out[98]: 58890680
      
    • copy.copycopy.deepcopy的区别

      1. b = copy.copy(a) 复所有a指向的数据到一个新的空间, 但不会递归copy
      2. b = copy.deepcopy(a)会将c指向的空间进行递copy, 产生两个内容完全一样,但引用不同. 即a指向一个空间 b指向一个新的空间.

私有化

  • xx: 公有变量
  • _x: 单前置下划线, 私有化属性或者方法, 即 from somemodule import *禁止导入, 类对象和子类可以访问.
  • __xx: 双前置下划线, 避免与子类的属性命名冲突, 完全私有 不能导入不能继承 外部不能访问.
  • __xx__: 双前后下划线, 用户名字空间的魔法对象或属性. 是公有属性.
  • xx_: 单后置下划线, 用于避免与python关键字冲突 ,printprint_

import 导入模块

  1. import 搜索路径

    In [2]: import sys
    
    In [3]: sys.path
    Out[3]:
    ['C:\\Users\\58347\\AppData\\Local\\Programs\\Python\\Python37\\Scripts\\ipython.exe',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\python37.zip',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\DLLs',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37',
     '',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\sqlalchemy-1.3.3-py3.7-win-amd64.egg',
     'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\IPython\\extensions',
     'C:\\Users\\58347\\.ipython']
    
    1. 路径搜索
    • 从上面列出的目录里依次查找要导入的模块文件
    • ''表示当前路径
    • 列表中的路径的先后顺序代表了python解释器在搜索模块时的先后顺序
    1. 程序执行时添加新模块

      sys.path.append('/xxx/xxx')
      sys.path.insert(0.'/xxx/xxx')
      
  2. 重新导入模块

    模块被导入后, import module不能重新导入模块, 重新导入需用reload

多继承以及MRO顺序

  1. 单独调用父类的方法

    类方法重写是覆盖父类的方法

    print("******多继承使用类名.__init__ 发生的状态******")
    class Parent(object):
        def __init__(self, name):
            print('parent的init开始被调用')
            self.name = name
            print('parent的init结束被调用')
    
    class Son1(Parent):
        def __init__(self, name, age):
            print('Son1的init开始被调用')
            self.age = age
            Parent.__init__(self, name)
            print('Son1的init结束被调用')
    
    class Son2(Parent):
        def __init__(self, name, gender):
            print('Son2的init开始被调用')
            self.gender = gender
            Parent.__init__(self, name)
            print('Son2的init结束被调用')
    
    class Grandson(Son1, Son2):
        def __init__(self, name, age, gender):
            print('Grandson的init开始被调用')
            Son1.__init__(self, name, age)  # 单独调用父类的初始化方法
            Son2.__init__(self, name, gender)
            print('Grandson的init结束被调用')
    
    gs = Grandson('grandson', 12, '男')
    print('姓名:', gs.name)
    print('年龄:', gs.age)
    print('性别:', gs.gender)
    
    print("******多继承使用类名.__init__ 发生的状态******\n\n")
    

    运行结果

    ******多继承使用类名.__init__ 发生的状态******
    Grandson的init开始被调用
    Son1的init开始被调用
    parent的init开始被调用
    parent的init结束被调用
    Son1的init结束被调用
    Son2的init开始被调用
    parent的init开始被调用
    parent的init结束被调用
    Son2的init结束被调用
    Grandson的init结束被调用
    姓名: grandson
    年龄: 12
    性别: 男
    ******多继承使用类名.__init__ 发生的状态******
    
  2. 多继承中的super调用

    print("******多继承使用super().__init__ 发生的状态******")
    class Parent(object):
        def __init__(self, name, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
            print('parent的init开始被调用')
            self.name = name
            print('parent的init结束被调用')
    
    class Son1(Parent):
        def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
            print('Son1的init开始被调用')
            self.age = age
            super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
            print('Son1的init结束被调用')
    
    class Son2(Parent):
        def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
            print('Son2的init开始被调用')
            self.gender = gender
            super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
            print('Son2的init结束被调用')
    
    class Grandson(Son1, Son2):
        def __init__(self, name, age, gender):
            print('Grandson的init开始被调用')
            # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
            # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
            # super(Grandson, self).__init__(name, age, gender)
            super().__init__(name, age, gender)
            print('Grandson的init结束被调用')
    
    print(Grandson.__mro__)
    
    gs = Grandson('grandson', 12, '男')
    print('姓名:', gs.name)
    print('年龄:', gs.age)
    print('性别:', gs.gender)
    print("******多继承使用super().__init__ 发生的状态******\n\n")
    

    运行结果:

    ******多继承使用super().__init__ 发生的状态******
    (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
    Grandson的init开始被调用
    Son1的init开始被调用
    Son2的init开始被调用
    parent的init开始被调用
    parent的init结束被调用
    Son2的init结束被调用
    Son1的init结束被调用
    Grandson的init结束被调用
    姓名: grandson
    年龄: 12
    性别: 男
    ******多继承使用super().__init__ 发生的状态******
    

    注意:

    • 调用累的__mro__方法会把这个类的所有长辈类(即父类,爷爷类等)通过元组方式列出 例如上面代码中的Grandson类的所有长辈类.

      print(Grandson.__mro__)
      (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
      
    • 如果两个子类中都继承了父类, 当在孙子类中通过子类名调用两个子类时,parent被执行了两次.

      Son1.__init__(self, name, age)
      Son2.__init__(self, name, gender)
      
    • 如果两个父类中都继承了爷爷类, 当在子类中通过surper调用两个父类时,parent被执行了一次.

    super().__init__(name, age, gender)
    
    • 子类重写不会影响父类和其他子类

      父类重写只会影响没有被重写过的子类

      class Parent(object):
          x = 1
      
      class Child1(Parent):
          pass
      
      class Child2(Parent):
          pass
      
      print(Parent.x, Child1.x, Child2.x)
      Child1.x = 2
      print(Parent.x, Child1.x, Child2.x)
      Parent.x = 3
      print(Parent.x, Child1.x, Child2.x)
      

      答案, 以上代码的输出是:

      1 1 1
      1 2 1
      3 2 3 
      

静态方法 and 类方法

  1. 类属性 and 实例属性

    • 类属性属于类, 实例属性属于对象
    • 类属性是对他的对象共享, 实例属性只属于一个对象

    应用场景:

    • 通过类创建实例对象时, 如果每个对象需要具有相同的名字和属性, 那么就使用类属性, 用一份即可.
  2. 实例方法 and 静态方法 and 类方法

    三种方法都属于类, 区别在于调用方式不同.

    • 实例方法: 由对象调用; 至少有一个self参数; 执行实例方法时, 自动调用该方法的对象赋值给self.

    • 类方法: 由类调用; 至少一个cls参数; 执行类方法时, 自动将调用该方法的类赋值给cls;

    • 静态方法: 由类调用; 无默认参数;

      class Foo(object):
          def __init__(self, name):
              self.name = name
          
          def ord_func(self):
              """定义实例方法, 至少有一个self参数"""
              pass
          
          @classmethod
          def class_func(cls):
              """定义类方法. 至少有一个cls参数"""
              pass
          
          @staticmethod
          def static_func():
              """定义静态方法, 无默认参数"""
              pass
      
          
      f = Foo("中国")
      # 调用实例方法
      f.ord_func()
      
      # 调用类方法
      Foo.class_func()
      
      # 调用静态方法
      Foo.static_func()
      

property属性

  1. 使用property

    • 定义时, 在实例方法的基础上添加@property装饰器; 并且仅有一个self参数

    • 调用时, 无需括号

      # ############### 定义 ###############
      class Foo:
          def func(self):
              pass
      
          # 定义property属性
          @property
          def prop(self):
              pass
      
      # ############### 调用 ###############
      foo_obj = Foo()
      foo_obj.func()  # 调用实例方法
      foo_obj.prop  # 调用property属性
      
    • 可以复杂的计算方法封装成一个property属性中, 调用这个属性,返回计算结果.

  2. property属性的两种方式

    • 装饰器 即:在方法上应用装饰器
    • 类属性 即: 在类中定义值为property对象的类属性

    经典类: 具有一种@property装饰器

    class Goods(object):
        @property
        def price(self):
            return 'xx yuan'
    obj = Goods()
    pri = obj.price
    print(pri)
    

    新式类, 具有三种@property装饰器

    class Goods():
        """python3中才有@xxx.setter  @xxx.deleter"""
        @property
        def price(self):
            return self value 
        @price.setter
        def price(self, value):
            self.value = value
        @price.deleter
        def price(self):
            pass
    obj = Goods()
    obj.price  # 自动执行@property修饰的price方法,并获取返回值
    obj.price = 123 # 自动----,并将123赋值给方法的参数
    del obj.price
    

魔法属性

  1. __doc__
  • 表示类的描述信息
class Foo:
    """ 描述类信息,这是用于看片的神奇 """
    def func(self):
        pass

print(Foo.__doc__)
#输出:类的描述信息
  1. __module____class__
  • module 表示当前操作的对象在那个模块
  • class 表示当前操作的对象的类是什么
test.py
# -*- coding:utf-8 -*-

class Person(object):
    def __init__(self):
        self.name = 'laowang'
main.py
from test import Person

obj = Person()
print(obj.__module__)  # 输出 test 即:输出模块
print(obj.__class__)  # 输出 test.Person 即:输出类
  1. __init__
  • 初始化方法,通过类创建对象时,自动触发执行
class Person:
    def __init__(self, name):
        self.name = name
        self.age = 18


obj = Person('laowang')  # 自动执行类中的 __init__ 方法
  1. __del__
  • 当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo:
    def __del__(self):
        pass
  1. __call__
  • 对象后面加括号,触发执行。

注:__init__方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 执行 __init__
obj()  # 执行 __call__
  1. __dict__
  • 类或对象中的所有属性

类的实例属性属于对象;类中的类属性和方法等属于类,即:

class Province(object):
    country = 'China'

    def __init__(self, name, count):
        self.name = name
        self.count = count

    def func(self, *args, **kwargs):
        print('func')

# 获取类的属性,即:类属性、方法、
print(Province.__dict__)
# 输出:{'__dict__': <attribute '__dict__' of 'Province' objects>, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>, 'func': <function Province.func at 0x101897950>, '__init__': <function Province.__init__ at 0x1018978c8>}

obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}

obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
  1. __str__
  • 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo:
    def __str__(self):
        return 'laowang'


obj = Foo()
print(obj)
# 输出:laowang
  1. __getitem____setitem____delitem__
  • 用于索引操作,如字典。以上分别表示获取、设置、删除数据
# -*- coding:utf-8 -*-

class Foo(object):

    def __getitem__(self, key):
        print('__getitem__', key)

    def __setitem__(self, key, value):
        print('__setitem__', key, value)

    def __delitem__(self, key):
        print('__delitem__', key)


obj = Foo()

result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'laowang'   # 自动触发执行 __setitem__
del obj['k1']           # 自动触发执行 __delitem__

9.__getslice____setslice____delslice__

  • 该三个方法用于分片操作,如:列表
# -*- coding:utf-8 -*-

class Foo(object):

    def __getslice__(self, i, j):
        print('__getslice__', i, j)

    def __setslice__(self, i, j, sequence):
        print('__setslice__', i, j)

    def __delslice__(self, i, j):
        print('__delslice__', i, j)

obj = Foo()

obj[-1:1]                   # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
del obj[0:2]                # 自动触发执行 __delslice__

上下文管理器

任何实现了 __enter__()__exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。

那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 enter() 和 exit() 方法。

class File():

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        print("entering")
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, *args):
        print("will exit")
        self.f.close()

__enter__() 方法返回资源对象,这里就是你将要打开的那个文件对象,__exit__()方法处理一些清除工作。

因为 File 类实现了上下文管理器,现在就可以使用 with 语句了。

with File('out.txt', 'w') as f:
    print("writing")
    f.write('hello, python')

这样,你就无需显示地调用 close 方法了,由系统自动去调用,哪怕中间遇到异常 close 方法也会被调用。

实现上下文管理器的另外方式

Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。

from contextlib import contextmanager

@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()

调用

with my_open('out.txt', 'w') as f:
    f.write("hello , the simplest context manager")

总结

Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。

mysql

python与mysql交互

  1. python操作mysql的步骤

![img](file:///media/charlie/%E6%96%B0%E5%8A%A0%E5%8D%B71/work_station/%E6%96%87%E6%A1%A3/Python%E9%AB%98%E7%BA%A7-%E5%85%A8%E9%83%A8%EF%BC%88html%E7%89%88%EF%BC%89/Images/assets/WechatIMG9052.jpeg)

引入模块

在py文件中引入pymysql模块

from pymysql import *

Connection 对象

用于建立与数据库的连接

创建对象:调用connect()方法

conn=connect(参数列表)

参数host:连接的mysql主机,如果本机是'localhost'

参数port:连接的mysql主机的端口,默认是3306

参数database:数据库的名称

参数user:连接的用户名

参数password:连接的密码

参数charset:通信采用的编码方式,推荐使用utf8

对象的方法

close()关闭连接

commit()提交

cursor()返回Cursor对象,用于执行sql语句并获得结果

Cursor对象

用于执行sql语句,使用频度最高的语句为select、insert、update、delete

获取Cursor对象:调用Connection对象的cursor()方法

cs1=conn.cursor()

对象的方法

close()关闭

execute(operation [, parameters ])执行语句,返回受影响的行数,主要用于执行insert、update、delete语句,也可以执行create、alter、drop等语句

fetchone()执行查询语句时,获取查询结果集的第一个行数据,返回一个元组

fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回

对象的属性

rowcount只读属性,表示最近一次execute()执行后受影响的行数

connection获得当前连接对象
  1. 增删改
from pymysql import *

def main():
    # 创建Connection连接
    conn = connect(host='localhost',port=3306,database='jing_dong',user='root',password='mysql',charset='utf8')
    # 获得Cursor对象
    cs1 = conn.cursor()
    # 执行insert语句,并返回受影响的行数:添加一条数据
    # 增加
    count = cs1.execute('insert into goods_cates(name) values("硬盘")')
    #打印受影响的行数
    print(count)

    count = cs1.execute('insert into goods_cates(name) values("光盘")')
    print(count)

    # # 更新
    # count = cs1.execute('update goods_cates set name="机械硬盘" where name="硬盘"')
    # # 删除
    # count = cs1.execute('delete from goods_cates where id=6')

    # 提交之前的操作,如果之前已经之执行过多次的execute,那么就都进行提交
    conn.commit()

    # 关闭Cursor对象
    cs1.close()
    # 关闭Connection对象
    conn.close()

if __name__ == '__main__':
    main()
  1. 查询一行

    from pymysql import *
    
    def main():
        # 创建Connection连接
        conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')
        # 获得Cursor对象
        cs1 = conn.cursor()
        # 执行select语句,并返回受影响的行数:查询一条数据
        count = cs1.execute('select id,name from goods where id>=4')
        # 打印受影响的行数
        print("查询到%d条数据:" % count)
    
        for i in range(count):
            # 获取查询的结果
            result = cs1.fetchone()
            # 打印查询的结果
            print(result)
            # 获取查询的结果
    
        # 关闭Cursor对象
        cs1.close()
        conn.close()
    
    if __name__ == '__main__':
        main()
    
  2. 查询多行

    from pymysql import *
    
    def main():
        # 创建Connection连接
        conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')
        # 获得Cursor对象
        cs1 = conn.cursor()
        # 执行select语句,并返回受影响的行数:查询一条数据
        count = cs1.execute('select id,name from goods where id>=4')
        # 打印受影响的行数
        print("查询到%d条数据:" % count)
    
        # for i in range(count):
        #     # 获取查询的结果
        #     result = cs1.fetchone()
        #     # 打印查询的结果
        #     print(result)
        #     # 获取查询的结果
    
        result = cs1.fetchall()
        print(result)
    
        # 关闭Cursor对象
        cs1.close()
        conn.close()
    
    if __name__ == '__main__':
        main()
    

元类

元类就是用来创建类的东西

type就是Python在背后用来创建所有类的元类

type 的创建类的方式

  • type("类名",(父类名,),{"类属性名":"类属性值",})

    eg : type("son",("father",),{"num1":"100", "num2":"200"})

  • 如果要创建类中带有实例方法 需要先创建好一个实例方法

    eg: type("son",("father",),{"num1":"100", "实例方法名 ":xxxx}) xxx是一个函数

    def sltest(self):
        print("this is 实例方法")
    test = type("test", (), {"wtest":wtest})
    
  • 如果要创建的类中带有类方法 需要先创建好一个类方法

    eg: type("son", (), {"num1":"100", "类方法名 ":xxxx}) xxx是一个类方法

    @classmethod
    def ltest(cls):
        print("this is 类方法")
        pass
    test = type("test", (), {"ltest":ltest})
    

__metaclass__

  • 在创建类的时候添加__metaclass__属性 python就会使用元类来创建类

    def create_class(class_name, class_parents, class_attr):
        return type(class_name, class_parents, class_attr)
       
    class Foo(object, metaclass = create_class):
        num1 = 100
    

    Python做了如下的操作:

    1. Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
    2. 如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
    3. 如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
    4. 如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
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

    #调用type来创建一个类
    return type(class_name, class_parents, new_attr)

class Foo(object, metaclass=upper_attr):
    bar = 'bip'

print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))

f = Foo()
print(f.BAR)

__new__

class UpperAttrMetaClass(type):
	# __new__实在__init__之前被调用的方法
	# __new__使用来创建对象并返回之的方法
	# __new__的返回值当做self给__init__
	# 而__init__只是用来将传入的参数初始化给对象
	# 很少用到__new__, 除非你希望能够控制对象的创建
	# 这里创建的对象是类, 我们希望能够自定义它, 所以我们这里改写了__new__
	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


		# 方法1: 通过'type'来做类对象的创建
		return type(class_name, class_parents, new_attr)

		# 方法2:复用type.__new__方法
        # 这就是基本的OOP编程,没什么魔法
        # return type.__new__(cls, class_name, class_parents, new_attr)  #不懂


class Foo(object, metaclass=UpperAttrMetaClass):
	bar = "bip"

print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:'bip'

不懂看博客blog.csdn.net/qq_41020281…

  • 就元类本身而言,很简单:
    1. 拦截类的创建
    2. 修改类
    3. 返回修改后的类

元类实现ORM

orm是什么

  • ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。
  • 一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句

demo:

class User(父类省略):
    uid = ('uid', "int unsigned")
    name = ('username', "varchar(30)")
    email = ('email', "varchar(30)")
    password = ('password', "varchar(30)")
    ...省略...


u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()
# 对应如下sql语句
# insert into User (username,email,password,uid)
# values ('Michael','test@orm.org','my-pwd',12345)