判断class的类型,可以使用isinstance()
函数。
isinstance()
判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。
>>> a = Animal() >>> d = Dog() >>> h = Husky() >>> isinstance(h, Husky)True >>> isinstance(h, Dog)True
能用type()
判断的基本类型也可以用isinstance()
判断:
>>> isinstance('a', (str, unicode))True>>> isinstance(u'a', (str, unicode))True
dir()
获得一个对象的所有属性和方法
返回一个包含字符串的list
如果也想用len(myObj)
的话,就自己写一个__len__()
方法:
>>> class MyObject(object):... def __len__(self):... return 100...>>> obj = MyObject()>>> len(obj)100
获取对象信息:
配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态:
>>> class MyObject(object):... def __init__(self):... self.x = 9... def power(self):... return self.x * self.x...>>> obj = MyObject()
>>> hasattr(obj, 'x') # 有属性'x'吗?True>>> obj.x9>>> hasattr(obj, 'y') # 有属性'y'吗?False>>> setattr(obj, 'y', 19) # 设置一个属性'y'>>> hasattr(obj, 'y') # 有属性'y'吗?True>>> getattr(obj, 'y') # 获取属性'y'19>>> obj.y # 获取属性'y'19
可以传入一个default参数,如果属性不存在,就返回默认值:
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404404
也可以获得对象的方法:
>>> hasattr(obj, 'power') # 有属性'power'吗?True>>> getattr(obj, 'power') # 获取属性'power'>>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn>>> fn # fn指向obj.power >>>> fn() # 调用fn()与调用obj.power()是一样的81
绑定:
# -*-coding:utf-8-*-from types import MethodTypedef set_age(self, arg): self.age = argclass Student(object): passs = Student()#给student 创建一个方法 但这里不是在class中创建而是创建了一个链接把外部的set_age 方法用链接知道Student内s.set_age = MethodType(set_age,s,Student)s.set_age(213) #调用实例方法print s.age
# -*-coding:utf-8-*-from types import MethodTypedef set_age(self, arg): self.age = argclass Student(object): pass#直接用类来创建一个方法 不过此时还是用链接的方式在类外的内存中创建Student.set_age = MethodType(set_age,Student)#此时在创建实例的时候外部方法 set_age 也会复制 这些实例和Student类都指向同一个set_age方法new1 = Student()new1.set_age(132)print new1.age
__slots__
变量,来限制该class能添加的属性:
__slots__
要注意,__slots__
定义的属性仅对当前类起作用,对继承的子类是不起作用的: 除非在子类中也定义__slots__
,这样,子类允许定义的属性就是自身的__slots__
加上父类的__slots__
。
>>> class Student(object):... __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称...
Mixin继承
为了更好地看出继承关系,我们把Runnable
和Flyable
改为 RunnableMixin
和 FlyableMixin
定制类
__str__()
,而是__repr__()
,两者的区别是__str__()
返回用户看到的字符串
class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name=%s)' % self.name __repr__ = __str__
__iter__
如果一个类想被用于for ... in
循环,类似list或tuple那样,
就必须实现一个__iter__()
方法,该方法返回一个迭代对象,
然后,Python的for循环就会不断调用该迭代对象的next()
方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def next(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一个值
__getitem__
Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素:
class Fib(object): def __getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a + b return a
__getattr__
正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99 >> s.score 99
__call__
还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。通过callable()
函数,我们就可以判断一个对象是否是“可调用”对象。
class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) >>> s = Student('Michael')>>> s()My name is Michael.
动态创建类
>>> 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))>>> print(type(h))
错误处理
当我们认为某些代码可能会出错时,就可以用try
来运行这段代码, 如果执行出错,则后续代码不会继续执行,
而是直接跳转至错误处理代码,即except
语句块,
执行完except
后,如果有finally
语句块,则执行finally
语句块(是否有错误都会执行),至此,执行完毕
try: print 'try...' r = 10 / 0 print 'result:', rexcept ZeroDivisionError, e: print 'except:', efinally: print 'finally...'print 'END'
Python的错误其实也是class,所有的错误类型都继承自BaseException
,所以在使用except
时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”
try: foo()except StandardError, e: print 'StandardError'except ValueError, e: print 'ValueError'
第二个except
永远也捕获不到ValueError
,因为ValueError
是StandardError
的子类,如果有,也被第一个except
给捕获了。
常见的错误类型和继承关系:
记录错误
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
Python内置的logging
模块可以非常容易地记录错误信息:
import loggingdef foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): try: bar('0') except StandardError, e: logging.exception(e)main()print 'END'
通过配置,logging
还可以把错误记录到日志文件里,方便事后排查。
抛出错误: raise
class FooError(StandardError): passdef foo(s): n = int(s) if n==0: raise FooError('invalid value: %s' % s) return 10 / n