首页 > 代码库 > 重新学习python系列(二)? WTF?
重新学习python系列(二)? WTF?
判断class的类型,可以使用isinstance()
函数。
isinstance()
判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。
>>> a = Animal()
>>> d = Dog()
>>> h = Husky()
>>> isinstance(h, Husky) True>>> isinstance(h, Dog) True
能用type()
判断的基本类型也可以用isinstance()
判断:
并且还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是str或者unicode:
>>> 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.x 9 >>> 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‘,如果不存在,返回默认值404 404
也可以获得对象的方法:
>>> hasattr(obj, ‘power‘) # 有属性‘power‘吗? True >>> getattr(obj, ‘power‘) # 获取属性‘power‘ <bound method MyObject.power of <__main__.MyObject object at 0x108ca35d0>> >>> fn = getattr(obj, ‘power‘) # 获取属性‘power‘并赋值到变量fn >>> fn # fn指向obj.power <bound method MyObject.power of <__main__.MyObject object at 0x108ca35d0>> >>> fn() # 调用fn()与调用obj.power()是一样的 81
绑定:
http://www.cnblogs.com/yhl664123701/p/6051448.html
# -*-coding:utf-8-*- from types import MethodType def set_age(self, arg): self.age = arg class Student(object): pass s = 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 MethodType def set_age(self, arg): self.age = arg class 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)) <type ‘type‘> >>> print(type(h)) <class ‘__main__.Hello‘>
错误处理
当我们认为某些代码可能会出错时,就可以用try
来运行这段代码,
如果执行出错,则后续代码不会继续执行,
而是直接跳转至错误处理代码,即except
语句块,
执行完except
后,如果有finally
语句块,则执行finally
语句块(是否有错误都会执行),至此,执行完毕
try: print ‘try...‘ r = 10 / 0 print ‘result:‘, r except ZeroDivisionError, e: print ‘except:‘, e finally: 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
给捕获了。
常见的错误类型和继承关系:https://docs.python.org/2/library/exceptions.html#exception-hierarchy
记录错误
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
Python内置的logging
模块可以非常容易地记录错误信息:
import logging def foo(s): return 10 / int(s) def bar(s): return foo(s) * 2 def main(): try: bar(‘0‘) except StandardError, e: logging.exception(e) main() print ‘END‘
通过配置,logging
还可以把错误记录到日志文件里,方便事后排查。
抛出错误: raise
class FooError(StandardError): pass def foo(s): n = int(s) if n==0: raise FooError(‘invalid value: %s‘ % s) return 10 / n
重新学习python系列(二)? WTF?