类与对象

面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑、操作、应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

定义类

class Animal:
    def run(self):
        print("我会跑")
  • objectPython 里所有类的最顶级父类。
  • 类名 的命名规则按照"大驼峰命名法"。
  • run 是一个实例方法,第一个参数一般是 self,表示实例对象本身。也可以将 self 换为其它的名字,其作用是定义了一个指向当前对象的变量。

创建对象

a1 = Animal()
a1.run()

a2 = Animal()
a2.run()

可以使用已经定义的类去创建出一个或多个对象。用盖房子,来简单的理解:

  • 类就相当于做房子的图纸,对象就是依据图纸做出来真实的房子。
  • 一张图纸可以做多个相似的房子出来。
  • (图纸) 通过 实例化(建造) 变成 对象(真实的房子)

设置和获取对象的属性

class Animal:
    def run(self):
        print("我的名字叫:%s" % self.name)
        print("我会跑")


animal = Animal()
animal.name = "小猪皮皮"

print(animal.name)
animal.run()
  • 在类内部获取属性实例方法,通过 self 获取。
  • 在类外部获取属性实例方法,通过对象名获取。
  • 如果一个类有多个对象,每个对象的属性是各自保存的,都有各自独立的地址。
  • 但是实例方法是所有对象共享的,只占用一份内存空间。类会通过 self 来判断是哪个对象调用了实例方法。

魔术方法

如果方法名是__xxxx__()的,那么就是有特殊功能的方法,我们叫它 魔术 方法。

__init__ 构造方法

class Animal:
    def __init__(self, name, age):
        print("Hello There~")
        self.name = name
        self.age = age

    def run(self):
        print("我的名字叫:%s" % self.name)
        print("我%s岁了" % self.age)
        print("我会跑")


pig = Animal('小猪皮皮', 3);
pig.run()
  • __init__() 方法,在创建一个对象时默认被调用,不需要手动调用
  • __init__(self) 中的 self 参数,不需要传递,Python 解释器会自动把当前对象传递进去

__str__ 方法

class Animal:
    def __init__(self, name, age):
        print("实例化,我就要先运行")
        self.name = name
        self.age = age

    def run(self):
        print("我的名字叫:%s" % self.name)
        print("我%s岁了" % self.age)
        print("我会跑")

    def __str__(self):
        return "我的名字叫:%s" % self.name


pig = Animal('小猪皮皮', 3);
print(pig)
  • 当使用 print 输出对象的时候,默认打印对象的内存地址。如果类定义了 __str__(self) 方法,那么就会打印从在这个方法中 return 的数据
  • __str__ 方法通常返回一个字符串,作为这个对象的描述信息。

__del__ 析构方法

创建对象后,python 解释器默认调用 __init__() 方法。

当删除对象时,python 解释器也会默认调用一个方法,这个方法为 __del__() 方法。

class Animal:
    def __init__(self, name, age):
        print("实例化,我就要先运行")
        self.name = name
        self.age = age

    def run(self):
        print("我的名字叫:%s" % self.name)
        print("我%s岁了" % self.age)
        print("我会跑")

    def __del__(self):
        print("哟西,我被干掉了")


pig = Animal('小猪皮皮', 3);
bird= Animal('鹦鹉波利', 1);
  • 当有变量保存了一个对象的引用时,此对象的引用计数就会加1。
  • 当使用 del() 删除变量指向的对象时,则会减少对象的引用计数。如果对象的引用计数不为1,那么会让这个对象的引用计数减1,当对象的引用计数为0的时候,则对象才会被真正删除(内存被回收)。
  • 运行以上代码,可以看到两个构造都运行完成了以后,才会运行析构。

继承

单继承

class Animal:
    def run(self):
        print("我会跑")


class Bird(Animal):
    def fly(self):
        print("我会飞")


brid = Bird();
brid.run()
brid.fly()

多继承

class Father:
    def run(self):
        print("我是你爹,我会跑")

    def work(self):
        print("我会搬砖")


class Mother:
    def run(self):
        print("我是你妈,我会跑")

    def cook(self):
        print("我会做饭")


class Child(Father, Mother):
    pass


child = Child()
child.run()
child.work()
child.cook()
print(Child.__mro__)
  • 多继承可以继承多个父类,也继承了所有父类的属性和方法
  • 注意:如果多个父类中有同名的属性和方法,则默认使用第一个父类的属性和方法(根据子类的 __mro__ 魔术属性属性按顺序来查找)。
  • 多个父类中,不重名的属性和方法,不会有任何影响。

子类重写父类的同名属性或方法

class Animal:
    def run(self):
        print("我会跑")


class Bird(Animal):
    def run(self):
        print("我跑不快")


brid = Bird();
brid.run()

子类调用父类中同名的属性或方法

调用父类方法格式:父类类名.父类方法(self)

class Animal:
    def run(self):
        print("我会跑")


class Bird(Animal):
    def run(self):
        # 不要这样使用,相当于创建了一个新的父类对象
        # Animal().run()

        Animal.run(self)
        print("我跑不快")


brid = Bird();
brid.run()
  • 无论何时何地,self 表示的都是被实例化类的对象,而不是父类。

多层继承

class Grandpa:
    def draw(self):
        print("我是你爷爷,我会画画")


class Father(Grandpa):
    def music(self):
        print("我是你爹,我会弹钢琴")


class Child(Father):
    pass


child = Child()
child.music()
child.draw()

super()的使用

class Father:
    def run(self):
        print("我是你爹,我会跑")


class Mother:
    def run(self):
        print("我是你妈,我会跑")


class Child(Father, Mother):
    def run(self):
        super().run()
        Father.run(self)
        Mother.run(self)


child = Child()
child.run()
  • 如果使用 Animal.run(self) 这种格式,子类继承了多个父类。假如父类类名修改了,那么子类也要涉及多次修改。而且需要重复写多次调用,显得代码臃肿。

  • 如果继承了多个父类,且父类都有同名方法,super() 默认只执行第一个父类的,而无法执行多个父类的同名方法。

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print("我叫%s" % self.name)
        print("我%s岁了" % self.age)
        print("我会跑")


class Bird(Animal):
    def __init__(self, name, age, color):
        super().__init__(name, age)
        self.color = color

    def run(self):
        super().run()
        print("我的羽毛是%s的" % self.color)
        print("但是我跑不快")


brid = Bird('鹦鹉波利', 1, "黄色");
brid.run()
  • super() 通常用于单继承中
  • super() 经常出现在 __init__