类与实例相互关联着:类是对象的定义,而实例是"真正的实物",它存放了类中所定义的对象的具体信息.
class MyNewObjectType(bases): "define MyNewObjectType class" class_suite而object是"所有类之母".我们可以给类添加属性
>>> class MyData(object): pass >>> mathObj = MyData() >>> mathObj.x = 4 >>> mathObj.y = 5 >>> mathObj.x * mathObj.y 20 >>> dir(mathObj) ['__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__', 'x', 'y']
我们可以给类添加功能(方法),调用方法的途径如下:(1)定义类(和方法),(2)创建一个实例;(3)用这个实例调用方法:
>>> class MyDataWithMethod(object): def printFoo(self): print("you invoked printFoo()!") >>> myObj = MyDataWithMethod() >>> myObj.printFoo() you invoked printFoo()!这里self类似于C++的this,而python中的方法调用类中的其他变量或函数时,需要通过self来引用:
>>> class TestClass(object): def printFunc(self): print(self.show()) def errorPrintFunc(self): print(show()) def show(self): return "hello" >>> test = TestClass() >>> test.printFunc() hello >>> test.errorPrintFunc() Traceback (most recent call last): File "<pyshell#30>", line 1, in <module> test.errorPrintFunc() File "<pyshell#27>", line 5, in errorPrintFunc print(show()) NameError: name 'show' is not defined
>>> class AddrBookEntry(object): """address book entry class""" def __init__(self, nm, ph): self.name = nm self.phone = ph print("created instance for: %s" % self.name) def updatePhone(self, newph): self.phone = newph; print("updated phone# for:%s" % self.name)__init__():在实例化时被调用,关联C++的构造函数即可.
>>> john = AddrBookEntry("john doe", "123-456-789") created instance for: john doe >>> jane = AddrBookEntry("hane doe", "987-654-321") created instance for: hane doe >>> john <__main__.AddrBookEntry object at 0x000000000333D668> >>> john.name 'john doe' >>> jane.phone '987-654-321' >>> jane.updatePhone("111-222-333") updated phone# for:hane doe >>> jane.phone '111-222-333'
>>> class EmplAddrBookEntry(AddrBookEntry): """Employee Address Book Entry class""" def __init__(self, nm, ph, id, em): AddrBookEntry.__init__(self, nm, ph) self.empid = id self.email = em def updateEmail(self, newem): self.email = newem print("updated e-mail address for: %s" % self.name) >>> john = EmplAddrBookEntry("john doe", "123-456-789", 42, "[email protected]") created instance for: john doe >>> john.email '[email protected]' >>> john.updateEmail("[email protected]") updated e-mail address for: john doe >>> john.email '[email protected]'
属性就是属于另一个对象的数据或者函数元素,可以通过句点属性标识法来访问.
类属性仅与被定义的类相绑定,它与具体的实例无关.
类的数据属性表示这些数据与类对象绑定,不依赖于任何类实例:
>>> class C(object): foo = 100 >>> print(C.foo) 100 >>> C.bar = 200 >>> print(C.bar) 200
方法是一个作为类定义一部分定义的函数,必须通过类的实例来调用:即方法必须绑定到一个实例才能直接调用.
>>> class MyClass(object): def myMethod(self): pass >>> mc = MyClass() >>> mc.myMethod() >>> MyClass.myMethod() Traceback (most recent call last): File "<pyshell#75>", line 1, in <module> MyClass.myMethod() TypeError: myMethod() missing 1 required positional argument: 'self'而我们通常可以通过dir()和属性__dict__来查看类的属性:
>>> dir(MyClass) ['__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__', 'myMethod'] >>> MyClass.__dict__ mappingproxy({'__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__doc__': None, '__module__': '__main__', 'myMethod': <function MyClass.myMethod at 0x000000000333EA60>})
C.__name__ |
类C的名字 |
C.__doc__ |
类C的文档字符串 |
C.__bases__ |
类C的所有父类构成的元组 |
C.__dict__ |
类C的属性 |
C.__module |
类C定义所在的模块 |
C.__class__ |
实例C所对应的类 |
>>> class MyClass(object): pass >>> mc = MyClass() >>> type(mc) <class '__main__.MyClass'> >>> type(MyClass) <class 'type'>
当类被调用,实例化的第一步是创建实例对象.一旦对象创建了,python检查是否实现了__init__()方法.__init__()类似构造函数,任何需要的特定操作都要在__init__()中完成,例如定义类的数据变量.如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递进去.
对内建类型进行派生的情况下,解释器需要调用类的__new__()方法,一个静态方法,并且传入的参数是在类实例中操作时生成的.
__del__()要直到该实例对象所有的引用都被清除后才会执行,通常在python中不实现,因为实例很少被显式释放.
class P(object): def __del__(self): pass class C(P): def __init__(self): super(C, self).__init__() print("initialized") def __del__(self): super(C, self).__del__() print("deleted") if __name__ == "__main__": c1 = C() c2 = c1 c3 = c1 print([id(x) for x in (c1, c2, c3)]) del c1 del c2 del c3输出如下:
>>> initialized [67873480, 67873480, 67873480] deleted
设置实例的属性可以在实例创建后任意时间进行,也可以在能够访问实例的代码中进行.构造器__init__()是设置这些属性的关键点之一.
我们可以在__init__函数中设置实例属性,并且可以提供默认的参数,且__init__应当返回None:
>>> class C(object): pass >>> c = C() >>> c.foo = "roger" >>> c.bar = "shrubber" >>> dir(c) ['__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'] >>> c.__dict__ {'bar': 'shrubber', 'foo': 'roger'} >>> c.__class__ <class '__main__.C'>
类属性与实例无关,类属性可以理解为静态成员.类是类属性的名字空间,而实例是实例属性的名字空间.
实例无法更改类的不可变属性:
>>> class MyClass(object): version = 1.2 print("version id:%d" %id(version)) version id:48859632 >>> c = MyClass() >>> c.version 1.2 >>> id(c.version) 48859632 >>> MyClass.version += 0.1 >>> id(MyClass.version) 48858456 >>> c.version 1.3 >>> id(c.version) 48858456 >>> c.version += 0.4 >>> id(c.version) 48859632 >>> c.version 1.7000000000000002 >>> id(MyClass.version) 48858456
这里之所以是新建一个实例属性version,是因为version不可改变.如果类属性为可改变的,比如列表,则情况完全不同
>>> class MyClass(object): version = [1, 2] print("version id:%d" %id(version)) version id:57720328 >>> c = MyClass() >>> c.version.append(3) >>> id(c.version) 57720328 >>> id(MyClass.version) 57720328
首先,方法仅仅是类内部定义的函数(这意味着方法是类属性而不是实例属性).
其次,方法只有在其所属的类拥有实例时,才能被调用.当存在一个实例时,方法才被认为是绑定到那个实例了.没有实例时方法就是未绑定的.
最后,任何一个方法定义中的第一个参数都是变量self,它表示调用此方法的实例对象.
一般情况下,方法肯定用到了self,来操作类的变量(self.name,...).如果方法中没有使用实例self,则通常定义方法为常规函数:
>>> class MyClass(object): def __init__(self): self.name = "lcj" def show(self): print(self.name) def noBingShow(): print("hello world") >>> c = MyClass() >>> c.show() lcj >>> c.noBingShow() Traceback (most recent call last): File "<pyshell#167>", line 1, in <module> c.noBingShow() TypeError: noBingShow() takes 0 positional arguments but 1 was given >>> MyClass.noBingShow() hello world而非绑定方法通常用于:在子类构造器中调用父类的构造器并且明确的传递(父类)构造器所需要的self参数.这时候需要通过父类名来调用它:
>>> class EmplAddrBookEntry(AddrBookEntry): """Employee Address Book Entry class""" def __init__(self, nm, ph, id, em): AddrBookEntry.__init__(self, nm, ph) self.empid = id self.email = em
可以使用装饰器来编写静态方法和类方法:
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
http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python
继承描述了基类的属性如何"遗传"给派生类.一个子类可以继承它的基类的任何属性,不管是数据属性还是方法.
>>> class P(object): """P class""" def __init__(self): print("created an instance of %s" % self.__class__.__name__) >>> class C(P): pass >>> p = P() created an instance of P >>> p.__class__ <class '__main__.P'> >>> P.__bases__ (<class 'object'>,) >>> P.__doc__ 'P class' >>> c = C() created an instance of C >>> c.__class__ <class '__main__.C'> >>> C.__bases__ (<class '__main__.P'>,) >>> C.__doc__
对任何子类,__bases__是一个包含其父类的集合的元组:
>>> class A(object): pass >>> class B(A): pass >>> class C(B): pass >>> A.__bases__ (<class 'object'>,) >>> B.__bases__ (<class '__main__.A'>,) >>> C.__bases__ (<class '__main__.B'>,)
>>> 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__
当从一个带构造器__init__()的类派生,如果你不去覆盖__init__(),它将会被继承并自动调用.但如果你在子类中覆盖了__init__(),子类被实例化时,基类的__init__()就不会被自动调用:
>>> class P(object): def __init__(self): print("calling P's constructor") >>> class C(P): def __init__(self): print("calling C's constructor") >>> c = C() calling C's constructor而我们可以通过super来达到目的: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 constructor calling C's constructor
>>> class RoundFloat(float): def __new__(cls, val): return super(RoundFloat, cls).__new__(cls, round(val, 2)) >>> RoundFloat(1.5955) 1.6 >>> RoundFloat(1.5945) 1.59 >>> RoundFloat(-1.9955) -2.0
>>> class SortedKeyDict(dict): def keys(self): return sorted(super(SortedKeyDict, self).keys()) >>> d = SortedKeyDict((("x" , 1), ("z" , 2), ("y", 3))) >>> [key for key in d] ['y', 'x', 'z'] >>> d.keys() ['x', 'y', 'z']
一个实例如下:
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): pass class 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()
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 "<pyshell#288>", line 1, in <module> 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']dir():
显示模块的所有属性信息.
super():
子类用于查找父类的属性.
vars():
与dir()相似,只是给定的对象参数都必须有一个__dict__属性.