1. 类的一些基本概念
1. __init__
可理解为构造函数。它在类实例化时候调用:
In [10]: class Book(object): ....: """Book information""" ....: def __init__(self, title): ....: self.title = title ....: print '__init__ called' ....: In [11]: book = Book('Python')__init__ called
2. 类的数据属性
类的数据属性与实例无关,与类相关。
In [12]: class C(object): ....: foo = 100 ....: In [13]: C.fooOut[13]: 100In [14]: C.foo += 1In [15]: C.fooOut[15]: 101In [16]: C.bar = 200In [17]: C.bar += 1In [18]: C.barOut[18]: 201但存在特殊的类属性:
C.__name__: 类C的名字
C.__doc__: 类C的文档字符串
C.__bases__: 类C的所有父类构成的元组
C.__dict__: 类C的属性
C.__module__: 类C定义所在的模块
C.__class__: 实例C对应的类
实例如下:
In [31]: class C(object): ....: pass ....: In [32]: class SubC(C): ....: """Sub class""" ....: pass ....: In [33]: SubC.__name__Out[33]: 'SubC'In [34]: SubC.__doc__Out[34]: 'Sub class'In [35]: SubC.__bases__Out[35]: (__main__.C,)In [36]: SubC.__dict__Out[36]:In [37]: SubC.__module__Out[37]: '__main__'In [38]: SubC.__class__Out[38]: typeIn [39]: subc = SubC()In [40]: subc.__class__Out[40]: __main__.SubC
3. 实例属性
通常是在__init__中定义实例属性。
一般也可以在“运行时”创建实例属性,但是不推荐。而且在设计中,不推荐实例属性为列表或字典(可被修改的变量),因为这样很可能到最后你根本就不确定实例属性的值是多少。
一般可以把字典/列表等设计成类属性,供所有的实例使用:
In [42]: class C(object): ....: arr = [] ....: def __init__(self, num): ....: self.num = num ....: In [44]: c1 = C(1)In [45]: c2 = C(2)In [46]: c1.numOut[46]: 1In [47]: c2.numOut[47]: 2In [48]: c1.arr.append(1)In [49]: c2.arr.append(2)In [50]: c1.arrOut[50]: [1, 2]In [51]: c2.arrOut[51]: [1, 2]而我们可以通过dir来查看所有实例属性:
In [52]: dir(c1)Out[52]: ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'arr', 'num']In [53]: c1.__dict__Out[53]: {'num': 1}
4. 静态方法和类方法
可以使用装饰器来编写静态方法和类方法:
class TestStaticMethod(object): @staticmethod def foo(): print("calling static method foo()!")class TestClassMethod(object): @classmethod def foo(cls): print("calling class method foo()") print("foo() is part of class:%s" % cls.__name__) >>> tsm = TestStaticMethod()>>> tsm.foo()calling static method foo()>>> TestStaticMethod.foo()calling static method foo()>>> tcm = TestClassMethod()>>> tcm.foo()calling class method foo()foo() is part of class:TestClassMethod>>> TestClassMethod.foo()calling class method foo()foo() is part of class:TestClassMethod而静态方法和类方法的区别在stackoverflow上已说明:
2. 继承
1. __bases__类属性
对任何子类,__bases__是一个包含其父类的集合的元组:
>>> class A(object): pass>>> class B(A): pass>>> class C(B): pass>>> A.__bases__(,)>>> B.__bases__( ,)>>> C.__bases__( ,)
2. 通过继承覆盖方法
>>> class P(object): def foo(self): print("Hi, I am P-foo()") >>> class C(P): def foo(self): print("Hi, I am C-foo()") >>> c = C()>>> c.foo()Hi, I am C-foo()这时,如果我想调用父类的foo()方法,应该将实例c传入类P中:
>>> P.foo(c)Hi, I am P-foo()而更一般的情况是:我们通过调用super内建方法:
>>> class C(P): def foo(self): super(C, self).foo() print("Hi, I am C-foo()") >>> c = C()>>> c.foo()Hi, I am P-foo()Hi, I am C-foo()核心笔记:重写__init__不会自动调用基类的__init__
所以我们需要super:好处是我们不需要明确的给出任何基类名字
>>> class P(object): def __init__(self): print("calling P's constructor") >>> class C(P): def __init__(self): super(C, self).__init__() print("calling C's constructor") >>> c = C()calling P's constructorcalling C's constructor
3. 多重继承
class P1(object): def foo(self): print("called P1-foo()")class P2(object): def foo(self): print("called P2-foo()") def bar(self): print("called P2-bar()")class C1(P1, P2): passclass C2(P1, P2): def bar(self): print("called C2-bar()")class GC(C1, C2): pass这里的多重继承,采取的查询方法为广度优先搜索:即对于GC来说,现搜索C1,C2.而旧类为深度搜索:现搜索C1,P1,然后搜索C2,P2:
>>> gc = GC()>>> gc.foo()called P1-foo()>>> gc.bar()called C2-bar()
3. 类,实例和其他对象的内建函数
issubclass():
判断一个类是另一个类的子类或子孙类:
issubclass(sub, sup)isinstance():
判定一个对象是否是另一个给定类的实例:
isinstance(obj1, obj2)obj1是类obj2的一个实例,或者是obj2的子类的一个实例时,返回True.
hasattr(),getattr(),setattr(),delattr():
*attr()系列函数有两个参数,第一个参数是传递进来的方法,第二个参数为字符串属性名.
hasattr()函数是布尔型,决定一个对象是否有一个特定的属性,一般用于访问某属性前先作一个检查.getattr()和setattr()函数相应的取得和赋值给对象的属性,getattr()读取不存在的属性时,引发AttributeError异常,除非给出那个可选的默认参数.setattr()将要么加入一个新的属性,要么取代一个已存在的属性.而delattr()函数会从一个对象中删除属性.
>>> class myClass(object): def __init__(self): self.foo = 100 >>> myInst = myClass()>>> hasattr(myInst, "foo")True>>> getattr(myInst, "foo")100>>> hasattr(myInst, "bar")False>>> getattr(myInst, "bar")Traceback (most recent call last): File "dir():", line 1, in getattr(myInst, "bar")AttributeError: 'myClass' object has no attribute 'bar'>>> setattr(myInst, "bar", "my attr")>>> dir(myInst)['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo']>>> getattr(myInst, "bar")'my attr'>>> delattr(myInst, "foo")>>> dir(myInst)['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar']
显示模块的所有属性信息.
super():
子类用于查找父类的属性.
vars():
与dir()相似,只是给定的对象参数都必须有一个__dict__属性.