python核心编程笔记(12)- OOP

chap 13 oop(13.1-13.7)

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
    
    


    
    
    
    


        
 
       
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值