Python_09-面向对象编程

目录:

1       面向对象编程
1.1    简单例子
1.2    调用
1.3    python命名规范(约定)
1.4    类的设计
1.4.1 Exception 异常捕获结构
1.4.2 自定义异常
1.4.3 __init__.
1.4.4 __new__.
1.4.5 __new__ 的作用
1.4.6 用__new__来实现单例
1.4.7 静态方法
1.4.8 类方法
1.5    面向对象编程
1.5.1 Python支持多继承
1.5.2 多态 (override overload)
1.6    super关键字
1.6.1 普通继承
1.6.2 super继承

 

 

 

 

1       面向对象编程

1.1   简单例子

#!/usr/bin/python

#-*- encoding:utf-8 -*-

class test: #定义一个test

    desc = "这是一个测试类。" #在类中定义一个属性desc

    def __init__(self,name1): #对象构造函数,初始化类

        self.name1 = name1

    def show(self,name2): #在类中定义一个方法show()

        print("hello world")

        print('name1:',self.name1)

        print('name2:',name2)

 

1.2   调用

obj = test('这是传递给name1的值') #生成test类的实例对象

print(obj.desc) #调用类中的desc属性

obj.show('这是传递给name2的值') #调用类中的show()方法  

 

1.3   python命名规范(约定)

类里面 “单下划线” 开始的成员变量叫做保护变量,  意思是只有类对象和子类对象自己能访问到这些变量;

而 "双下划线" 开始的是私有成员, 意思是只有类对象自己能访问, 连子类对象也不能访问到这个数据。

类的首字母大写, 没有特别原因不要在前面加 “T或者 “C什么的

函数和变量尽量全小写, 单词间用下划线连接。

 

 

1.4   类的设计

 class Foo:

      def __init__(self, a, b):

        self.a = a

        self.b = b

 

      def show_a(self):

        print self.a

 

      def show_b(self):

        print self.b

 

    __init__ 函数:每次生成类的时候都会执行的, self 指向类对象自身。

记住, 类函数(或者叫做方法) 它的第一个参数 “self不要忘记写了

 

其中的“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。

       foo_obj = Foo("I'm A", "I'm B")

     foo_obj.show_a()

     foo_obj.b = "Hello world!"

     foo_obj.show_b()

 

 

1.4.1   Exception  异常捕获结构

try:

……

except Exceptionname

…….

except:

       …….

else:

       …….

finally:

       …….

 

1.4.2   自定义异常

       class MyError(Exception):

              pass

 

       raise 关键字 可以抛出自定义的异常

              例: raise MyError

注意:一定注意先后顺序, 要先定义异常类后才可以使用, 而不能上来就用。

1.4.3   __init__

 

程序cPerson.py

class Person(object):

    """Silly Person"""

 

    def __init__(self, name, age):

        self.name = name

        self.age = age

 

 

    def __str__(self):

        return '<Person: %s(%s)>' % (self.name, self.age)

 

 

if __name__ == '__main__':

    piglei = Person('piglei', 24)

print piglei

运行:

>>> import cPerson

>>> str(a)

'<Person: yong(22)>'

>>> a=cPerson.Person('LiLee',22)

>>> str(a)

'<Person: LiLee(22)>'

 

1.4.4   __new__

每一个 new-style class 都有一个名为{{_new_}}的静态方法. 当你调用 C(args,kwds)创建一个C实例时,python内部调用的是 C._new_(C,*args,*kwds).

