关闭

python学习11-面向对象

标签: python
180人阅读 评论(0) 收藏 举报
分类:

面向对象
对象可以看作数据以及由一系列可以存取,操作这些数据的方法所组成的集合。
多态:多态意味着就算不知道变量所引用的对象类型是什么,还是可以对他进行操作,而它也会根据对象类型的不同而表现出不同的行为。例如“+”运算符可以对数字和字符串2进行不同的操作。唯一能毁掉多态的就是使用函数显示地检查类型,比如type,ininstance以及issubclass函数。如果可能的话应尽力避免使用这些毁掉多态的方式。
如何创建一个类:
class MyNewObjectType(bases):
class_suit #类体
bases可以是一个或多个用于继承的父类。创建一个实例的过程称作实例化,过程如下:
myFirstObject = MyNewObjectType()
方法: 方法定义在类定义中,但只能被实例所引用。
class MyDataWithMethod(object):
def printFoo(self):
print ‘You invoked printFoo()!’
self参数在所有的方法声明中都存在。这个参数代表实例对象本身,当你用实例调用方法时,由解释器自动传递给方法,所以,你不需要自己传递self过来。一般的方法会需要这个实例(self),而静态方法或类方法不会,其中类方法需要类而不是实例。
python创建实例后,在实例化过程中,调用init()方法,当一个类被实例化时,就可以定义额外的行为。
类名通常以大写字母打头,这是标准惯例。
类属性仅与其被定义的类相绑定,并且因为实例对象在日常 OOP 中用得最多,实例数据属性是你将会一直用到的主要数据属性。类数据属性仅当需要有更加“静态”数据类型时才变得有用,它和任何实例都无关。
Python 严格要求,没有实例,方法是不能被调用的。这种限制即 Python所描述的绑定概念(binding)。
决定类的属性
要知道一个类有哪些属性,有两种方法。最简单的是使用 dir()内建函数。另外是通过访问类的字典属性dict,这是所有类都具备的特殊属性之一。
特殊类属性
C.name 类C的名字(字符串)
C.doc 类C的文档字符串
C.bases 类C的所有父类构成的元组
C.dict 类C的属性
C.module 类C定义所在的模块(1.5 版本新增)
C.class 实例C对应的类(仅新式类中)
new() “构造器”方法
init()相比,new()方法更像一个真正的构造器。类型和类在版本 2.2 就统一了,Python 用户可以对内建类型进行派生,因此,需要一种途径来实例化不可变对象,比如,派生字符串,数字,等等。在这种情况下,解释器则调用类的new()方法,一个静态方法,并且传入的参数是在类实例化操作时生成的。new()会调用父类的new()来创建对象(向上代理)。为何我们认为new()比init()更像构造器呢?这是因为new()必须返回一个合法的实例,这样解释器在调用init()时,就可以把这个实例作为 self 传给它。调用父类的new()来创建对象,正像其它语言中使用 new 关键字一样。
实例属性
实例仅拥有数据属性(方法严格来说是类属性)
,后者只是与某个类的实例相关联的数据值,并
且可以通过句点属性标识法来访问。这些值独立于其它实例或类。当一个实例被释放后,它的属性同时也被清除了。
能够在“运行时”创建实例属性,是 Python 类的优秀特性之一,Python 不仅是动态类型,而且在运行时,允许这些对象属性的动态创建。
对内建类型也可以使用dir(),与其他对象一样,可以得到一个包含它属性名字的列表。在内建类型中不存在dict这个属性。
类属性仅是与类相关的数据值,和
实例属性不同,类属性和实例无关。这些值像静态成员那样被引用,即使在多次实例化中调用类,它们的值都保持不变。不管如何,静态成员不会因为实例而改变它们的值,除非实例中显式改变它们的值。类和实例都是名字空间。类是类属性的名字空间,实例则是实例属性的。你可采用类来访问类属性,如果实例没有同名的属性的话,你也可以用实例来访问。
使用实例属性来试着修改类属性是很危险的。原因在于实例拥有它们自已的属性集,在 Python 中没有明确的方法来指示你想要修改同名的类属性,比如,没有 global关键字可以用来在一个函数中设置一个全局变量(来代替同名的局部变量)。修改类属性需要使用类名,而不是实例名。
调用非绑定方法
调用非绑定方法并不经常用到。需要调用一个还没有任何实例的类中的方法的一个重要场景是:你在派生一个子类而且你要覆盖父类的方法,这时你需要调用那个父类中想要覆盖掉的方法。
新式类和旧式类
为了确保类是新式类,应该为赋值语句 __metaclass__ = type 放在你的模块的最开始,或者子类化内建类object,考虑下面的两个类:
class NewStyle(object):
….more_code_here
class OldStyle(object):
….more_code_here
在这两个类中,NewStyle是新式类,OldStyle是旧式类。如果文件以__metaclass__ = type开始,那么这两个类都是新式类。
使用super函数:
当前的类和对象可以作为super函数的参数使用,调用函数返回的任何方法都是调用超类的方法,而不是当前类的方法。下面的例子,比较使用super函数和不使用super函数:
class Bird:
….def __init__(self):
……..self.hungry = True
….def eat(self):
……..if self.hungry:
…………print ‘Aaaaah….’
…………self.hungry = False
……..else:
…………print ‘No, thanks!’
不使用super函数,子类调用未绑定的超类方法。
class SongBird(Bird):
….def __inti__(self):
………Bird.__init__(self)
………self.sound = ‘squawk!’
….def sing(self):
………print self.sound
使用super函数,super函数只用在新式类中
class SongBird(Bird):
….def __init__(self):
……..super(SongBird, self).__init__()
……..self.sound = ‘squawk’
….def sing(self):
……..print self.sound
Property函数
通常我们在访问和赋值属性的时候,都是直接和类的__dict__打交道,或者跟函数描述符等在打交道。但是假如我们要规范这些访问和设值方式的话,一种方法是引入复杂的数据描述符机制,另一种恐怕就是轻量级的数据描述符协议函数Property().它的标准定义是:
property(fget = None, fset = None, fdel = None, doc = None)
前面三个参数都是未绑定的方法,所以它们事实上可以是任意的类成员函数。实例如下:
__metaclass__ = type
class Rectange:
….def __init__(self):
……..self.width = 0
……..self.height = 0
….def setSize(self, size):
……..self.width, self.height = size
….def getSize(self):
……..return self.width, self.height
size = property(getSize, setSize)
///r = Rectange()
///r.size
输出:(10, 5)
///r.size = 150, 100
///r.width
输出:150
静态方法和类成员方法
静态方法和类成员方法分别在创建时装入staticmethod类型和classmethod类型的对象中。静态方法的定义没有self参数,且能够被类本身直接调用。类方法在定义时需要名为cls的类似于self的参数,类成员方法可以直接用类的具体对象调用,但cls参数是自动被绑定到类的,示例:
__metaclass__= type
class MyClass:
….def smeth():
……..print ‘This is a static method’
….smeth = staticmethod(smeth)
….def cmeth():
……..print ‘This is a class method of’, cls
….cmeth = classmethod(cmeth)
装饰器 使用@操作符
__metaclass__ = type
class MyClass:
….@staticmethod
….def smeth():
……..print ‘This is a static method’
….@classmethod
….def cmeth():
……..print ‘This is a class method of’, cls
静态方法和类成员方法在python中向来都不是很重要,主要愿意是大部分情况下可以使用函数或者绑定方法代替。
从标准类型派生
不可变类型的例子:
将一个浮点数进行舍入操作保留两位:
class RoundFloat(flat):
….def __new__(cls, val):
……..return float.__new___(cls, round(val, 2))
我们通过调用父类的构造函数来创建真实对象float.__new__()注意所有的new方法都是类方法,我们要显式地传入类作为第一个参数,这类似于常见的方法如 __init__()中的self。通常情况下,最好是使用super()内建函数去捕获对应的父类以调用它的__new__方法。下面是对上面的修改:
class RoundFloat(float):
….def __new__(cls. val):
….return super(RoundFloat,cls).__new__(cls, round(val, 2))
*多重继承*
python允许子类继承多个基类,但最难的工作是如何正确找到没有当前子类定义的属性。当使用多重继承时有两个不同的方面要注意,首先还是要找到合适的属性,另一个是当你重写方法时,如何调用对应父类以发挥它们的作用。
方法调用顺序:
经典类为深度优先,新式类为广度优先。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:19008次
    • 积分:416
    • 等级:
    • 排名:千里之外
    • 原创:24篇
    • 转载:2篇
    • 译文:1篇
    • 评论:0条
    文章分类