Python基础知识:面向对象(封装、继承、多态)1

面向对象(封装、继承、多态)

领取Python学习资料可以加小编的微信:tz2020jd

类中: ①特征被称为属性;②行为被称为方法;③三要素:类名、属性、方法;

dir函数可以查看对象的所有方法;

dir显示的方法中,__方法名__格式的方法是Python提供的内置方法/属性

Python基础知识:面向对象(封装、继承、多态)1_第1张图片

类中的方法第一个参数必须是self(类似Java中的this?);
创建第一个类:

class Cat:
    def eat(self):
        print("小猫爱吃鱼!")
    def drink(self):
        print("小猫爱喝水!")


tom = Cat()  # 和Java不同,不需要使用 new
tom.eat()
tom.drink()

print(tom)  # 输出对象变量
print("%x" % id(tom))  # 输出16进制的地址
print("%d" % id(tom))  # 输出10进制的地址

输出:
Python基础知识:面向对象(封装、继承、多态)1_第2张图片

引用的强调

Python基础知识:面向对象(封装、继承、多态)1_第3张图片

Python如果不想修改类,可以直接给对象增加属性(不同于其他语言!)(这种方式不推荐);
self关键字(Java中的this关键字): 哪一个对象调用的这个方法,self就是哪个对象的引用,可以通过self.访问对象的属性和方法;
初始化方法__init__:
当使用类名()创建对象时,会自动执行以下操作:

①. 为对象在内存中分配空间 – 创建对象;
②. 为对象的属性 设置初始值 – 初始化方法(init);

这个初始化方法就是__init__方法,__init__是对象的内置方法。
__init__方法是专门用来定义一个类具有哪些属性的方法!

在初始化方法__init__内部定义属性:
在init方法内部使用self.属性名 = 属性的初始值就可以定义属性;
定义属性之后,再使用该类创建的对象,都拥有该属性;
使用:

class Cat:
    def __init__(self):
        print("这是一个初始化方法")
        self.name = "Tom"

    def eat(self):
        print("%s 爱吃鱼" % self.name)


tom = Cat()
print(tom.name)
tom.eat()

输出:

 

这是一个初始化方法
Tom
Tom 爱吃鱼


初始化方法__init__中带参数,构造对象;
class Cat:
    def __init__(self, new_name):
        print("这是一个初始化方法")
        self.name = new_name

    def eat(self):
        print("%s 爱吃鱼" % self.name)


tom = Cat("Tom")
print(tom.name)
tom.eat()

lazy_cat = Cat("大懒猫")
print(lazy_cat.name)
lazy_cat.eat()


__del__方法的调用

Python基础知识:面向对象(封装、继承、多态)1_第4张图片

class Cat:
    def __init__(self, new_name):
        print("初始化方法被调用")

    def __del__(self):
        print("del方法被调用")


# tom是一个全局变量 等到程序全部执行完成之后才会销毁
tom = Cat("Tom")

# 可以手动调用 del tom 提前销毁 tom对象
# del tom
print("*" * 50)


输出: (注意: 如果不注释 # del tom,__del__方法的调用就在输出横线的上方)

 

初始化方法被调用
**************************************************
del方法被调用

__str__方法(类似Java中的toString())
在python中,使用print输出对象变量,默认情况下输出这个变量 引用的对象是由哪一个类创建的对象,以及在内存中的地址(16进制表示) ;
如果在开发中,希望使用print输出对象变量时,能够打印自定义内容,就可以利用__str__方法;
注意:__str__方法必须返回一个字符串;
class Cat:
    def __init__(self, new_name):
        self.name = new_name

    def __str__(self):  # 返回的是一个字符串
        return "我是小猫【%s】" % self.name


tom = Cat("Tom")
print(tom)

输出:

我是小猫【Tom】
1
面向对象案例一 : 房子和家具
class HouseItem:
    def __init__(self, name, area):
        self.name = name
        self.area = area

    def __str__(self):
        return "家具名称: %s, 家具面积: %s " % (self.name, self.area)


class House:
    def __init__(self, house_type, area):  # 房子类型, 总面积
        self.house_type = house_type
        self.area = area
        self.free_area = area  # 一开始剩余面积等于总面积
        self.item_list = []  # 家具列表一开始是空的
        pass

    def __str__(self):
        # python 能够自动的将一对括号内内部的代码 连接在一起
        return ("户型: %s\n总面积: %.2f【剩余: %.2f】\n家具: %s"  # 如果没有使用括号,这里就要有一个 \ 换行标符
                % (self.house_type, self.area,
                   self.free_area, self.item_list))  # 注意这里使用了一个括号

    def add_item(self, item):  # 在列表中添加家具
        if self.free_area < item.area:
            print("房子已满,不能再放家具了!")
            return
        self.item_list.append(item.name)
        self.free_area -= item.area

# 创建家具
bed = HouseItem("席梦思", 40)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 20)

# 创建房子
my_home = House("两室一厅", 60)
print(my_home)

# 添加家具
my_home.add_item(bed)
print(my_home)
my_home.add_item(chest)
print(my_home)
my_home.add_item(table)
print(my_home)


输出:

户型: 两室一厅
总面积: 60.00【剩余: 60.00】
家具: []
户型: 两室一厅
总面积: 60.00【剩余: 20.00】
家具: ['席梦思']
户型: 两室一厅
总面积: 60.00【剩余: 18.00】
家具: ['席梦思', '衣柜']
房子已满,不能再放家具了!
户型: 两室一厅
总面积: 60.00【剩余: 18.00】
家具: ['席梦思', '衣柜']


