类定义
class ClassName(object):
"""docstring for ClassName"""
def __init__(self, arg):
super(ClassName, self).__init__()
self.arg = arg
def method(self, args):
pass
Python中的类也是一个对象,类与其实例拥有不同级别的作用域.
当试图通过实例访问一个属性时,Python会先在实例的作用域中搜索该属性,若实例作用域中不存在该属性则继续搜索类作用域.
若在类作用域中找到了该属性,Python将把这个属性复制一个副本(浅拷贝),加入到对象的作用域中。
通常我们在类中直接定义方法, 在初始化方法中__init__
中定义并初始化属性.
Python中没有this参数,self是表示对象自身引用的关键字(即其它语言中的this).
定义方法时需要显式声明self参数作为第一个参数,使用Object.method()
调用类方法时self不必显式传递,python将自动传递.
在类方法中访问对象属性或调用方法时需要显式使用self,否则将被解释为访问同名的方法局部变量(Python在访问对象前是无需声明的)。
类的私有属性或方法以两个下划线__
开头,只允许类内部访问不允许类外访问. 公有属性或方法禁止以两个下划线开头。
采用两个下划线开头和结尾的方法一般为特殊方法,除非重写这些方法否则不要占用这些标识符。
__init__
方法是类的构造函数,在生成对象时调用;__del__
为析构函数,释放对象时使用完成清理工作__repr__
类似java中的toString方法,用于显示对象时将对象转换为可显示的形式(一般为字符串)。
继承
class SubClass(BaseClass1, BaseClass2):
pass
需要注意圆括号中基类的顺序。再调用方法时首先调用本类方法,然后搜索基类方法。调用方法或访问属性时本类采用self,基类则使用括号中基类的名字指定。
Python中还提供了super()
来解决多重继承问题,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。super机制里可以保证公共父类仅被执行一次,执行的顺序由__mro__
决定。
class SubClass(Baseclass):
def __init__(*args):
super(SubClass, self).__init__(args)
若是基类中有相同的方法名,而在子类使用时未指定,Python从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。
class circle:
radium = 0
def area(self):
return math.pi * self.radium ** 2
class cylinder(circle):
height = 0
def volume(self):
c = circle()
c.radium=1
return c.area() * self.height
重载运算符
“鸭子类型”是动态面向对象语言设计中的一个概念,即如果一个东西行走像鸭子,游泳像鸭子,进食像鸭子那它就是鸭子
即一个对象具有某一类的特征,即可作为该类实例来对待,不必强制实现接口.
Python允许重写某些特殊方法来定义使用某些操作符
可以通过重写某些方法模拟字典和列表的行为:
__setitem__
按照key为元素赋值__getitem__
按照key取元素__delitem__
按照key删除元素__call__
允许将对象作为函数进行调用__len__
获得长度,调用len(obj)时即调用obj.__len__()
__iter__()
返回iterable, for-in循环会调用这个对象的next()方法进行迭代__call__
重载函数调用,调用obj(args)
即调用obj.__call__(args)
模拟dict:
class MyDict:
def __init__(self):
self.data = dict()
def __getitem__(self, key):
return self.data.get(key)
def __setitem__(self, key, val):
self.data[key] = val
def __delitem__(self, key):
self.data.pop(key)
def __iter__(self):
for item in self.data:
yield item
def __len__(self):
return len(self.data)
if __name__ == '__main__':
d = MyDict()
# set item
d['first'] = 1
d['second'] = 2
# get item
print(d['first'], d['second'])
# len
print(len(d))
# iter
for item in d:
print(item)
# del item
del(d['first'])
print(d['first'])
模拟list:
class MyList:
def __init__(self):
self.data = list()
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, val):
self.data[key] = val
def __delitem__(self, key):
self.data.pop(key)
def __iter__(self):
for item in self.data:
yield item
def __len__(self):
return len(self.data)
if __name__ == '__main__':
l = MyList()
l.data.extend([0,0])
# set item
l[0] = 1
l[1] = 2
# get item
print(l[0], l[1])
# len
print(len(l))
# iter
for item in l:
print(item)
# del item
del(l[0])
print(l[0])
作为函数:
class MyFunc():
def __call__(self):
print('I am callable')
if __name__ == '__main__':
f = MyFunc()
f()
重载算术与关系运算:
__cmp__
比较运算__add__
加运算__sub__
减运算__mul__
乘运算__div__
除运算;__mod__
求余运算__pow__
乘方
metaclass
Python中类的类型为"type",type()函数可以建立一个"type"类型对象即一个类。type函数有三个参数,class的名称,基类元组和成员名-成员对象字典。
def func(args):
print("fuck");
ClassObj = type('ClassName',(object,),dict(method1=func))
print(ClassObj)
print(dir(ClassObj))
Python的class语法实际上是调用type()函数进行动态编译。元类metaclass是进行类动态创建与修改的另一种方式。
def func(args):
pass
class aMetaclass(type):
def __new__(classObj, className, bases, attrs):
attrs.update(dict(aMethod=func));
return type.__new__(classObj,className,bases,attrs)
class aClass(object, metaclass=aMetaclass):
pass
obj = aClass();
print(dir(obj))
通常类的创建由type()
或type.__new__()
完成,在指定了一个类的metaclass参数之后,该类对象的创建将交由metaclass来完成。metaclass.__new__
将会拦截类的创建,进行处理后调用type.__new__
进行创建。
相对于使用type()动态创建类,metaclass可以使用继承等OOP机制且作为类其功能比函数更为强大。metaclass拥有其它成员和类动态添加成员机制,而函数只能以硬编码编制创建逻辑。
示例,使用metaclass编写ORM:
ORM(Object Relational Mapping,对象-关系映射)把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
tinyORM中首先定义了表中域的类型,然后定义Model类执行创建数据表的逻辑,类Users定义数据表'users'。
Users类创建时首先封装创建类的参数,然后封装Model的创建参数执行基类Model的创建。Model创建过程被ModelMetaclass.__new__
拦截,传入的name参数为'users'(__new__
只处理Model派生类的建立,对Model类的建立不进行处理)。__new__
将一个成员映射为一列,并存入__mapping__
中和保存数据表名字的__table__
一起添加到Users的属性中。__new__
返回修改后的类, 执行Model.__init__
进行初始化。
#tinyORM.py
#Define field types
class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __repr__(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')
#define Model
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 # save mapping of attribute-column
attrs['__table__'] = name # name the table after the class name
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):
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))
#send sql and args to database
#The end of ORM, the following code should be created by ORM's users.
#define table 'user' and its structure
class Users(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
password = StringField('password')
def test()
u = Users(id=2333, name='username', password='password')
u.save()
test()