首页 > 代码库 > 重新学习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继承

为了更好地看出继承关系,我们把RunnableFlyable改为  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,因为ValueErrorStandardError的子类,如果有,也被第一个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?