您的位置:首页 > 编程语言 > Python开发

Python_09-面向对象编程

2015-06-21 00:56 537 查看
目录:

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__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

参考:

/article/2204275.html

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的定义就知道了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: