chap 13 oop(13.1-13.7)
1.类方法:(1)定义类(及方法)(2)创建实例(3)调用实例上的方法
2. 创建一个类(新式类):
创建一个实例
>>> john = AddrBookEntry('John Doe', '408-555-1212')
Created instance for: John Doe
>>> jane = AddrBookEntry('Jane Doe', '650-555-1212')
Created instance for: Jane Doe
访问实例属性
>>> john
<__main__.AddrBookEntry instance at 80ee610>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> jane.name
'Jane Doe'
>>> jane.phone
'650-555-1212'
方法调用
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
创建子类
42, 'john@spam.doe')
Created instance for: John Doe
>>> john
<__main__.EmplAddrBookEntry object at 0x62030>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> john.email
'john@spam.doe'
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
>>> john.updateEmail('john@doe.spam')
Updated e-mail address for: John Doe
>>> john.email
'john@doe.spam'
3.面向对象编程:
类:类体由所有声明语句,类成员定义,数据属性和函数组成。类通常在一个模块的顶层进行定义,以便类实例能够在类所定义的源代码文件中的任何地方被创建。
无虚函数或者抽象函数:如果对 OOP 很熟悉,请注意 Python 并不支持纯虚函数(像 C++)或者抽象方法(如在 JAVA 中),这些都强制程序员在子类中定义方法。作为替代方法,你可以简单地在基类方法中引发 NotImplementedError 异常,这样可以获得类似的效果。
属性链:有关属性的一个有趣的地方是,当你正访问一个属性时,它同时也是一个对象,拥有它自己的属性,可以访问,这导致了一个属性链
python的绑定及非绑定:Python 严格要求,没有实例,方法是不能被调用的。
特殊的类属性:
C.__name__ 类C的名字(字符串)
C.__doc__ 类C的文档字符串
C.__bases__ 类C的所有父类构成的元组
C.__dict__ 类C的属性
C.__module__ 类C定义所在的模块(1.5 版本新增)
C.__class__ 实例C对应的类(仅新式类中)
4.__init__()类似于OOP中的构造函数,但是在python中它还不是真正的构造函数。当一个类被实例化的时候,__init__()就会被自动调用,而且该对象会被作为参数传入__init__()。如果__init__()没有实现,则返回它的对象,如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递进去,像标准方法调用一样。
5.__new__()更像一个真正的构造器,用来实例化不可变对象,比如,派生字符
串,数字,等。这种情况下,解释器则调用类的__new__()方法,一个静态方法,并且传入的参数是在类实例化操作时生成的。__new__()会调用父类的__new__()来创建对象(向上代理)。它总是在__init__()之前被调用的。__new__()接受即将被创建实例的类作为第一个参数cls,而它接收的其余参数正是我们创建实例时传给类的参数。所以__new__()可以表示成__new__(cls,*args,**kwargs)
eg:
class A(object):
def __new__(cls,*args,**kwargs):
print cls
print 'args is',args
ptint 'kwargs is',kwargs
>>> a = A()
cls is <class '__main__.A'>
args is ()
kwargs is {}
>>> print a #经过调用了__new__之后发现a仍然为None
None
>>> a = A(1,2)
cls is <class '__main__.A'>
args is (1, 2) #传给A()的参数1,2都被传给了__new__()当中
kwargs is {}
>>> print a #经过调用了__new__之后发现a仍然为None,可见还得需要__init__()的进一步加工
None
6.__del__():特殊的析构器,python具备(引用计数)垃圾对象回收机制,当某个实例对象的所有引用都被清除掉后这个函数才会被执行。在定义__del__()的时候需要注意:
a.不要忘记首先调用父类的__del__()
b.调用了del x不代表调用了x.__del__()
c.如果你有一个循环引用或者其他原因,让一个实例引用逗留,那么该对象的__del__()可能永远不会执行
d.__del__()未捕获的异常会被忽略掉(因为一些在__del__()用到的变量或许已经被删除了)。不要在__del__()中干与实例没任何关系的事情
e.如果你定义了__del__,并且实例是某个循环的一部分,垃圾回收器将不会终止这个循环,你需要自已显式调用 del。
7.实例属性
实例具有数据属性,而对于类中定义的方法是属于类属性。python中的实例属性不同于java和c++,java中的所有属性在使用前都必须明确定义或声明,python不仅是动态类型,而且在运行时,允许这些对象属性的动态创建。这种特性需要谨慎使用。
在构造器中首先设置实例属性,上文我们知道__init__()是实例创建以后第一个被调用的方法。在__init__()中设置实例属性最好。在__init__()函数中可以为实例属性设置默认值,这样就可以不用向它传递参数。否则就要显示的向__init__()传递参数。需要注意的是,默认参数应该是不变的对象,向列表,字典这样可变对象可以作为静态数据,然后在每个方法调用中来维护它们的内容。
__init__()函数应该返回None,而不应返回任何对象,否则就会报错TypeError
通过dir()和__dict__可以看实例的属性,通过__class__可以看实例所属的类
8.类属性和实例属性
类属性的名字空间是类,实例属性的名字空间是实例。在访问类属性的时候,你可以用类来访问类属性,如果实例没有同名的实例属性的话,也可以使用实例来访问。但是修改类属性需要使用类名,而不是实例名。
我们只有当使用类来访问类属性时,才能更新类属性的值。如果使用实例来访问类属性,并且同时要改变类属性的值的行为是不会发生的,而且只会创建一个和类属性相同名字的实例属性。python通过这样的机制遮蔽了类属性不被实例轻易修改。如果我们删除了这个新创建的实例属性,再次使用实例去访问类属性,就会发现类属性又通过实例访问暴露出来了。需要特别注意的,但是以上的事实在类属性是可变对象比如字典的时候,就不一样了。看例子:
类属性是不变对象:
>>> class A(object):
... version = 1.2
...
>>>
>>> a = A()
>>> A.version #通过类访问类属性
1.2
>>> a.version #通过实例访问类属性
1.2
>>> a.version+=1 #通过实例访问类属性并且修改类属性
>>> A.version #通过类访问类属性,依然不变
1.2
>>> a.version #此时已不是通过实例访问类属性,而是直接访问新创建的实例属性
2.2
>>> del a.version #删除实例属性
>>> a.version #类属性重新暴露出来
1.2
类属性是可变对象:
>>> class B(object):
... x = {123:'abc'} #类属性是可变对象
...
>>> b = B()
>>> B.x #通过类访问属性
{123: 'abc'}
>>> b.x #通过实例访问类属性
{123: 'abc'}
>>> b.x[456]='def' #通过实例访问类属性并且修改类属性
>>> B.x
{456: 'def', 123: 'abc'} #通过类访问类属性,竟然发现改变了
>>> b.x
{456: 'def', 123: 'abc'} #通过类访问类属性,改变
>>> del b.x #没有遮蔽所以不能删除掉
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'B' object attribute 'x' is read-only
1.类方法:(1)定义类(及方法)(2)创建实例(3)调用实例上的方法
2. 创建一个类(新式类):
class AddrBookEntry(object): # class definition
'address book entry class'
def __init__(self, nm, ph): # define constructor
self.name = nm # set name
self.phone = ph # set phone#
print 'Created instance for:', self.name
def updatePhone(self, newph): # define method
self.phone = newph
print 'Updated phone# for:', self.name
创建一个实例
>>> john = AddrBookEntry('John Doe', '408-555-1212')
Created instance for: John Doe
>>> jane = AddrBookEntry('Jane Doe', '650-555-1212')
Created instance for: Jane Doe
访问实例属性
>>> john
<__main__.AddrBookEntry instance at 80ee610>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> jane.name
'Jane Doe'
>>> jane.phone
'650-555-1212'
方法调用
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
创建子类
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:', self.name
使用子类
>>> john = EmplAddrBookEntry('John Doe', '408-555-1212',42, 'john@spam.doe')
Created instance for: John Doe
>>> john
<__main__.EmplAddrBookEntry object at 0x62030>
>>> john.name
'John Doe'
>>> john.phone
'408-555-1212'
>>> john.email
'john@spam.doe'
>>> john.updatePhone('415-555-1212')
Updated phone# for: John Doe
>>> john.phone
'415-555-1212'
>>> john.updateEmail('john@doe.spam')
Updated e-mail address for: John Doe
>>> john.email
'john@doe.spam'
3.面向对象编程:
类:类体由所有声明语句,类成员定义,数据属性和函数组成。类通常在一个模块的顶层进行定义,以便类实例能够在类所定义的源代码文件中的任何地方被创建。
无虚函数或者抽象函数:如果对 OOP 很熟悉,请注意 Python 并不支持纯虚函数(像 C++)或者抽象方法(如在 JAVA 中),这些都强制程序员在子类中定义方法。作为替代方法,你可以简单地在基类方法中引发 NotImplementedError 异常,这样可以获得类似的效果。
属性链:有关属性的一个有趣的地方是,当你正访问一个属性时,它同时也是一个对象,拥有它自己的属性,可以访问,这导致了一个属性链
python的绑定及非绑定:Python 严格要求,没有实例,方法是不能被调用的。
特殊的类属性:
C.__name__ 类C的名字(字符串)
C.__doc__ 类C的文档字符串
C.__bases__ 类C的所有父类构成的元组
C.__dict__ 类C的属性
C.__module__ 类C定义所在的模块(1.5 版本新增)
C.__class__ 实例C对应的类(仅新式类中)
4.__init__()类似于OOP中的构造函数,但是在python中它还不是真正的构造函数。当一个类被实例化的时候,__init__()就会被自动调用,而且该对象会被作为参数传入__init__()。如果__init__()没有实现,则返回它的对象,如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递进去,像标准方法调用一样。
5.__new__()更像一个真正的构造器,用来实例化不可变对象,比如,派生字符
串,数字,等。这种情况下,解释器则调用类的__new__()方法,一个静态方法,并且传入的参数是在类实例化操作时生成的。__new__()会调用父类的__new__()来创建对象(向上代理)。它总是在__init__()之前被调用的。__new__()接受即将被创建实例的类作为第一个参数cls,而它接收的其余参数正是我们创建实例时传给类的参数。所以__new__()可以表示成__new__(cls,*args,**kwargs)
eg:
class A(object):
def __new__(cls,*args,**kwargs):
print cls
print 'args is',args
ptint 'kwargs is',kwargs
>>> a = A()
cls is <class '__main__.A'>
args is ()
kwargs is {}
>>> print a #经过调用了__new__之后发现a仍然为None
None
>>> a = A(1,2)
cls is <class '__main__.A'>
args is (1, 2) #传给A()的参数1,2都被传给了__new__()当中
kwargs is {}
>>> print a #经过调用了__new__之后发现a仍然为None,可见还得需要__init__()的进一步加工
None
6.__del__():特殊的析构器,python具备(引用计数)垃圾对象回收机制,当某个实例对象的所有引用都被清除掉后这个函数才会被执行。在定义__del__()的时候需要注意:
a.不要忘记首先调用父类的__del__()
b.调用了del x不代表调用了x.__del__()
c.如果你有一个循环引用或者其他原因,让一个实例引用逗留,那么该对象的__del__()可能永远不会执行
d.__del__()未捕获的异常会被忽略掉(因为一些在__del__()用到的变量或许已经被删除了)。不要在__del__()中干与实例没任何关系的事情
e.如果你定义了__del__,并且实例是某个循环的一部分,垃圾回收器将不会终止这个循环,你需要自已显式调用 del。
7.实例属性
实例具有数据属性,而对于类中定义的方法是属于类属性。python中的实例属性不同于java和c++,java中的所有属性在使用前都必须明确定义或声明,python不仅是动态类型,而且在运行时,允许这些对象属性的动态创建。这种特性需要谨慎使用。
在构造器中首先设置实例属性,上文我们知道__init__()是实例创建以后第一个被调用的方法。在__init__()中设置实例属性最好。在__init__()函数中可以为实例属性设置默认值,这样就可以不用向它传递参数。否则就要显示的向__init__()传递参数。需要注意的是,默认参数应该是不变的对象,向列表,字典这样可变对象可以作为静态数据,然后在每个方法调用中来维护它们的内容。
__init__()函数应该返回None,而不应返回任何对象,否则就会报错TypeError
通过dir()和__dict__可以看实例的属性,通过__class__可以看实例所属的类
8.类属性和实例属性
类属性的名字空间是类,实例属性的名字空间是实例。在访问类属性的时候,你可以用类来访问类属性,如果实例没有同名的实例属性的话,也可以使用实例来访问。但是修改类属性需要使用类名,而不是实例名。
我们只有当使用类来访问类属性时,才能更新类属性的值。如果使用实例来访问类属性,并且同时要改变类属性的值的行为是不会发生的,而且只会创建一个和类属性相同名字的实例属性。python通过这样的机制遮蔽了类属性不被实例轻易修改。如果我们删除了这个新创建的实例属性,再次使用实例去访问类属性,就会发现类属性又通过实例访问暴露出来了。需要特别注意的,但是以上的事实在类属性是可变对象比如字典的时候,就不一样了。看例子:
类属性是不变对象:
>>> class A(object):
... version = 1.2
...
>>>
>>> a = A()
>>> A.version #通过类访问类属性
1.2
>>> a.version #通过实例访问类属性
1.2
>>> a.version+=1 #通过实例访问类属性并且修改类属性
>>> A.version #通过类访问类属性,依然不变
1.2
>>> a.version #此时已不是通过实例访问类属性,而是直接访问新创建的实例属性
2.2
>>> del a.version #删除实例属性
>>> a.version #类属性重新暴露出来
1.2
类属性是可变对象:
>>> class B(object):
... x = {123:'abc'} #类属性是可变对象
...
>>> b = B()
>>> B.x #通过类访问属性
{123: 'abc'}
>>> b.x #通过实例访问类属性
{123: 'abc'}
>>> b.x[456]='def' #通过实例访问类属性并且修改类属性
>>> B.x
{456: 'def', 123: 'abc'} #通过类访问类属性,竟然发现改变了
>>> b.x
{456: 'def', 123: 'abc'} #通过类访问类属性,改变
>>> del b.x #没有遮蔽所以不能删除掉
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'B' object attribute 'x' is read-only