globals()函数
python中 globals()
函数可以查看一个内存空间 它以字典的形式存储了变量名 和变量的引用 只有在这个空间里有的变量 才可以使用 这个内存空间中储存了所有定义的全局变量
以及类对象
实例对象
的引用以及所有不需要定义就可以使用的函数 如: print()
next()
list()
都在内建模块__builtin__
中 当使用这些函数时 程序会在globals()所查看的空间中查找 如果没有就在内建模块
中查找 如果还没有找到才会报错
当使用class 类名
定义类时 实际上就已经在这个空间中定义了一个对象key是类名 指向一个空间 所以类也是一个对象
类实际上是一个字典 类的空间中以key的形式储存了变量名 指向一个globals()的空间中的
值
(类属性) 列表
(类属性) 或者函数
(方法)或者指向叫做__init__
的函数(实例属性)
使用type()创建类
class A(object): # 以下要继承的父类
num = 100
def print_b(self): # 普通函数
print(self.num)
@staticmethod
def print_static(): # 带装饰器的函数
print("----haha-----")
@classmethod
def print_class(cls):
print(cls.num)
# 此时使用type 创建的类 有父类 类方法 静态方法 实例方法
# 这个类在globals()的空间中用变量B来存储 而这个类叫做C
B = type("C", (A,), {"print_b": print_b, "print_static": print_static, "print_class": print_class})
a = A()
b = B()
b.print_b() # 结果====> 100
b.print_static() # 结果====> ----haha-----
b.print_class() # 结果====> 100
# 实例对象由类创建 而不管是class的方式还是type的方式创建的类对象 都是由type创建的
b.__class__ # 结果====> __main__.C
b.__class__.__class__ # 结果====> type
a.__class__ # 结果====> __main__.A
a.__class__.__class__ # 结果====> type
# 函数由function 创建 而创建function的 也是type
print_b.__class__ # 结果====> function
print_b.__class__.__class__ # 结果====> type
类与实例对象 都在这个空间中 而类与实例对象的区别在于 类有创建实例对象的功能而实例对象没有创建对象的功能
创建类对象的东西就是元类 元类不仅创建类对象 所有的对象最根本都是元类type
创建的
__metaclass__属性
在定义一个类的时候为其添加__metaclass__
属性
class Foo(Bar, metaclass=something): # python3写法
# python2 写法
# __metaclass__ = something…
pass
- Python会通过
__metaclass__
指定的对象创建一个名字为Foo的类(对象) - 如果Python没有找到
__metaclass__
会继续在Bar(父类)
中寻找__metaclass__
属性 并尝试做和前面同样的操作 - 如果Python在任何父类中都找不到
__metaclass__
它就会在模块层次中去寻找__metaclass__
并尝试做同样的操作 - 如果还是找不到
__metaclass__
Python就会用内置的type
来创建这个类对象
可以在__metaclass__
中放置可以创建一个类的东西: type
或者任何使用到type
的东西都可以
自定义元类
将所有小写属性名变为大写
使用函数:
#-*- coding:utf-8 -*-
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')) # False
print(hasattr(Foo, 'BAR')) # True
f = Foo()
print(f.BAR)
使用真正的class来当做元类:
#coding=utf-8
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
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)
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = 'bip'
# python2的用法
# class Foo(object):
# __metaclass__ = UpperAttrMetaClass
# bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'
继承
自type
的类就可以简单的认为是一个元类
子类
的类对象内存空间
是由父类的__new__
方法来创建的
但是在metaclass
指定元类后 这个类的空间就由原来的父类变为由元类
的__new__
方法来创建
修改元类中__new__
接收到的值实现修改类
直接返回type(.....)
实现完成类对象创建 或者 返回父类type.__new__(cls, .....)
的方法实现完成创建类对象的内存空间
元类的作用:
- 拦截类的创建
- 修改类
- 返回修改之后的类
装饰器
可以给函数
添加功能,元类
可以给类
添加功能
元类实现ORM
ORM 是 python编程语言后端web框架 Django的核心思想 “Object Relational Mapping” 即对象-关系映射 简称ORM
一个句话理解就是:创建一个实例对象 用创建它的类名当做数据表名 用创建它的类属性对应数据表的字段 当对这个实例对象操作时能够对应相应的MySQL语句
通过元类实现ORM insert功能
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
# 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k)
# 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)
class User(metaclass=ModelMetaclass):
uid = ("int", "unsigned")
name = ("varchar(30)","not null")
email = ("varchar(30)", "not null")
password = ("varchar(30)", "not null")
# 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储
# 以上User类中有
# __mappings__ = {
# "uid": ('uid', "int unsigned")
# "name": ('username', "varchar(30)")
# "email": ('email', "varchar(30)")
# "password": ('password', "varchar(30)")
# }
# __table__ = "User"
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(k)
args.append(getattr(self, k)
args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print('SQL: %s' % sql)
u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()
抽取到基类中
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判断是否需要保存
for k, v in attrs.items():
# 判断是否是指定的StringField或者IntegerField的实例对象
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
# 删除这些已经在字典中存储的属性
for k in mappings.keys():
attrs.pop(k)
# 将之前的uid/name/email/password以及对应的对象引用、类名字
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)
class Model(object, metaclass=ModelMetaclass):
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(k)
args.append(getattr(self, k)
args_temp = list()
for temp in args:
# 判断入如果是数字类型
if isinstance(temp, int):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print('SQL: %s' % sql)
class User(Model):
uid = ("int", "unsigned")
name = ("varchar(30)","not null")
email = ("varchar(30)", "not null")
password = ("varchar(30)", "not null")
u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()
如果在类中没有发现metaclass
会在父类中寻找metaclass
父类中的metaclass
指定了元类