1、Python中面向对象程序设计特点:封装、继承和多态
关于继承:可以打个形象的比方
矩形、菱形、平行四边形和梯形等都是四边形,以平行四边形为例,如果把平行四边形看成四边形的延伸,那么平行四边形就复用了四边形的属性和行为,同时添加了平行四边形特有的属性和行为,如平行四边形的对边平行且相等。
---->在Python中可以把平行四边形类看作是继承四边形类后产生的类,其中,将类似于平行四边形的的类称为子类,将类似于四边形的类称为父类或超类,
在阐释平行四边形和四边形关系时,可以说平行四边形是特殊的四边形,却不能说四边形是平行四边形。
---->同理Python中可以说子类的实例都是父类的实例,却不能说父类的实例都是子类的实例。
- 继承中方法重写:指的是派生类方法想重写,不想从基类继承时,就需要改写基类的方法。
基类的成员都会被派生类继承,当基类中的某个方法不完全适用于派生类时,就需要在派生类中重写父类的这个方法。
class Fruit: # 父类 def harvest(self): pass class Apple(Fruit): # 派生类 def harvest(self): # 方法重写 pass
- 派生类中定义的__init__方法不会自动调用基类的__init__方法,如想让他调用,需要在派生类中加入super()__init__()
class Fruit: # 父类 def __init__(self,color = 'green'): Fruit.color = color print(Fruit.color) def harvest(self): print('水果原来是:'+ Fruit.color+ '的!') class Apple(Fruit): # 派生类 def __init__(self): # 方法重写 print('i am apple') # super().__init__() apple = Apple() apple.harvest()
改写后:
class Fruit: # 父类 def __init__(self,color = 'green'): Fruit.color = color print(Fruit.color) def harvest(self): print('水果原来是:'+ Fruit.color+ '的!') class Apple(Fruit): # 派生类 def __init__(self): # 方法重写 print('i am apple') super().__init__() apple = Apple() apple.harvest()
2、多态
3、创建类的同时会创建一个内置__init__方法,在内置函数中self参数是必要的,不可省略。
4、类属性和实例属性。通过在类中定义的变量(属性)位置不同,可分为类属性和实例属性。
- 类属性:定义在类中的属性,该属性在类中函数体之外。
- 实例属性:定义在类的方法之中的属性,只作用于当前实例之中。
访问方法:
类属性通过类名或实例名访问,而实例属性只能通过实例名访问。如果通过类名访问则会报错。
特殊点:实例属性可通过实例名称修改,并不影响该类其他实例中相应的实例属性的值。
(1)通过类名调用类属性:也可以通过实例名访问
class Geese: """雁类""" neck = "脖子太长" wing = "振翅频率高" leg = "腿位于身份的中心支点,行走自如" def __init__(self): print("我属于雁类,我有如下特征:") print(Geese.neck) print(Geese.wing) print(Geese.leg) geese = Geese()
输出如下:
我属于雁类,我有如下特征: 脖子太长 振翅频率高 腿位于身份的中心支点,行走自如
(2)只可通过实例名访问实例属性,
class Geese: """雁类""" def __init__(self): self.neck = "脖子太长" self.wing = "振翅频率高" self.leg = "腿位于身份的中心支点,行走自如" print("我属于雁类,我有如下特征:") print(self.neck) print(self.wing) print(self.leg) geese = Geese() geese1 = Geese() geese1.neck = "我的实例属性值改变了" print(geese1.neck)
结果如下:
我属于雁类,我有如下特征: 脖子太长 振翅频率高 腿位于身份的中心支点,行走自如 我属于雁类,我有如下特征: 脖子太长 振翅频率高 腿位于身份的中心支点,行走自如 我的实例属性值改变了
5、访问限制
三种形式: __foo__,__foo,_foo
- __foo__:表示系统定义的方法名称:
- _foo: protected(保护类型成员),只允许类本身和子类访问,不能使用(from module import *)导入
- __foo: private(私有)类型成员。只允许定义该类本身访问,而不能通过类的实例访问,但可以通过类的实例名.类名__xxx方式访问
class Geese: """雁类""" _neck = "脖子太长" def __init__(self): print(Geese._neck) geese = Geese() print (geese._neck) # 通过类的实例访问
class Geese: """雁类""" __neck = "脖子太长" def __init__(self): print(Geese.__neck)geese = Geese()print(geese._Geese__neck)print (geese.__neck) # 通过类的实例访问
可以看出__xxx定义的私有属性只能够通过类本身调用或类实例._类名__xxx的方式调用,直接用类实例调用就会报错。
6、装饰器@property
作用简单理解为,写在函数前,将一个方法转换为属性,实现用于计算的属性,外部可以直接使用函数名来访问方法,不需要写成上述5中形式,且调用方法时不需要加()。另外需要注意通过此种方式创建的私有属性是只读的,外部也不可直接赋值修改,否则会报错。
承接上面的例子,私有属性无法在外部通过类访问时。也可以通过装饰器进行解决。
class Geese: """雁类""" def __init__(self,neck): self.__sh = neck # @property def show(self): return self.__sh geese = Geese('脖子很长') print(geese.show()) print(geese._Geese__sh) print (geese.__sh) # 通过类的实例访问
添加装饰器:
class Geese: """雁类""" def __init__(self,neck): self.__sh = neck @property def show(self): return self.__sh geese = Geese('脖子很长') print(geese.show) print(geese._Geese__sh) print (geese.__sh) # 通过类的实例访问
外部修改私有属性:
class Geese: """雁类""" def __init__(self,neck): self.__sh = neck @property def show(self): return self.__sh geese = Geese('脖子很长') print(geese.show) geese.show = '脖子不长' print(geese.show)