Python之面向对象

类解释了面向对象(OOP,object-oriented programming)的思想。这里就类实例和方法进行探讨。

1、类和实例

存在着两种形式的类定义,区别仅在于是否从父类派生,从而有经典类和新式类,后文中均以新式类为例进行学习,新式类如:

class MyNewObjectType(bases):
    'define MyNewObjectType class'  #类文档字符串
	class_suite

bases可以是一个(单继承)或者多个(多重继承)用于继承的父类,object是所有类的父类,如果没有继承任何父类,object将作为默认的父类,其位于所有类继承结构的最上层,如果没有直接或者间接的子类化一个对象,那就定义了一个经典类。

class MyNewObjectType:
    'define MyNewObjectType class'  #类文档字符串
	class_suite

关于类和实例化的关系,通过一个例子来说明:

class MyData(object):
    pass

创建一个实例的过程称为实例化

myFirstObject = MyNewObjectType()

类名加上函数操作符“()”,以函数调用的形式出现,通常把这个新建的实例赋值给一个变量,但赋值语句不是必须的,如果没有把这个实例保存到一个变量中,它就没用了,会被自动垃圾收集器回收,因为没有任何引用指向这个实例。

mathObj = MyData()
mathObj.x = 4
mathObj.y = 5
print mathObj.x + mathObj.y

这里 mathObj.x 和 mathObj.y 是实例属性,因为它们不是类MyData的属性,而是实例对象(mathObj)的独有属性,这些属性是动态的:不需要在构造器中或者其他任何地方为它们预先声明或者赋值。

2、方法

类的功能有一个通俗的名字叫作方法,在Python中,方法定义在类的定义中,但只能被实例所调用,因此调用一个方法的过程:

a.定义类(类中定义方法) ;b.创建实例;c.用这个实例调用方法

class MydataWithMethod(object):
    'defint MydataWithMethod class'
    def printFoo(self):
        print "you invoked printFoo()"

注意self参数,它在所有的方法声明中都存在,这个参数代表实例对象本身,当你用实例调用方法时,有解释器传递给方法的。一般的方法需要这个实例(self),但是静态方法或者类方法不需要

class AddrBookEntry(object):
    'address book entry class'
    def __init__(self,nm,ph):
        self.name = nm
        self.phone = ph
        print "Created instance for:",self.name
    def updatePhone(self,newph):
        self.phone = newph
        print "Updated phone# for:",self.name

对于__init__()方法,在创建一个新的对象时被调用,即是在实例化对象 AddrBookEntry() 被调用,可以认为实例化是对__init__()的一种隐式调用。

john = AddrBookEntry('John Doe','408-1234')

这就是实例化调用,会自动调用 __init__(),self 把实例对象自动传入 __init__()。注意__init__()不是实例化对象调用的第一个方法,实例化对象时,首先使用('John Doe','4008-1234')这两个参数来执行类的 __new__() 方法,返回 AddrBookEntry 类的一个实例,(通常情况下是使用 super(Persion, cls).__new__(cls, ... ...) 这样的方式);然后利用这个实例来调用类的上一步里面__new__产生的实例也就是 __init__里面的的 self
所以,__init__ 和 __new__ 最主要的区别在于:
1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

3、创建子类

依靠继承或者派生子类实现新类的类型定制,可以保持父类的所有特性,不会更改父类的定义,同时定制子类特有的功能。

class EmpAddrBookEntry(AddrBookEntry):
    "Emplyee 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

当子类被派生出来以后,子类就继承了基类的所有属性。如果需要最好每个子类都定义自己的构造器,不然基类的构造器会被调用。然而如果子类重写基类的构造器,基类的构造器就不会被自动调用了,这样基类的构造器必须显示写出才会被执行。

4、继承覆盖

面向对象就不得不提继承和派生,这里不会对继承和派生进行过多介绍,而就继承中如何覆盖进行介绍

首先写一个类,然后在其子类中对它进行覆盖

 
 
class Parent(object):
    def foo(self):
        print "I am Parent-foo()"
p = Parent()
print p.foo()

现在来创建子类Chlid,派生于父类Parent

class Child(Parent):
    def foo(self):
        print "I am Child-foo()"
c = Child()
print c.foo()

尽管子类Chlid继承了父类Parent类的foo()方法,但是因为子类也定义了自己的foo()方法,所以父类的foo()方法被覆盖了,覆盖的原因之一是,子类可能需要这个方法有不同的或者特定的功能。那子类对象还能调用父类的方法吗?通过

 
 
print Parent.foo(c)
输出结果:
I am Parent-foo

注意已经有了一个Parent类的实例p,但是上面这个例子没有调用它。我们不需要Parent类的实例调用Parent的方法,因为已经有一个Parent类的子类的实例c可用。典型的情况是会在子类的重写方法中显示的调用基类方法

class Child(Parent):
    def foo(self):
        Parent.foo(self)
        print "I am Chlid-foo()"

注意这个(未绑定)方法调用中显示的传递了 self,一个更好的办法是使用 super() 内建函数

class Child(Parent):
    def foo(self):
        super(Child,self).foo()
        print "I am Chlid-foo()"

这样super不仅能找到基类方法,而且还能传递 self,现在调用子类的方法,就可搞定了

c = Child()
print c.foo()
输出结果:
 I am Parent-foo()
I am Chlid-foo()

猜你喜欢

转载自blog.csdn.net/rhx_qiuzhi/article/details/80140745