【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()

    ...

posted @ 2021-09-19 17:27  灰灰不吃鱼  阅读(41)  评论(0编辑  收藏  举报