# 面向对象
## 多重继承、定制类、元类
### 动态创建类
type(classname) #类的类型就是type
因此可以看出 **类是由type函数动态创建成的**
type(classobject) # 类实例的类型是 classname 类名称
type()函数既可以返回一个对象的类型,又**可以创建出新的类型**
>>> def fn(self, name='world'): # 先定义函数
... print('Hello, %s.' % name)
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<type 'type'>
>>> print(type(h))
<class '__main__.Hello'>
要创建一个class对象,type()函数依次传入3个参数:
1. class的名称;
2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
> **note:** 通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。
### 控制类的创建行为 metaclass (元类) 我不要用type来创建类 我要用type的子类xxxxMetaclass
> metaclass允许你创建类或者修改类。你可以把类看成是metaclass创建出来的"实例"
> 先定义metaclass,就可以创建类,最后创建实例
# 为list添加add方法
class ListMetaclass(type):
def __new__(cls,name,bases,attrs):
# name 类名称
# bases 继承父类列表
# attrs 属性/方法
attrs['add'] = lambda self,value:self.append(value) # 对类属性/方法做出一些调整
return type.__new__(cls,name,bases,attrs)
class MyList(list): #
__metaclass__ = ListMetaclass #我不要用type来创建类 我要用type的子类
def __insert(self): # attrs 中键名是 '_MyList__insert'
pass
if __name__ == '__main__':
L = MyList()
L.add(1)
L.add(2)
print L # [1,2]
> **使用场景举例**
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
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)
mappings = dict()
for k,v in attrs.iteritems():
if isinstance(v,Field):
print 'Found mapping: %s==>%s' % (k,v)
mappings[k] = v
for k in mappings.iterkeys():
attrs.pop(k)
attrs['__table__'] = name # 假设表名和类名一致
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
return type.__new__(cls,name,bases,attrs)
class Model(dict): # 继承自 字典
__metaclass__ = ModelMetaclass
def __init__(self, **kw):
super(Model, self).__init__(**kw) #传递过来的参数都成了字典 键值
def __getattr__(self, key): # 字典本不能 dict.key 这里实现
print 'yyyyyyyyyy'
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
print 'xxxxxxxx'
self[key] = value
def save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.iteritems():
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 = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
if __name__ == '__main__':
# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
print u # {'email': 'test@orm.org', 'password': 'my-pwd', 'id': 12345, 'name': 'Michael'}
print u.name # yyyyyyyyyy \n Michael
# 保存到数据库:
#u.save()
### 定制类 参见魔术方法
> \_\_getattr\_\_ 可以类的所有属性和方法调用全部动态化处理
### python支持多重继承
### 类方法转换成属性访问 @property
class Student(object):
@property
def score(self):
return self._score
@score.setter # 不定义setter 就是只读属性
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
### 限制类能添加的属性 \_\_slots\_\_
class Student(object):
\_\_slots\_\_ = ('name', 'age') # 试图绑定此未定义的属性 抛出 AttributeError异常
\_\_slots\_\_定义的属性仅对当前类起作用
在子类中也定义\_\_slots\_\_,这样,子类允许定义的属性就是自身的\_\_slots\_\_加上父类的\_\_slots\_\_
### 为类动态添加方法
>>> from types import MethodType
>>> def set_score(self, score):
... self.score = score
>>> Student.set_score = MethodType(set_score, None, Student)
### 为对象动态添加方法
>>> s = Student()
>>> s.set_score = MethodType(set_score, s, Student)
## 继承 多态
### 判断 对象类型
type() # 类的类型就是type,实例的类型就是类名称 (创建类就是使用type()函数)
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
isinstance() #适用于对象类型、继承关系
### 获取对象属性和方法
dir()
getattr() 可以获取对象方法并变量调用
setattr()
hasattr()
### 继承和多态
**开闭原则**
. 对扩展开放 :允许新增x子类
. 对修改封闭 : 不需要修改依赖x类型的函数