Python面向对象编程笔记
上篇
class Animal():
def __init__(self,name,speed):
self.name = name # 动物名字
self.speed = speed # 动物行走或飞行速度
- self的作用是指明这两个数据是实例上的,而非类上的。
- 注意到__init__也有参数self,说明这个也是实例上的方法(而非类的)
class Animal():
def __init__(self,name,speed):
self.name = name # 动物名字
self.speed = speed # 动物行走或飞行速度
def __str__(self):
return '''Animal({0.name},{0.speed}) is printed
name={0.name}
speed={0.speed}'''.format(self)
- 其中0.name等,是类专有的打印格式
- 返回
Animal(加菲猫,8) is printed
name=加菲猫
speed=8
类可以直接拥有属性,例如:
class Animal():
cprop = "我是类上的属性cprop"
该属性可以被直接引用且继承,比如
In [1]: Animal.cprop
Out[1]: '我是类上的属性cprop'
In [1]: cat = Animal('加菲猫',8)
In [2]: cat.cprop
Out[2]: '我是类上的属性cprop'
也可以直接给类或者实例添加一个之前不存在的属性(赋值会自动创建)
cat.color = 'grap'#定义的Animal类只有name和speed两个属性
In [24]: hasattr(cat,'color') # cat 已经有`color`属性
Out[24]: True
可以在类内设置私有属性,仅类内方法可以使用该属性。
class Manager():
def __init__(self,animal):
self.animal = animal
def recordTime(self):
self.__t = time.time()
print('feeding time for %s(行走速度为:%s) is %.0f'%(self.animal.name,self.animal.speed,self.__t))
def getFeedingTime(self):
return '%0.f'%(self.__t,)
此处self__t表示类的私有属性,只能被该类之内的方法引用(产生继承也无法引用),t前两个下横杠
多态
import time
from animal import (Animal,Cat,Bird)
class Manager():
def __init__(self,animal):
self.animal = animal
def recordTime(self):
self.__t = time.time()
if isinstance(self.animal, Cat):
print('feeding time for %s is %.0f'%(self.animal.name,self.__t))
self.animal.getRunningSpeed()
if isinstance(self.animal,Bird):
print('feeding time for %s is %.0f'%(self.animal.name,self.__t))
self.animal.getFlyingSpeed()
def getFeedingTime(self):
return '%0.f'%(self.__t,)
当Manager分别继承Cat和Bird时,若继承的对象不同,则其中继承的某些函数方法也会不同,比如recordTime的功能是记录时间。对于Cat而言,方法是统计running的时间,而对于Bird而言,是统计Flying的时间,所以分别继承Cat和Bird时,recordTime时,对应不同对象,执行的小函数是不同的,如上代码所示,则需要先对继承的实例进行判断。
当使用多态时,则省去了写许多if的麻烦:首先在基类Animal中创建一个基方法(只执行pass),然后由Cat和Bird继承后重写此方法。
# animal2.py 模块
class Animal():
cprop = "我是类上的属性cprop"
def __init__(self,name,speed):
self.name = name # 动物名字
self._speed = speed # 动物行走或飞行速度
def __str__(self):
return '''Animal({0.name},{0._speed}) is printed
name={0.name}
speed={0._speed}'''.format(self)
def getSpeedBehavior(self):
pass
class Cat(Animal):
def __init__(self,name,speed,color,genre):
super().__init__(name,speed)
self.color = color
self.genre = genre
# 重写方法
def getSpeedBehavior(self):
print('running speed of %s is %s' %(self.name, self._speed))
return self._speed
class Bird(Animal):
def __init__(self,name,speed,color,genre):
super().__init__(name,speed)
self.color = color
self.genre = genre
# 重写方法
def getSpeedBehavior(self):
print('flying speed of %s is %s' %(self.name, self._speed))
return self._speed
重写完后则Manager导入参数Animal
# manager2.py 模块
import time
from animal2 import (Animal,Cat,Bird)
class Manager():
def __init__(self,animal):
self.animal = animal
def recordTime(self):
self.__t = time.time()
print('feeding time for %s is %.0f'%(self.animal.name,self.__t))
self.animal.getSpeedBehavior()
def getFeedingTime(self):
return '%0.f'%(self.__t,)
在实际使用时,将信息传入Cat类,再让Manager去继承,当执行Manager类recordTime方法时,就会指向Cat里的getSpeedBehavior
if __name__ == "__main__":
jiafeimao = Cat('jiafeimao',2,'gray','CatGenre')
haiying = Bird('haiying',40,'blue','BirdGenre')#创建了由Animal类继承且改写的实例
Manager(jiafeimao).recordTime()
print('#'*30)
Manager(haiying).recordTime()
下篇(进阶)
上篇中的多态重写方法并不是最好的,更优的方法是使用python内置的abc模块中的abstractmethod装饰器
import abc
class Animal():
cprop = "我是类上的属性cprop"
def __init__(self,name,speed):
self.name = name # 动物名字
self._speed = speed # 动物行走或飞行速度
def __str__(self):
return '''Animal({0.name},{0._speed}) is printed
name={0.name}
speed={0._speed}'''.format(self)
# 使用abstractmethod装饰器后,变为抽象方法,指明需要重写此方法
@abc.abstractmethod
def getSpeedBehavior(self):
pass
对类的属性赋值时,如果想要对取值范围加以限制,则可以使用property,先用property声明要限制的属性,再对声明的属性_speed使用setter函数,进行赋值检查。
# 读
@property
def _speed(self):#前面单下划线表示伪私有,外部可以访问,但声明了最好不要访问。
return self.__speed
# 写
@_speed.setter
def _speed(self,val):#对输入值进行检查
if val < 0:
raise ValueError('speed value is negative')
self.__speed = val
我们可以对实例动态地添加属性,也可以给类添加属性,但添加类属性过多则会内存占用大,影响程序性能,因此可以使用系统魔法函数slots
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
def __init__(self,name,age):
self.name = name
self.age = age
s = Student('xiaoming',100) # 创建新的实例
s.score=10
链式调用
每一个对外公开的方法都返回self
当执行完s.set_name('xiaoming1')时,返回的self和 .set_age(25)又组成了新的语句self.set_age(25),形成了一个链式调用。
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
def __init__(self, name, age):
self.name = name
self.age = age
def set_name(self, val):
self.name = val
return self
def set_age(self, age):
self.age = age
return self
def print_info(self):
print("name: " + self.name)
print("age: " + str(self.age))
return self
s = Student('xiaoming', 100) # 创建新的实例
(
s
.set_name('xiaoming1')
.set_age(25)
.print_info()
)
参考资料:Python与算法社区 ,作者zhenguo