参考:黑马程序员教程 - Python基础 面向对象html
OOP三大特性,且三个特性是有顺序的:python
指的就是把现实世界的事务,封装、抽象成编程里的对象,包括各类属性和方法。
这个通常都很简单,不须要多讲。程序员
惟一要注意的就是:推荐从小往大开始封装、开发类。好比
手枪,子弹
这两个类,咱们须要先定义和开发子弹的全部属性和方法,而后再去开发上一层的手枪。这样的话会很方便。反过来开发手枪的适合,发现写到一半写不下去要到子弹那里写,就很乱了。
子类能够继承父类和父父类的全部属性、方法。编程
继承格式:函数
class Parent: def func1(self): pass class Son(Parent): def func2(self): func1()
方法改写:
子类在不满意时,也能够进行本身的改写父类的属性、方法。
其中有两种状况:ui
Extend 扩展父类函数:设计
super().func()
引用父类方法。其中super
是一个python builtin 特殊类,而super()
即生成一个super的实例。在子类中生成super实例,会获得父类的引用。ParentName.func(self)
引用父类方法。可是不推荐,由于父类名称改变的话全部的子类都要改。私有不继承:
子类可以继承的只是父类的公开内容,可是不包括父类的私有内容。
若是要访问的话也能够,可是须要间接的调用父类再用方法调用私有内容。code
Python中,子类是能够同时有多个父类的:也就是可以同时继承多个父类的全部属性、方法。htm
继承格式:对象
class Father: def func1(self): pass class Mother: def func2(self): pass class Son(Father, Mother): def func3(self): func1() func2()
注意:
若是多个父类间存在有同名的方法,那么会继承第一个父类的方法。
MRO, Method Resolution Order
查看继承顺序:
经过类自带的.__mro__
属性(MRO, Method Resolution Order
),能够查看这个类的继承顺序。
子类能够直接写FatherName.func()
来调用父级函数。
可是当子类用super().func()
时候,python就会根据MRO
顺序,由近到远逐次寻找,找到最近的上级则返回。
用上例,若是是多继承的话,那么寻找顺序是:SON -> Father -> Mother -> object
。
dir(className)
能够查看内置全部属性方法。
Python3开始使用新式的类定义,即默认让全部定义的类都自动继承一个叫object
的内置基础类。object
基础类定义了不少方便的属性。包括18项之多。
而旧式的Python2.x时代,不继承object基础类,本身定义的类就只有__doc__
和__module__
两样内置属性而已。2.x时代,若是须要手动继承,如:
class MyClass(object): pass
多态是指,不一样的子类对象调用相同的父类方法,会产生多态多样结果的编程特性。
多态的前提是可以继承父类的方法,且可以重写改写父类的方法。
多态的特色:
def Father(): def work(self): do_job() def do_job(self): print('Farming on the field...') def Son(Father): def do_job(self): print('Programming at an office...') # ---- Now let's work ---- Jason = Son() Jason.work()
以上代码中,一样是work()
函数,且要do_work()
。可是,不一样的人调用的是不一样的do_work
。
Father调用本身的do_work,儿子由于本身重写了do_work,因此调用本身的方法。
这就是多态——所继承的方法,不须要再特殊指定谁用什么方法,而对象会自动调用适合本身的方法。
Python中,实例是一个对象,类也是一个对象,一切皆对象。但这也是Python OOP中引发不少麻烦的缘由。
实例对象很是好理解,也好用,直接用,就不说了。可是类对象
就不那么好理解了。
简单说,类对象
也是一个标准的对象,有本身的属性和方法,只不过可以像模版
同样生成多个实例对象而已。
类对象有这两大研究点:
类属性:就是能让全部实例访问和操做的公用厕所
类方法:比较难理解,必须用到名为@classmethod
的装饰器,函数的第一个参数必须是关键字cls
,如同self
。
@classmethod
装饰器:用来告诉解释器这是一个类方法
,而不是实例方法。cls
参数:这是Python OOP中困扰不少人的特色。可是其实不难理解,总结以下:
class MyClass: # 在这个位置定义的,叫类属性。==等同于其它语言的“静态属性” # 这是每一个实例共有的公用属性,至关于宿舍的公用洗澡间 count = 0 def __init__(self): # 用self.定义的,叫实例属性,是每一个实例只本身全部的属性,selfish self.name = "Jason"
访问类属性的方法有两种:
ClassName.propertyName
:推荐,直接用类名访问类属性。Instance.propertyName
:不推荐用实例名访问类属性,由于若是须要写入操做,那么这种方法只会给本身添加一个实例属性,而不会影响类属性。方法一:
>>> MyClass.newAttribute = 'I am a class attribute' >>> print( MyClass.newAttribute ) 'I am a class attribute'
方法二:装饰器
# Customized decorator for classproperty class classproperty(object): def __init__(self, getter): self.getter= getter def __get__(self, instance, owner): return self.getter(owner) class MyClass: @classproperty def newAttribute(cls): return 'I am a class attribute.' >>> print( MyClass.newAttribute ) 'I am a class attribute'
之因此把方法封装为一个类属性,是由于咱们有时候须要根据其它类属性来定制这个类属性。
而通常状况下,咱们无法在类属性定义的时候得到当前的类或类中其它的属性。
类方法如同类属性,是属于全类的方法,可是(推荐)只用来访问类属性。
类方法:比较难理解,必须用到名为@classmethod
的装饰器,函数的第一个参数必须是关键字cls
,如同self
。
@classmethod
装饰器:用来告诉解释器这是一个类方法
,而不是实例方法。cls
参数:如同self
,用来指代当前的类。注意:@classmethod
和cls
都是关键字,不能改。
代码:
class MyClass: # 定义一个“类属性” count = 0 # 这里开始定义“类方法” @classmethod def func(cls): print(cls.count)
类中的staticmethod
装饰器一样是python基础类object的一个用于包装、装饰的方法。一旦在类方法前放上装饰器@staticmethod
,方法就会转换为一个静态方法
。
静态方法就是一个很是独立的方法:既不访问实例的信息,也不访问类的信息。
代码:
class MyClass: # 定义一个“类属性” count = 0 # 这里开始定义“类方法” @staticmethod def func(): pass
类中的property
装饰器,也是python基础类object的一个用于包装、装饰的方法。一旦类方法前放上装饰器@property
,方法就会转换为一个类属性
。不少时候把方法假装成属性,是很是方便的。
class MyClass: # 这里开始定义由方法转换为“类属性” @property def name(self): return "Jason" c = MyClass() print( c.name )
在继承object基础类的状况下,python给出了三种类属性装饰,对应三种操做:
@property
@name.setter
@name.deleter
也就是说,当你读取类属性my_name
的时候,会调用被@property
修饰的方法;当你修改my_name
当时候,会调用被@my_name.setter
修饰的方法;当你删除这个属性时,会调用被@my_name.deleter
修饰的方法。
注意:
@property
, @*.setter
, @*.deleter
,这是固定的名字,不能改。代码:
class MyClass: # 这里开始定义由方法转换为“类属性” @property def name(self): return "Jason" @name.setter def name(self, value): self.name = value @name.deleter def name(self): del "Jason" c = MyClass() print( c.name ) # READ c.name = "Brown" # SET del c.name # DELETE
不少OOP语言,针对property属性
,通常操做是:一个私有属性,配合两个公有方法。
如:
class MyClass: def __init__(self): self.__name = "Jason" def get_name(self): return self.__name def set_name(self, value): self.__name = value c = MyClass() # 开始调用 c.set_name("Brownee") print( c.get_name() )
在Python下,能够利用装饰器改成如下代码,极大方便调用的过程:
class MyClass: def __init__(self): self.__name = "Jason" @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value c = MyClass() # 开始调用 c.name = "Brownee" print( c.name )