【Python】二、Python面向对象
类和对象
理解
类是对象的模板,对象是类的实例。好比类是做月饼的模具,而做出的各个馅的月饼就是一个个对象,你说模具是月饼不够恰当,但模具创造月饼,月饼依赖模具,月饼之所以不是饺子、包子,也依赖于模具。
Python用class
定义类,也用同名进行实例化。
class Animals():
...
cat = Animals()
构造函数
但是动物的种类繁多,每个种类也有各个不同的个体,且每个个体都有自己的属性、动作等,因此我们可以通过在实例化对象的时候传入他的属性,这需要构造函数的帮助,即__init__
函数,__init__
函数在对象被实例化时自动运行。
class Animals():
def __init__(self,kind,name,age):
self.kind = kind
self.name = name
self.age = age
cat = Animals('cat','kitty',1)
self
作为必须传入的参数,它可以是任何名字,self
是习惯写法,self
代表当前调用某一个方法的对象。
类变量与实例变量
类变量和实例变量不同,实例变量是对于每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。
class Animals():
num = 0 #类变量
def __init__(self,kind,name,age):
self.kind = kind #实例变量
self.name = name
self.age = age
若实例变量和类变量名字相同,实例化对象时,实例变量会覆盖类变量,即优先寻找实例变量,若无再寻找类变量
实例方法
对象的行为或动作,被定义为实例方法,用.
调用
class Animals():
def __init__(self,kind,name,age):
self.kind = kind
self.name = name
self.age = age
def run(self):
print(self.name + "is running")
cat = Animals('cat','kitty',1)
cat.run()
在实例方法中访问实例变量很容易,只需要加self
,但是访问类变量的话,就需要使用其他方法
class Animals():
num = 0
def __init__(self):
Animal.num += 1 #直接使用类名+.的方式访问
self.__class__.num += 1 #通过对象的__class__方法访问
类方法
定义类方法时,需要在方法前加入装饰器@classmethod
,用来操作和类相关的变量,由类和对象都可调用(建议由类调用,供类使用)
class Animals():
num = 0
@classmethod
def num_plus(cls):
cls.num += 1
静态方法
使用装饰器@staticmethod
定义静态方法,可以访问类变量
成员的可见性
避免直接修改实例变量,可以通过调用实例方法修改实例变量(强烈建议)
class Animals():
def __init__(self,name):
self.name = name
self.age = 0
def change_age(self,age):
if age < 0:
return "年龄错误"
self.age = age
但是即使使用实例方法修改实例变量,还是可以通过赋值直接修改实例变量,那么如何解决呢?将公有变量变为私有,在变量名前加__
class Animals():
def __init__(self,name):
self.name = name
self.__age = 0
def change_age(self,age):
if age < 0:
return "年龄错误"
self.__age = age
私有的实例变量仍能在类外进行修改,但是在修改之前不能访问。Python的动态语言的特性,在类外修改时,就是添加了一个新的属性,和类内的属性无关。
class Animals():
def __init__(self,name):
self.name = name
self.__age = 0
cat = Animals('kitty')
print(cat.__age) #AttributeError: 'Animal' object has no attribute '__age'
cat.__age = 1
print(cat.__age) # 1
print(cat.__dict__) #{name': 'kitty', '_Animal__age': 0, '__age': 1}
其中_Animal__age
是类内的私有变量,__age
为新定义的__age属性,此时访问print(cat._Animal__age)
会得到类内私有变量的结果
事实上,Python的私有变量只是在定义的时候偷偷换掉了名字,在类外当然无法访问,但是赋值时,创建了新的变量,类内定义的私有变量仍然存在,且通过一定手段仍可在类外访问,即 Python没有什么是不能访问的,只是约定俗成,君子行为,请大家自觉
继承
为避免定义重复的属性和重复的方法,用继承来省去子类所拥有的父类相同的属性和方法,父类提供公有属性和方法,子类也可以拥有自己特有的属性和方法
class Animals():
num = 0
def __init__(self, name):
self.name = name
def run(self):
print(self.name+" is running...")
class Cat(Animals):
def eat_fish(self):
print("Eating fish")
cat = Cat("kitty")
print(cat.name)
cat.run()
cat.eat_fish()
当构造函数不一致时,可以添加子类特有属性,并将公有属性传入父类
class Animals():
def __init__(self,name):
self.name = name
class Cat(Animals):
def __init(self,age,name):
self.age = age
Animals.__init__(self,name) #不能丢失self,在没有形成实例化对象前,都不能丢掉self
但是若Cat()
更改父类之后,则类内含有原父类的代码都需要更改,因此这种方法不可取,我们使用super
来代替父类
class Animals():
def __init__(self,name):
self.name = name
class Cat(Animals):
def __init(self,age,name):
self.age = age
super(Cat,self).__init__(name)
如果子类方法和父类方法同名,优先调用子类方法
可以在子类方法中调用父类方法,super(Cat,self).eat_fish()
...