关于类的一些高级操作
class Chain(object):
def __init__(self, path=''):
self._path = path
def __getattr__(self, path):
return Chain('%s/%s' % (self._path, path))
def users(self, name):
return Chain('%s/users/:%s' % (self._path, name))
def __str__(self):
return self._path
__repr__ = __str__
print(Chain().users('lovelyfrog').repos)
/users/:lovelyfrog/repos
使用元类
type()
str是用来创建字符串对象地类,int是用来创建整数对象的类,而type就是创建类对象的类
def fn(self, name='world'):#先定义函数
print('hello, %s' % name)
Hello = type('Hello', (object,), dict(hello=fn)) #创建Hello class
- 要创建一个class对象,type()函数依次传入3个参数:
1.class的名称
2.继承的父类集合,是个tuple
3.class方法名称与函数绑定,dict
通过type()函数创建的类和直接写class是完全一样的,因为python解释器遇到class定义时会自动扫描一下class定义的语法,然后调用type()函数创建class.
type()函数允许我们动态创建类,也就是说,动态语言本身支持运行期间动态创建类
动态地创建类
def choose_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo
else:
class Bar(object):
pass
return Bar
MyClass = choose_class('foo')
print (MyClass)
<class '__main__.choose_class.<locals>.Foo'>
print (MyClass())
<__main__.choose_class.<locals>.Foo object at 0x0000021FF34BADD8>
metclass
除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass(元类)
如果我们想创建出类,就必须根据metaclass创建出类,所以先定义metaclass然后创建类,换句话说可以把类看成metaclass创建出来的实例
- 我们可以在写一个类的时候为其添加metaclass属性
class Foo(object):
__metaclass__ = something...
[...]
如果这么做了,python就会用元类来创建Foo。
class Foo(Bar):
pass
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-28-ee44de34193a> in <module>()
----> 1 class Foo(Bar):
2 pass
NameError: name 'Bar' is not defined
在上面的代码中python做了如下地操作:
Foo 中有metaclass这个属性吗,如果是python会在内存中通过metaclass创建一个Foo的类对象,如果没有找到,它会继续在Bar(父类)中寻找metaclass属性,并尝试做和前面同样的操作。如果最终还是找不到,则用内置的type来创建这个类对象
自定义元类
元类的主要目的就是为了当创建类的时候可以自动地改变类,比如你决定在你的模块中所有的类属性都是大写
#元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
'''返回一个类对象,将属性都转为大写形式'''
#选择所有不以‘__’开头的属性
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
#将它们转为大写形式
upper_attr = dict((name.upper(), value) for name, value in attrs)
#通过type来做类对象的创建
return type(future_class_name, future_class_parents, upper_attr)
class Foo(object, metaclass=upper_attr):
bar = 'bip'
print (hasattr(Foo, 'bar'))
False
f = Foo()
print(f.BAR)
bip
# 用一个真正的class当作元类,metaclass是类的模板,所以必须要从type类派生
class UpperAttrMetaClass(type):
#__new__是在__init__之前被调用的方法
#__new__是用来创建对象并返回之的方法
def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
upper_attr = dict((name.upper(), value) for name, value in attrs)
return type(future_class_name, future_class_parents, upper_attr)
class UpperAttrMetaclass(type):
def __new__(cls, name, bases, dct):
attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
upper_attr = dict((name.upper(), value) for name, value in attrs)
return type.__new__(cls, name, bases, upper_attr)
python中的一切都是对象,他们要么是类的实例,要么是元类的实例,除了type,type实际上是它自己的元类
按照默认习惯,metaclass的类名总是以Metaclass结尾,以清楚地表示这是一个metaclass
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda cls, value: cls.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass=ListMetaclass):
pass
L = MyList()
L.add(1)
L
[1]
而普通的list没有add()方法
L2=list()
L2.add(1)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-73-0a75f2c80b37> in <module>()
1 L2=list()
----> 2 L2.add(1)
AttributeError: 'list' object has no attribute 'add'
尝试编写一个ORM框架
#首先定义Field类,它负责保存数据库表的字段名和字段类型
class Field(object):
def __init__(self,name,column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)
class StringField(Field):
def __init__(self,name):
super(StringField, self).__init__(name, 'varchar(100)')
class IntegerField(Field):
def __init__(self,name):
super(IntegerField, self).__init__(name, 'bigint')
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name=='Model':
return type.__new__(cls, name, bases, attrs)
print('Found model: %s' % name)
mappings = dict()
for k,v in attrs.items():
if isinstance(v, Field):
print('Found mapping: %s==>%s' %(k,v))
mappings[k]=v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings #保存属性和列的映射关系
attrs['__table__'] = name
return type.__new__(cls, name, bases, attrs)
#定义基类Model
class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kw):
super(Model, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r'Model object has no attribute %s' % key)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k,v in self.__mappings__.items():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' %(self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' %sql)
print('ARGS: %s' %str(args))
#先把调用接口写出来
class User(Model):
id_num = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
Found model: User
Found mapping: id_num==><IntegerField:id>
Found mapping: password==><StringField:password>
Found mapping: email==><StringField:email>
Found mapping: name==><StringField:username>
u = User(id_num=12345, name='lovelyfrog', email='lovelyfrog@qq.com', password='zbq19970216')
u.save()
SQL: insert into User (password,id,email,username) values (?,?,?,?)
ARGS: ['zbq19970216', 12345, 'lovelyfrog@qq.com', 'lovelyfrog']
sdd = ['a','b','c']
','.join(sdd)
'a,b,c'