{_new_}}方法的返回值 x 就是该类的实例. 在确认 x 是C的实例以后, python调用C.{{_init_(x,args,*kwds)来初始化这个实例. 也就是说,对新类C来讲,语句 x=C(23)等同于

x = C._new_(C, 23)

if isinstance(x, C): C._init_(x, 23)

_new方法拥有函数工厂的绝大部分弹性. 根据实际需求,我们可以让new_返回一个已有的实例或者创建一个新的实例.

下面举一个通过重载_new_方法实现独身对象的设计模式的例子:

class Singleton(object):

 _singletons = {}
 def _new_(cls, *args, **kwds):
 if not cls._singletons.has_key(cls): #
若还没有任何实例
      cls.singletonscls = object.new_(cls) #
生成一个实例
 return cls._singletonscls #
返回这个实例
Singleton
的所有子类(当然是没有重载_new方法的子类)都只可能有一个实例. 如果该类的子类定义了一个init方法,那么它必须保证它的init_方法能够安全的对同一实例进行多次调用.

 

__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。 

# -*- coding: utf-8 -*-

class Person(object):

    """Silly Person"""

 

 

    def __new__(cls, name, age):

        print '__new__ called.'

        return super(Person, cls).__new__(cls, name, age)

 

 

    def __init__(self, name, age):

        print '__init__ called.'

        self.name = name

        self.age = age

 

 

    def __str__(self):

        return '<Person: %s(%s)>' % (self.name, self.age)

 

 

if __name__ == '__main__':

    piglei = Person('piglei', 24)

    print piglei

执行结果:

执行方法1

$ python new_and_init.py

__new__ called.

__init__ called.

<Person: piglei(24)>

执行方法2:

>>> 

>>> import cPerson

>>> a=Person('dd',39)

__new__ called.

__init__ called.

通过运行这段代码,我们可以看到,__new__方法的调用是发生在__init__之前的。其实当你实例化一个类的时候,具体的执行逻辑是这样的:

  • p = Person(name, age)
  • 首先执行使用nameage参数来执行Person类的__new__方法,这个__new__方法会返回Person类的一个实例(通常情况下是使用 super(Persion, cls).__new__(cls, ... ...) 这样的方式),
  • 然后利用这个实例来调用类的__init__方法,上一步里面__new__产生的实例也就是 __init__里面的的 self

所以,__init__ __new__ 最主要的区别在于: 


  • __init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性,做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
  • __new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

 

参考:

http://my.oschina.net/leejun2005/blog/207371

 

1.4.5   __new__ 的作用

依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple)提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass

首先我们来看一下第一个功能,具体我们可以用int来作为一个例子:

假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。

 

class PositiveInteger(int):

    def __init__(self, value):

        super(PositiveInteger, self).__init__(self, abs(value))

i = PositiveInteger(-3)

print i

但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。

这是修改后的代码:

class PositiveInteger(int):

    def __new__(cls, value):

        return super(PositiveInteger, cls).__new__(cls, abs(value))

i = PositiveInteger(-3)

print i

通过重载__new__方法,我们实现了需要的功能。

另外一个作用,关于自定义metaclass。其实我最早接触__new__的时候,就是因为需要自定义 metaclass,但鉴于篇幅原因,我们下次再来讲python中的metaclass和__new__的关系。

1.4.6   用__new__来实现单例

事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton)

因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们可以很简单的实现单例模式。

class Singleton(object):

    def __new__(cls):

        # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象

        if not hasattr(cls, 'instance'):

            cls.instance = super(Singleton, cls).__new__(cls)

        return cls.instance

obj1 = Singleton()

obj2 = Singleton()

 

obj1.attr1 = 'value1'

print obj1.attr1, obj2.attr1

print obj1 is obj2

输出结果:

value1 value1

True

可以看到obj1和obj2是同一个实例。

class Singleton(object):

    __instance = None

    def __init__(self, *args, **kwargs):

        pass

    def __new__(cls, *args, **kwargs):

        if not cls.__instance:

            # if not hasattr(cls, 'instance'):

            cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)

            cls.__instance.aa = args[0]

            print type(cls), type(cls.__instance), type(cls.__instance.aa)

        return cls.__instance

 

obj1 = Singleton(1, 2, 3, b=2)

obj2 = Singleton(1, 2, 3, b=2)

 