面向对象案例二 : 枪和士兵
class Gun:  # 枪类
    def __init__(self, model): 
        self.model = model
        self.bullet_mount = 0

    def add_bullet(self, count):
        self.bullet_mount += count

    def shoot(self):
        if self.bullet_mount <= 0:
            print("【%s】没有子弹了..." % self.model)

        self.bullet_mount -= 1
        print("%s 突突突...【剩余子弹: %d】" % (self.model, self.bullet_mount))


class Soldier:
    def __init__(self, name):
        self.name = name
        # 这个使用None关键字 假定新兵没有枪
        self.gun = None  # Node类似Java中的null

    def fire(self):
        # 1.判断士兵是否有枪
        # if self.gun == None:  # 不推荐
        if self.gun is None:
            print("【%s】 还没有枪..." % self.name)
            return
        # 2. 高喊口号
        print("冲鸭...【%s】" % self.name)
        # 3. 让枪装填子弹
        self.gun.add_bullet(50)
        # 4.让枪发射子弹
        self.gun.shoot()


# 创建枪的对象
ak47 = Gun("AK47")
ak47.add_bullet(50)
ak47.shoot()

# 创建士兵对象
xusanduo = Soldier("许三多")
xusanduo.fire()  # 没有枪,打不了
xusanduo.gun = ak47  # 给士兵一把ak47的枪
xusanduo.fire()


身份运算符( == 类似Java中的equals,而 is(身份运算符) 却类似 java中的 ==);
 

Python基础知识:面向对象(封装、继承、多态)1_第5张图片

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)  # True
print(a is b)  # False


私有属性和私有方法: 只需要在属性名或者方法名前面加上两个下划线(真的6…),私有属性只能在类的内部使用;
但是Python中没有真正意义的私有,这个私有只是伪私有。可以使用_类名__属性或者_类名__方法强制访问私有属性或方法;
class Woman:
    def __init__(self, name):
        self.name = name
        self.__age = 18  # 加上两个_表示私有属性

    def secret(self):
        # 注意对象内部可以访问私有属性
        print("%s 的年龄是 %d" % (self.name, self.__age))


xiaomei = Woman("小美")

# print(xiaomei.__age)  # 报错,不能直接访问私有方法
xiaomei.secret()  # 这个可以

# 但是也可以通过 " _类名__属性/方法"  来强制访问私有属性或方法
print(xiaomei._Woman__age)  # 强制访问


输出:

小美 的年龄是 18
18

关于继承中的重写,和Java中差不多,直接覆盖即可;
class Animal:

    def eat(self):
        print("吃!")

    def drink(self):
        print("喝!")

    def run(self):
        print("跑!")

    def sleep(self):
        print("睡")


class Dog(Animal):  # 继承直接加上括号,不需要extends 关键字

    def bark(self):
        print("汪汪汪!")


class XiaoTianQuan(Dog):  # 继承可以传递,既继承了Animal也继承了Dog

    def fly(self):
        print("飞!")

    def bark(self):  # 重写方法
        print("嗷嗷嗷!")


xiao_tian = XiaoTianQuan()
xiao_tian.eat()
xiao_tian.drink()
xiao_tian.bark()
xiao_tian.fly()

扩展相关方法中使用super()关键字,和Java也差不多;
class XiaoTianQuan(Dog):  # 继承可以传递,既继承了Animal也继承了Dog

    def fly(self):
        print("飞!")

    def bark(self):  # 重写方法
        super().bark()  # 先调用父类的方法  #注意这个super()关键字在python2.x中没有
        print("嗷嗷嗷!")


注意子类不能访问父类的私有属性
class A:
    def __init__(self):
        self.num1 = 3  
        self.__num2 = 33

    def __test(self):
        print("num1 = %d, num2 = %d" % (self.num1, self.__num2))


class B(A):
    def demo(self):  # 测试能不能访问父类的私有方法
        # 访问父类的私有属性
        print("访问父类的私有属性 %d" % self.__num2)

        # 访问父类的私有方法
        self.test()

a = A()
b = B()
b.demo()  # 报错


但是子类可以通过公有方法间接的来访问父类的私有属性;
class A:
    def __init__(self):
        self.__num2 = 33

    def __test(self):
        print("__num2 = %d" % self.__num2)

    def test(self):
        # 访问自己类的 私有属性
        print("私有属性__num2 = %d" % self.__num2)
        # 访问自己类的 私有方法
        self.__test()


class B(A):
    def demo(self):
        self.test()  # 通过访问公共方法 test来间接访问 私有属性

b = B()
b.demo()  # 报错


注意,使用多继承的时候,如果两个父类中有相同的方法,尽量避免使用多继承, 避免产生混淆。可以使用__mro__(方法搜索顺序)用于在多继承时,判断方法、属性的调用路径;
class A:
    def test1(self):
        print("A类中的test_1方法!")

    def test2(self):
        print("A类中的test_2方法!")


class B:
    def test1(self):
        print("B类中的test_1方法!")

    def test2(self):
        print("B类中的test_2方法!")


class C(A, B):
    pass

c = C()
c.test1()
c.test2()
print(C.__mro__)  # 输出C的继承路径


输出:


 

领取Python学习资料可以加小编的微信:tz2020jd

你可能感兴趣的:(Python基础知识)