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)
- 首先执行使用name和age参数来执行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 python中self,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的定义就知道了。