obj1.attr1 = 'value1'

obj2.attr2 = 'value2'

print obj1.attr1, obj1.attr2

print obj1 is obj2

print obj1.aa, obj2.attr1

 

 

结果:

<type 'type'> <class '__main__.Singleton'> <type 'int'>

value1 value2

True

1 value1

 

1.4.7   静态方法

 @staticmethod #静态方法修饰符,表示下面的方法是一个静态方法

 def astatic( ): print 'a static method'
 anInstance = AClass( )
 AClass.astatic( ) # prints: a static method
 anInstance.astatic( ) # prints: a static method

1.4.8   类方法

@classmethod #类方法修饰符

 def aclassmet(cls): print 'a class method for', cls._name_
 class ADeriv(ABase): pass

 bInstance = ABase( )
 dInstance = ADeriv( )
 ABase.aclassmet( ) # prints: a class method for ABase
 bInstance.aclassmet( ) # prints: a class method for ABase
 ADeriv.aclassmet( ) # prints: a class method for ADeriv
 dInstance.aclassmet( ) # prints: a class method for ADeriv

1.5   面向对象编程

前面提到的操作函数和语句块是传统的面向过程编程,而编写大型程序,通常采用面向对象编程。类和对象是面向对象编程的两个主要方面,类创建一个新类型,而对象是类的实例。Python没有什么值类型与引用类型之分,它把所有事物统统看作是类。

 

面向对象实质上是一种思想,并不是一门技术。面向对象讲求一切皆对象.

面向对象的三大特性

继承

封装

多态

为什么要面向对象?

灵活性, 重用性。

 

 

继承关系可以被传递,如果c1是c2的子类,c2是c3的子类,那么c1也是c3的子类。

如果a继承b那么a具有b的一切属性和方法。

1.5.1   Python支持多继承

class A:

    def __init__(self):

        pass

class B:

    def __init__(self):

        pass

class C(A,B):

    def __init__(self):

        pass

    sex=''

    def Say(self):

        print self.name+ self.sex+self.age

 

1.5.2   多态  (override  overload)

Python 中的多态并没有完全实现,Python中只是利用多元化来实现部分多态的特性

class Person:   

    def __init__(self,name):

        self.Name=name

    Name='name'

    Sex='man'

    Age='age'

    def Say(self,message):

        print self.Name+message

class Role(Person):

    def __init__(self,name,roleName):

        Person.__init__(self,name)

        self.RoleName=roleName

    RoleName='roleName'#  light or dark

    def Say(self,message):

        print self.RoleName+self.Name+message

 

 

1.6   super关键字

super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

总之前人留下的经验就是:保持一致性。要不全部用类名调用父类,要不就全部用 super,不要一半一半。

 

1.6.1   普通继承

代码:

[python]view plaincopy在CODE上查看代码片派生到我的代码片

class FooParent(object): 

    def __init__(self): 

        self.parent = 'I\'m the parent.' 

        print 'Parent' 

     

    def bar(self,message): 

        print message, 'from Parent' 

         

class FooChild(FooParent): 

    def __init__(self): 

        FooParent.__init__(self) 

        print 'Child' 

         

    def bar(self,message): 

        FooParent.bar(self,message) 

        print 'Child bar function.' 

        print self.parent 

         

if __name__=='__main__': 

    fooChild = FooChild() 

    fooChild.bar('HelloWorld') 

 

 

1.6.2   super继承

代码

[python]view plaincopy在CODE上查看代码片派生到我的代码片

class FooParent(object): 

    def __init__(self): 

        self.parent = 'I\'m the parent.' 

        print 'Parent' 

     

    def bar(self,message): 

        print message,'from Parent' 

 

class FooChild(FooParent): 

    def __init__(self): 

        super(FooChild,self).__init__() 

        print 'Child' 

         

    def bar(self,message): 

        super(FooChild, self).bar(message) 

        print 'Child bar fuction' 

        print self.parent 

 

if __name__ == '__main__': 

    fooChild = FooChild() 

    fooChild.bar('HelloWorld') 

 

程序运行结果相同,为:

Parent

Child

HelloWorld from Parent

Child bar fuction

I'm the parent.

 

从运行结果上看,普通继承和super继承是一样的。但是其实它们的内部运行机制不一样,这一点在多重继承时体现得很明显。在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照mro进行的(E.__mro__)。

 

注意:super继承只能用于新式类,用于经典类时就会报错。

新式类:必须有继承的类,如果没什么想继承的,那就继承object

经典类:没有父类,如果此时调用super就会出现错误:

super() argument 1 must be type, not classobj

 

 

1.7   python的cls,self,classmethod,staticmethod

python类里会出现这三个单词,self和cls都可以用别的单词代替,类的方法有三种,

1.通过def定义的 普通的一般的,需要至少传递一个参数,一般用self,这样的方法必须通过一个类的实例去访问,类似于c++中通过对象去访问;
2.在def前面加上@classmethod,这种类方法的一个特点就是可以通过类名去调用,但是也必须传递一个参数,一般用cls表示class,表示可以通过类直接调用;
3.在def前面加上@staticmethod,这种类方法是静态的类方法,类似于c++的静态函数,他的一个特点是参数可以为空,同样支持类名和对象两种调用方式;

 

class A:

    member = "this is a test."

    def __init__(self):

        pass

 

    @classmethod

    def Print1(cls):

        print "print 1: ", cls.member

       

    def Print2(self):

        print "print 2: ", self.member

          

       

    @classmethod   

    def Print3(paraTest):

        print "print 3: ", paraTest.member

    @staticmethod

    def print4():

        print "hello"

   

 

a = A()

A.Print1() 

a.Print1()

#A.Print2()

a.Print2()

A.Print3()

a.Print3()

A.print4()

1.8   pythonself,cls

普通的方法,第一个参数需要是self,它表示一个具体的实例本身。

如果用了staticmethod,那么就可以无视这个self,而将这个方法当成一个普通的函数使用。

而对于classmethod,它的第一个参数不是self,是cls,它表示这个类本身。

>>> class A(object):

    def foo1(self):

        print "Hello",self

    @staticmethod

    def foo2():

        print "hello"

    @classmethod

    def foo3(cls):

        print "hello",cls

 

       

>>> a = A()

>>> a.foo1()          #最常见的调用方式,但与下面的方式相同

Hello <__main__.A object at 0x9f6abec>

>>> A.foo1(a)         #这里传入实例a,相当于普通方法的self

Hello <__main__.A object at 0x9f6abec>

>>> A.foo2()          #这里,由于静态方法没有参数,故可以不传东西

hello

>>> A.foo3()          #这里,由于是类方法,因此,它的第一个参数为类本身。

hello <class '__main__.A'>

>>> A                 #可以看到,直接输入A,与上面那种调用返回同样的信息。

<class '__main__.A'>

 

 

1.8.1   其他例子

cls是class的缩写。

class A:

    member = "this is a test."

    def __init__(self):

        pass

 

    @classmethod

    def Print1(cls):

        #

        print "print 1: ", cls.member

        

    def Print2(self):

        print "print 2: ", self.member

           

        

    @classmethod   

    def Print3(paraTest):

        print "print 3: ", paraTest.member

 

a = A()

A.Print1()   #相当于Print1(A)

a.Print2()   #相当于Print2(a)请注意@classmethod

A.Print3()  

 

 

可以看出来,python在通过“.”调用成员函数的时候,会将“.”前面的东西当作函数的第一个参数调用。

而且pyhon并不关心我们把类的成员函数的第一个参数的名称是什么,我们可以用任意的名称,可以看Print3的定义就知道了。

posted @ 2015-06-21 00:56  jiu~  阅读(652)  评论(0编辑  收藏  举报