python笔记更新(面向对象)

面向对象

面向对象的介绍

  • 面向过程:根据业务逻辑从上到下写代码
  • 面向对象:将变量和函数绑定到一起,分类进行封装,每个程序只要负责分配给自己的分类,这样能够更快速的开发程序,减少了重复代码。

面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程的思路是将数据和函数按照执行的逻辑顺序组织在一起,数据与函数分开考虑,面向过程基本是由函数组成的。

# 面向过程
# 关注点:怎样做
def add_user():
    pass


def del_user():
    pass


def modify_user():
    pass


def query_user():
    pass


def show_all():
    pass 


def start():
    pass


if __name__ == '__main__':
    start()
# 面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)
# 关注点:谁来做
# 例如,植物大战僵尸
# 分类:
# 大方向分为两类,植物和僵尸
# Plant:1.特征:hp,cost,position,cd 2.行为:shake()
# 		类的继承:ProtectPlant, AttackPlant:damage伤害值,attack_cd, attack()
# Zombie:1.特征:2.行为:

面向对象的基本语法

类和对象是面向对象编程的两个核心概念。

类是对一群具有相同特征或者行为的事物的一个统称,是抽象的。

  • 特征其实就是一个变量,在类里称之为属性
  • 行为其实就是一个函数,在类里称之为方法
  • 类其实就是由属性和方法组成的一个抽象概念
  1. 对象

对象是由类创建出来的一个具体存在。由哪一个类创建出来的对象,就拥有在哪一个类中定义的属性和方法。对象就相当于用图纸制造的飞机。在开发中,应该先有类,在类里定义好属性和行为,再根据类来创建对象。

在程序开发中,要设计一个类,通常需要满足三个要素:

  1. 类名:这类事物的名字,按照大驼峰命名法起名

    1. 属性:这类事物具有什么样的特征
      3. 方法:这类事物具有什么样的行为
# 小明今年18岁,身高1.75,每天早上跑完步,会去吃东西
# 小美今年17岁,身高1.65,小美不跑步,小美喜欢吃东西
# 定义类:类名怎样定义?使用class定义一个类
# class 类名  类名一般需要遵守大驼峰命名法,每一个单词的首字母都大写
# 1. class <类名>:
# 2. class <类名>(object):
class Student(object):  # 关注这个类有哪些特征和行为
    # 在 __init__ 方法里,以参数的形式定义特征,称之为属性
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height

    # 行为定义为一个个函数
    def run(self):
        print('正在跑步')

    def eat(self):
        print('正在吃东西')


# 使用 Student 类创建了两个实例对象 s1 s2
# s1 和 s2 都会有name,age,height属性,同时都有run和eat方法
s1 = Student('小明', 18, 1.75)  # Student() ==> 会自动调用 __init__ 方法
s2 = Student('小美', 17, 1.65)
# 根据业务逻辑,让不同的对象执行不同的行为
s1.run()
s1.eat()
s2.eat()

self的介绍

class Student(object):
    def __init__(self, x, y):
        self.name = x
        self.age = y

    def say_hello(self):
        print('大家好,我是', self.name)


# Student('张三', 18) 这段代码具体做了什么呢?
# 1. 调用 __new__ 方法,用来申请一段内存空间
# 2. 调用 __init__ 方法传入参数,并让 self 指向申请好的那段内存空间,填充数据
# 3. 让 s1 也指向创建好的这段内存空间
s1 = Student('张三', 18)
print('0x%X' % id(s1))  # 0x18B224DE2C8
print('s1的名字是', s1.name)  # s1的名字是 张三
s1.say_hello()  # 大家好,我是 张三
s2 = Student('jack', 21)
s2.say_hello()  # 大家好,我是 jack

双下划线slots双下划线属性的使用

class Student(object):
    # 这个属性直接定义在类里,是一个元组,用来规定对象可以存在的属性
    __slots__ = ('name', 'age', 'city')

    def __init__(self, x, y):
        self.name = x
        self.age = y

    def say_hello(self):
        print('大家好,我是', self.name)


s = Student('张三', 18)
print(s.name)
s.say_hello()
# 没有属性会报错
# print(s.height)  # AttributeError: 'Student' object has no attribute 'height'
# 直接使用等号给一个属性赋值
# 如果这个属性以前不存在,会给对象添加一个新的属性
# 动态属性
s.city = '上海'  # 给对象添加了一个city属性
print(s.city)  # 上海
# 如果这个属性以前存在,会修改这个属性对应的值
s.name = 'jack'
print(s.name)  # jack

魔法方法1

# 魔法方法,也叫魔术方法,是类里的特殊的一些方法
# 特点:
# 1. 不需要手动调用,会在合适的时机自动调用
# 2. 这些方法,都是使用 __ 开始,使用 __ 结束
# 3. 方法名都是系统规定好的,在合适的时机自己调用
import time


class Person(object):
    # 在创建对象时,会自动调用这个方法
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def __del__(self):
        # 当对象被销毁时,会自动调用这个方法
        print('__del__方法被调用了')


p = Person('zhangsan', 18)  # __init__方法被调用了
# del p  # 也可以手动销毁
time.sleep(10)  # 休息10秒,程序结束,数据自动被销毁,# __del__方法被调用了
# import datetime
#
# x = datetime.datetime(2020, 2, 24, 16, 17, 45, 200)
# print(x)  # __str__ 方法, __str__ 可读性更高
# print(repr(x))  # __repr__ 方法, __repr__ 更加准确


class Person(object):
    # 在创建对象时,会自动调用这个方法
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def __del__(self):
        # 当对象被销毁时,会自动调用这个方法
        print('__del__方法被调用了')

    def __repr__(self):
        return 'hello'

    def __str__(self):
        return '姓名:{},年龄:{}'.format(self.name, self.age)

    def __call__(self, *args, **kwargs):
        print('__call__ 被调用了')
        # args 是一个元组,保存(1, 2)
        # kwargs 是一个字典{'fn':lambda x, y: x + y}
        print('args={}, kwargs={}'.format(args, kwargs))
        # fn = kwargs['fn']
        # return fn(args[0], args[1])
        return kwargs['fn'](args[0], args[1])


p = Person('zhangsan', 18)
# 如果不做任何的修改,直接打印一个对象,是文件的 __name__.类型 内存地址
# print(p)  # <__main__.Person object at 0x0000018EC3EB0408>

# 当打印一个对象的时候,会调用这个对象的 __str__ 或者 __repr__ 方法
# 如果两个方法都写了,选择 __str__ 方法
print(p)

# print(repr(p))  # 调用内置函数repr会触发对象的 __repr__ 方法
# print(p.__repr__())  # 魔法方法,一般不手动调用,但可以手动调用

# p()  #  'Person' object is not callable
# 使用 __call__ 方法
# p()  # 对象名() ==> 调用这个对象的 __call__ 方法
n = p(1, 2, fn=lambda x, y: x + y)  # 相当于 p.__call__(可变参数)   __call__ 中有可变参数
print(n)

运算符相关的魔法方法

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

    def __eq__(self, other):
        print('__eq__方法被调用了,other=', other)
        # if self.name == other.name and self.age == other.age:
        #     return True
        # return False
        return self.name == other.name and self.age == other.age


p1 = Person('zhangsan', 18)
p2 = Person('zhangsan', 18)
p3 = Person('zhangsan', 19)
# p1 和 p2 是同一个对象吗?不是,指向了不同的地址,但内容相同
# 怎样比较两个对象是否是同一个对象?比较的是内存地址
print('0x%X' % id(p1))  # 0x2B5553586C8
print('0x%X' % id(p2))  # 0x2B555358708
# is 身份运算符 可以用来判断两个对象是否是同一个对象
print('p1 is p2', p1 is p2)  # False
# __eq__ 如果不重写,默认比较依然是内存地址
print('p1 == p2', p1 == p2)  # 本质调用 p1.__eq__(p2),获取这个方法的返回结果
print('p1 == p3', p1 == p3)
# is 比较两个对象的内存地址
# == 会调用对象的 __eq__ 方法,获取这个方法的比较结果
# nums1 = [1, 2, 3]
# nums2 = [1, 2, 3]
# print(nums1 is nums2)  # False
# print(nums1 == nums2)  # True

练习(important)

class House(object):
    def __init__(self, house_type, total_area, fru_list=None):
        if fru_list is None:
            fru_list = []
        self.house_type = house_type
        self.total_area = total_area
        self.free_area = total_area * 0.6
        self.fru_list = fru_list

    def add_fru(self, x):
        if self.free_area < x.area:
            print('剩余面积不足,放不进去了')
        else:
            self.fru_list.append(x.name)
            self.free_area -= x.area

    def __str__(self):
        return '户型={},总面积={},剩余面积={},家具列表={}'.format(self.house_type, self.total_area, self.free_area, self.fru_list)


class Furniture(object):
    def __init__(self, name, area):
        self.name = name
        self.area = area


house = House('一室一厅', 20)
sofa = Furniture('沙发', 10)
bed = Furniture('席梦思', 4)
chest = Furniture('衣柜', 2)
table = Furniture('餐桌', 1.5)
house.add_fru(sofa)
house.add_fru(bed)
house.add_fru(chest)
house.add_fru(table)
print(house)  '''剩余面积不足,放不进去了
				 剩余面积不足,放不进去了
				 户型=一室一厅,总面积=20,剩余面积=0.0,家具列表=['沙发', '衣柜']'''

魔法方法2

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

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    # def __ne__(self, other):  使用 != 运算符会自动调用这个方法
    def __gt__(self, other):  # greater than 使用 > 会自动调用这个方法
        return self.age > other.age

    # def __ge__(self, other):  # 使用 >= 运算符会自动调用
    # def __lt__(self, other):  # less than  p1 < p2
    # def __le__(self, other):  # <=
    def __add__(self, other):  # +
        return self.age + other.age

    def __sub__(self, other):  # -
        return self.age - other

    def __mul__(self, other):  # *
        return self.name * other

    # def __truediv__(self,other):  # /
    # def __mod__(self, other):  # 取模
    def __pow__(self, power, modulo=None):  # 幂运算
        return self.age ** power

    def __str__(self):
        return 'hello'

    def __int__(self):
        return 20

    def __float__(self):
        return 100.5


p1 = Person('zhangsan', 18)
p2 = Person('zhangsan', 18)
p3 = Person('lisi', 19)
print(p1 is p2)  # False
# == 运算符本质其实是调用对象的 __eq__ 方法,获取 __eq__ 方法的返回结果
# a == b  =>  a.__eq__(b)
print(p1 == p2)  # True  p1.__eq__(p2)
# != 本质是调用 __ne__ 方法 或者 __eq__ 取反
print(p1 != p2)  # False
print(p1 > p3)  # False
print(p1 + p2)  # 36
print(p1 - 2)  # 16
print(p1 * 2)  # zhangsanzhangsan
print(p1 ** 2)  # 324
# 转换成为字符串,默认会转换成为类型 + 内存地址
# str()将对象转换成为字符串,会自动调用 __str__ 方法
# print(str(p1))  # <__main__.Person object at 0x000001CE181A1C08>
print(str(p1))  # hello
# int() ==> 调用对象的 __int__ 方法
print(int(p1))  # 20
# float() ==> 调用对象的 __float__ 方法
print(float(p1))  # 100.5

内置属性

class Person(object):
    """
    这是一个人类
    """
    # __slots__ = ('name', 'age')

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

    def eat(self):
        print(self.name + '正在吃饭')


# ‘name’: 'zhangsan', 'age': 18, 'eat': <function>
p = Person('张三', 18)
print(dir(p))
print(p.__class__)  # <class '__main__.Person'>
# __dict__ 把对象属性和值转换成为一个字典
print(p.__dict__)  # {'name': '张三', 'age': 18}
print(p.__dir__())  # 等价于 dir(p)
print(p.__doc__)  # 这是一个人类  对象名.__doc__
print(Person.__doc__)  # 这是一个人类  类名.__doc__
print(p.__module__)  # __main__

把对象当做字典操作

class Person(object):
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city

    def __setitem__(self, key, value):
        # print('setitem方法被调用了,key={},value={}'.format(key, value))
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]


p = Person('张三', 18, '襄阳')
print(p.__dict__)  # 将对象转换成为字典 {'name': '张三', 'age': 18, 'city': '襄阳'}
# 不能直接把一个对象当做字典来使用
p['name'] = 'tony'  # [] 语法会调用对象的 __setitem__ 方法
p['age'] = 20
print(p.name, p.age)  # jack
print(p['name'])  # 会调用 __getitem__ 方法   tony

类属性和对象属性

class Person(object):
    type = '人类'  # 这个属性定义在类里,函数之外,我们称之为类属性

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


# Person 称之为 类对象
# 对象 p1, p2 是通过 Person 类创建出来的 实例对象
# name 和 age 是对象属性,在 __init__ 方法里,以参数的形式定义的
# 每一个实例对象都会单独保存一份的属性
# 每个实例对象之间的属性没有关联,互不影响
p1 = Person('张三', 18)
p2 = Person('李四', 19)
# 类属性可以通过类对象和实例对象获取
print(Person.type)  # 人类
print(p1.type)  # 人类
print(p2.type)  # 人类
p1.type = 'human'
print(p1.type)  # 并不会修改类属性,而是给实例对象添加了一个新的对象属性
print(Person.type)  # 人类
# 类属性只能通过类对象来修改,实例对象无法修改类属性
Person.type = 'monkey'  # 修改了类属性
print(p2.type)  # monkey

私有属性和方法的使用

import datetime


class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__money = 1000  # 以 __ 开始的变量是私有变量

    # def test(self):
    #     self.__money += 10  # 在这里可以访问私有属性
    def get_money(self):
        print('{}查询了余额'.format(datetime.datetime.now()))
        return self.__money

    def set_money(self, qian):
        if type(qian) != int:
            print('设置的余额不合法')
        else:
            print('修改余额了')
            self.__money = qian

    def __demo(self):  # 以 __ 开始的函数,是私有函数,在外部无法调用
        print('我是demo函数,name={}'.format(self.name))

    def test(self):
        self.__demo()


p = Person('张三', 18)
print(p.name, p.age)  # 张三 18
# print(p.__money)  # 不能够直接获取到私有变量
# p.__demo()  # 不能直接调用demo函数,它是私有方法
p._Person__demo()
# 获取私有变量的方式:
# 1. 使用 对象._类名__私有变量名 获取
# p.test()
print(p._Person__money)  # 1000
# 2. 定义 get 和 set 方法来获取
print(p.get_money())  # 1000
p.set_money('hello')
print(p.get_money())

类方法和静态方法

class Calculator(object):
    @staticmethod
    def add(a, b):
        return a + b

    @staticmethod
    def minus(a, b):
        return a - b

    @staticmethod
    def mul(a, b):
        return a * b


# c = Calculator()
# c.add(1, 2)
Calculator.add(1, 4)
Calculator.minus(9, 2)
Calculator.mul(2, 4)


class Person(object):
    type = 'human'

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

    def eat(self, food):  # 对象方法有一个参数self,指的是实例对象
        print(self.name + '正在吃' + food)

    # 如果一个方法里没有用到实例对象的任何属性,可以将这个方法写成static
    @staticmethod
    def demo():  # 默认的方法都是对象方法
        print('hello')

    @classmethod
    def test(cls):  # 如果这个函数只用到了类属性,我们可以把它定义成为一个类方法
        # 类方法会有一个参数 cls,也不需要手动的传参,会自动传参
        # cls 指的是类对象    cls is Person  ==> True
        print(cls.type + 'yes')


p1 = Person('张三', 18)
p2 = Person('李四', 19)
# 实例对象在调用方法时,不需要给形参self传参,会自动的把实例对象传递给self
# eat 对象方法,可以直接使用 实例对象.方法名(参数) 调用
# 使用 对象名.方法名(参数) 调用的方式,不用传self
p1.eat('红烧牛肉泡面')  # 直接使用实例对象调用方法
# print(p1.eat is p2.eat)  # False
# 方法存在类对象中,方法和实例对象是绑定关系
# print(p1.eat)  # <bound method Person.eat of <__main__.Person object at 0x000001946CF41B08>>
# print(p2.eat)  # <bound method Person.eat of <__main__.Person object at 0x000001946CF41C08>>
# print(Person.eat)  # <function Person.eat at 0x00000297A5D69558>
# 对象方法还可以使用类对象来调用 类名.方法名()
# 这种方式,不会自动给self传参,需要手动的指定self
Person.eat(p2, '西红柿鸡蛋盖饭')
# 静态方法:没有用到实例对象,也用不到类对象
Person.demo()
p1.demo()
# 类方法:可以使用实例对象和类对象调用
p1.test()
Person.test()

单例设计模式

class Singleton(object):
    __instance = None  # 类属性
    __is_first = True

    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            # 申请内存,创建一个对象,并把对象的类型设置为cls
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self, a, b):
        if self.__is_first:
            self.a = a
            self.b = b
            self.__is_first = False


# 调用 __new__ 方法申请内存
# 如果不重写 __new__ 方法,会调用 object 的 __new__ 方法
# object的 __new__ 方法会申请内存
# 如果重写了 __new__ 方法,需要自己手动的申请内存
s1 = Singleton('呵呵', '嘿嘿嘿')
s2 = Singleton('哈哈', '嘻嘻嘻')
s3 = Singleton('嘎嘎', '嘤嘤嘤')
# 单例就是使得结果为 True,创建的对象一样
print(s1 is s2)  # True
print(s1.a, s1.b)  # 嘎嘎 嘤嘤嘤  这样前一个会被覆盖
# 能否避免被覆盖,那就改 __init__
print(s1.a, s1.b)  # 呵呵 嘿嘿嘿

小练习

# 定义一个类属性,记录通过这个类创建了多少个对象
class Person(object):
    __count = 0  # 类属性

    def __new__(cls, *args, **kwargs):
        cls.__count += 1
        instance = object.__new__(cls)  # 申请内存,创建了一个对象,并设置类型是 Person 类
        return instance

    def __init__(self, name, age):
        # Person.count += 1
        self.name = name
        self.age = age

    @classmethod
    def get_count(cls):
        return cls.__count


# 每次创建对象,都会调用 __new__ 和 __init__ 方法
# 调用 __new__ 方法,用来申请内存
# 如果不重写 __new__ 方法,它会自动找 object 的 __new__
# object 的 __new__ 方法,默认实现申请一段内存,创建一个对象
p1 = Person('张三', 18)
p2 = Person('李四', 19)
p3 = Person('jack', 20)
# print(Person.get_count())  # 3
# 用 __new__ 方法也可以做
print(Person.get_count())  # 3
# 申请了内存,创建了一个对象,并设置它的类型是Person
# p4 = object.__new__(Person)
# p4.__init__('tony', 23)

继承的基本使用

# 面向对象编程有三大特性:封装、继承、多态
# 封装:函数是对语句的封装;类是对函数和变量的封装
# 继承:类和类之间可以人为手动的建立父子关系,父类(基类)的属性和方法,子类(派生类)可以使用
# 多态:是一种技巧,提高代码的灵活度
class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sleep(self):
        print(self.name + '正在睡觉')


class Dog(Animal):
    def bark(self):
        print(self.name + '正在叫')


class Student(Animal):
    def study(self):
        print(self.name + '正在好好学习')


# Dog() 调用 __new__ 方法,再调用 __init__ 方法
# Dog 里没有 __new__ 方法,会查看父类是否重写了 __new__ 方法
# 父类里也没有重写 __new__ 方法,查找父类的父类,找到了 object
# 调用 __init__ 方法,Dog类没有实现,会自动找 Animal 父类
d1 = Dog('大黄', 3)
print(d1.name)  # 父类里定义的属性,子类可以直接使用
d1.sleep()  # 父类的方法子类实例对象可以直接调用
d1.bark()

s1 = Student('小明', 18)
s1.sleep()
s1.study()

继承的注意事项

class A(object):
    def demo_a(self):
        print('我是A类里的方法demo_a')

    def foo(self):
        print('我是A类里的foo方法')


class B(object):
    def demo_b(self):
        print('我是B类里的方法demo_b')

    def foo(self):
        print('我是B类里的foo方法')


# class C:  # 如果不写父类,Python3以后,默认继承自object
# Python里允许多继承
class C(A, B):
    pass


c = C()
c.demo_a()  # 我是A类里的方法demo_a
c.demo_b()  # 我是B类里的方法demo_b
# 如果两个不同的父类有同名方法,有一个类属性可以查看方法的调用顺序
c.foo()  # 我是A类里的foo方法
print(C.__mro__)  # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
class A(object):
    pass


class B(object):
    def foo(self):
        print('我是B类里的foo方法')


class C(A):
    def foo(self):
        print('我是C类里的foo方法')


class D(B):
    pass


class X(D, C):
    pass


x = X()
# 深度优先
x.foo()  # 我是B类里的foo方法
print(X.__mro__)  # (<class '__main__.X'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
# <class '__main__.A'>, <class 'object'>)

私有属性的继承特点

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

    def eat(self):
        print(self.name + '正在吃东西')

    def __test(self):
        print('我是Animal类里的test方法')


class Person(Animal):
    def __demo(self):
        print('我是Person里的私有方法')


p = Person('张三', 18)
print(p.name)
p.eat()
p._Person__demo()  # 自己类里定义的私有方法   对象名._类名__私有方法名()
p._Animal__test()  # 可以通过 对象名._父类名__私有方法() 调用
# 私有属性和方法,子类不会继承
# p._Person__test()  # 父类的私有方法,子类没有继承
# print(p._Person__money)
print(p._Animal__money)  # 1000

新式类和经典类

# 手动的指定Student类继承自object
class Student(object):
    pass


# 没有指定Dog的父类,Python3里默认继承自object
class Dog:
    pass


# 新式类和经典类的概念:
# 1.新式类:继承自 object 的类我们称之为新式类
# 2.经典类:不继承自 object 的类
# 在Python2里,如果不手动的指定一个类的父类是object,这个类就是一个经典类
# Python3里不存在经典类,都是新式类

面向对象相关的运算符方法

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


class X(object):
    pass


class Student(Person, X):
    pass


p1 = Person('张三', 18)
p2 = Person('张三', 18)
s = Student('jack', 20)
# 获取两个对象的内存地址  id(p1) == id(p2)
print(p1 is p2)  # is 身份运算符是用来比较是否是同一个对象
# type(p1)  # 其实获取的就是类对象
print(type(p1) == Person)  # True
# s 这个实例对象是否是由Student类创建的?
print(type(s) == Student)  # True
print(type(s) == Person)  # False
# isinstance 用来判断一个对象是否是由指定的类(或者父类)实例化出来的
print(isinstance(s, (Student, X)))  # True
print(isinstance(s, Person))  # True
print(isinstance(p1, Student))  # False
# issubclass 用来判断一个类是否是另一个类的子类
print(issubclass(Student, (Person, X)))  # True
print(issubclass(Person, Student))  # False

子类重写父类方法

# 继承特点:如果一个类A继承自类B,由类A创建出来的实例对象都能直接使用类B里定义的方法
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sleep(self):
        print(self.name + '正在睡觉')


class Student(Person):
    def __init__(self, name, age, school):
        # self.name = name
        # self.age = age
        # 子类在父类实现的基础上,有添加了自己新的功能
        # 1.父类名.方法名(self, 参数列表)
        # Person.__init__(self, name, age)
        # 2.使用super直接调用父类的方法。推荐使用第二种方法
        super(Student, self).__init__(name, age)
        self.school = school

    def sleep(self):
        print(self.name + '正在课间休息时睡觉')

    def study(self):
        print(self.name + '正在学习')


s = Student('jerry', 20, '春田花花幼稚园')  # 调用了父类的 __init__ 方法
s.sleep()  # 调用了父类的 sleep 方法
# 1.子类的实现和父类的实现完全不一样,子类可以选择重写父类的方法
# 2.子类在父类的基础上又有更多的实现

不使用多态的问题

class PoliceDog(object):
    def attack_enemy(self):
        print('警犬正在攻击坏人')


class Person(object):
    def __init__(self, name, dog):
        self.name = name
        self.dog = dog

    def work_with_pd(self):
        print(self.name + '正在工作')
        self.dog.attack_enemy()


pd = PoliceDog()
police = Person('张警官', pd)
police.work_with_pd()
class PoliceDog(object):
    def attack_enemy(self):
        print('警犬正在攻击坏人')


class BlindDog(object):
    def lead_road(self):
        print('导盲犬正在领路')


class DrugDog(object):
    def search_drug(self):
        print('缉毒犬正在搜毒')


class Person(object):
    def __init__(self, name):
        self.name = name
        self.dog = None

    def work_with_pd(self):
        if self.dog is not None:
        	print(self.name + '正在工作')
        	self.dog.attack_enemy()

    def work_with_bd(self):
        if self.dog is not None:
        	self.dog.lead_road()

    def work_with_dd(self):
        if self.dog is not None:
        	self.dog.search_drug()


p = Person('张三')

pd = PoliceDog()
p.dog = pd
p.work_with_pd()

bd = BlindDog()
p.dog = bd
p.work_with_bd()

dd = DrugDog()
p.dog = dd
p.work_with_dd()

多态的使用

# 多态是基于继承,通过子类重写父类的方法,达到不同的子类对象调用相同的父类方法,得到不同的结果
# 提高代码的灵活度
class Dog(object):
    def work(self):
        print('狗正在工作')


class PoliceDog(Dog):
    def work(self):
        print('警犬正在攻击敌人')


class BlindDog(Dog):
    def work(self):
        print('导盲犬正在领路')


class DrugDog(Dog):
    def work(self):
        print('缉毒犬正在搜毒')


class Person(object):
    def __init__(self, name):
        self.name = name
        self.dog = None

    def work_with_dog(self):
        if self.dog is not None and isinstance(self.dog, Dog):
            self.dog.work()


p = Person('张三')

pd = PoliceDog()
p.dog = pd
p.work_with_dog()

bd = BlindDog()
p.dog = bd
p.work_with_dog()

dd = DrugDog()
p.dog = dd
p.work_with_dog()

练习题

1
# 设计两个类:
# 一个点类,属性包括x,y坐标
# 一个Rectangle类(矩形),属性有左上角和右下角的坐标
# 方法:1.计算矩形的面积;2.判断点是否在矩形内
# 实例化一个点对象,一个矩形对象,输出矩形的面积,输出点是否在矩形内
class Point(object):
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y


class Rectangle(object):
    def __init__(self, top_left: Point, bottom_right: Point):
        self.top_left = top_left
        self.bottom_right = bottom_right

    def get_area(self):
        # 面积:长*宽
        length = abs(self.bottom_right.x - self.top_left.x)
        width = abs(self.top_left.y - self.bottom_right.y)
        return length * width

    def is_inside(self, point):
        return self.bottom_right.x >= point.x >= self.top_left.x and self.top_left.y >= point.y >= self.bottom_right.y


p1 = Point(4, 20)  # 定义左上角的点
p2 = Point(30, 8)  # 定义右下角的点
r = Rectangle(p1, p2)  # 把左上角和右下角的点传递给矩形
print(r.get_area())  # 26*12=312
p = Point(20, 30)
print(r.is_inside(p))
2
# 建立一个汽车类 Auto
# 包括轮胎个数,汽车颜色,车身重量,速度等属性,并通过不同的构造方法创建实例
# 至少要求 汽车能够加速 减速 停车
# 再定义一个小汽车类 CarAuto 继承 Auto 并添加空调、导航属性
# 并且重新实现方法覆盖加速、减速的方法
class Auto(object):
    def __init__(self, color, weight, speed=0, wheel_count=4):
        self.color = color
        self.weight = weight
        self.speed = speed
        self.wheel_count = wheel_count

    def change_speed(self, x):
        """
        修改车速
        :param x: 表示要修改的车速值。如果是正数,表示加速,负数表示减速,0表示停车
        """
        if x == 0:  # 如果传递的参数是0,表示要停车
            self.speed = 0
            return
        self.speed += x
        if self.speed <= 0 and x < 0:
            self.speed = 0
            return  # return 后面可以什么数据都不加,表示函数结束


class CarAuto(Auto):
    def __init__(self, color, weight, ac, navigator, speed=0, wheel_count=4):
        super(CarAuto, self).__init__(color, weight, speed, wheel_count)
        self.ac = ac
        self.navigator = navigator


car = CarAuto('白色', 1.6, '美的', 'iOS', 10, 5)
3

方法一

# 定义一个点类 Pointer
# 属性是横向坐标 x 与纵向坐标 y
# 定义一个圆类 Circle
# 属性有圆心点 cp 与半径radius
# 方法有:
# 1.求圆的面积
# 2.求圆的周长
# 3.求指定点与圆的关系
import math


class Pointer(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


class Circle(object):
    def __init__(self, cp, radius):
        self.cp = cp
        self.radius = radius

    def get_area(self):
        return self.radius ** 2 * math.pi

    def get_length(self):
        return self.radius * 2 * math.pi

    def relationship(self, point):
        """
        求一个点和圆的关系。有三种关系:在圆内,在圆外,在圆上
        :param point:需要判断的点
        """
        distance = (abs(point.x) - abs(self.cp.x)) ** 2 + (abs(point.y) - abs(self.cp.y)) ** 2
        if distance > self.radius ** 2:
            print('在圆外')
        elif distance < self.radius ** 2:
            print('在圆内')
        else:
            print('在圆上')


p = Pointer(3, 4)  # 创建了一个Pointer对象p
c = Circle(p, 5)  # 创建好的Pointer对象p传递给了Circle对象c
print(c.get_area())
print(c.get_length())
p1 = Pointer(10, 10)
c.relationship(p1)
p2 = Pointer(2,2)
c.relationship(p2)
p3 = Pointer(0, 0)
c.relationship(p3)

方法二,使用子类重写父类

import math


class Pointer(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


class Circle(Pointer):
    def __init__(self, x, y, radius):
        super(Circle, self).__init__(x, y)
        self.radius = radius

    def get_area(self):
        return self.radius ** 2 * math.pi

    def get_length(self):
        return self.radius * 2 * math.pi

    def relationship(self, point):
        distance = (abs(point.x) - abs(self.x)) ** 2 + (abs(point.y) - abs(self.y)) ** 2
        if distance > self.radius ** 2:
            print('在圆外')
        elif distance < self.radius ** 2:
            print('在圆内')
        else:
            print('在圆上')


c = Circle(3, 4, 5)
p = Pointer(10, 10)
c.relationship(p)
4
打印列表
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return '姓名:{},年龄:{}'.format(self.name, self.age)


p1 = Person('张三', 18)
p2 = Person('李四', 20)
# print(p1)  # 调用 __str__ 或者 __repr__ 方法
persons = [p1, p2]
# 直接打印列表,会调用列表里元素的 __repr__ 方法
print(persons)  # 直接打印一个列表,会把列表里的每一个对象的内存地址打印出来

方法一

# 宠物店类 PetShop
# 属性:店名,店中的宠物[使用列表存储宠物]
# 方法:展示所有宠物的信息
# 宠物狗类 PetDog
# 属性:昵称,性别,年龄,品种
# 方法:叫,拆家,吃饭
# 宠物猫类 PetCat
# 属性:昵称,性别,年龄,品种,眼睛的颜色
# 方法:叫,撒娇,吃饭
# 注意:狗的叫声是汪汪,猫的叫声是喵喵,狗吃的是骨头,猫吃的是鱼
class PetShop(object):
    def __init__(self, shop_name, pet_list=None):
        self.shop_name = shop_name
        if pet_list is None:
            pet_list = []
        self.pet_list = pet_list

    # def __init__(self, shop_name):
    #     self.shop_name = shop_name
    #     self.pet_list = []

    def show_pets(self):
        if len(self.pet_list) == 0:
            print('本店还没有宠物')
            return
        print('{}店有{}个宠物,它们是:'.format(self.shop_name, len(self.pet_list)))
        for pet in self.pet_list:
            # print('{}:性别:{},品种:{},年龄:{}岁'.format(pet.name, pet.gender, pet.breed, pet.age))
            print(pet)


class Pet(object):
    def __init__(self, name, gender, age, breed):
        self.name = name
        self.gender = gender
        self.age = age
        self.breed = breed

    def bark(self):
        print(self.name + '正在叫')

    def eat(self):
        print(self.name + '正在吃东西')

    def __str__(self):
        return '姓名:{},性别:{},品种:{},年龄:{}'.format(self.name, self.gender, self.age, self.breed)


class PetDog(Pet):
    def bark(self):
        print(self.name + '正在汪汪汪')

    def build_home(self):
        print(self.name + '正在拆家')

    def eat(self):
        print(self.name + '正在啃骨头')


class PetCat(Pet):
    def __init__(self, name, gender, age, breed, eyes_color):
        super(PetCat, self).__init__(name, gender, age, breed)
        self.eyes_color = eyes_color

    def bark(self):
        print(self.name + '正在喵喵喵')

    def sajiao(self):
        print(self.name + '正在撒娇')

    def eat(self):
        print(self.name + '正在吃鱼')

    def __str__(self):
        x = super(PetCat, self).__str__()
        x += ',眼睛颜色:{}'.format(self.eyes_color)
        return x


dog1 = PetDog('大黄', 'female', 3, '哈士奇')
dog2 = PetDog('二黄', 'male', 2, '萨摩耶')
cat1 = PetCat('tom', 'male', 2, '英短', 'blue')
cat2 = PetCat('包子', 'female', 3, '加菲猫', 'black')
ps = PetShop('萌宠', [dog1, dog2, cat1, cat2])
ps.show_pets()

方法二,打印列表

class PetShop(object):
    def __init__(self, shop_name, pet_list=None):
        self.shop_name = shop_name
        if pet_list is None:
            pet_list = []
        self.pet_list = pet_list

    def show_pets(self):
        if len(self.pet_list) == 0:
            print('本店还没有宠物')
            return
        print('{}店有{}个宠物,它们是:{}'.format(self.shop_name, len(self.pet_list), self.pet_list))


class Pet(object):
    def __init__(self, name, gender, age, breed):
        self.name = name
        self.gender = gender
        self.age = age
        self.breed = breed

    def bark(self):
        print(self.name + '正在叫')

    def eat(self):
        print(self.name + '正在吃东西')

    def __repr__(self):
        return '姓名:{},性别:{},品种:{},年龄:{}岁'.format(self.name, self.gender, self.age, self.breed)


class PetDog(Pet):
    def bark(self):
        print(self.name + '正在汪汪汪')

    def build_home(self):
        print(self.name + '正在拆家')

    def eat(self):
        print(self.name + '正在啃骨头')


class PetCat(Pet):
    def __init__(self, name, gender, age, breed, eyes_color):
        super(PetCat, self).__init__(name, gender, age, breed)
        self.eyes_color = eyes_color

    def bark(self):
        print(self.name + '正在喵喵喵')

    def sajiao(self):
        print(self.name + '正在撒娇')

    def eat(self):
        print(self.name + '正在吃鱼')

    def __repr__(self):
        x = super(PetCat, self).__repr__()
        x += ',眼睛颜色:{}'.format(self.eyes_color)
        return x


dog1 = PetDog('大黄', 'female', '哈士奇', 3)
dog2 = PetDog('二黄', 'male','萨摩耶', 2)
cat1 = PetCat('tom', 'male','英短', 2, 'blue')
cat2 = PetCat('包子', 'female','加菲猫', 3, 'black')
ps = PetShop('萌宠', [dog1, dog2, cat1, cat2])
ps.show_pets()
5
# 学生类 Student
# 属性:学号,姓名,年龄,性别,成绩
# 班级类 Grade
# 属性:班级名称,班级中的学生[使用列表存储学生]
# 方法:
# 1.查看该班级中的所有学生的信息
# 2.查看指定学号的学生信息
# 3.查看班级中成绩不及格的学生信息
# 4.将班级中的学生按照成绩降序排序
class Student(object):
    def __init__(self, number, name, age, gender, score):
        self.number = number
        self.name = name
        self.age = age
        self.gender = gender
        self.score = score

    def __str__(self):
        return '学号:{},姓名:{},年龄:{},性别:{},成绩:{}'.format(self.number, self.name, self.age, self.gender,
                                                      self.score)


class Grade(object):
    def __init__(self, name, students):
        self.name = name
        self.students = students

    def show_all(self):
        for k in self.students:
            print(k)

    def get_student_by_number(self, n):
        for i in self.students:
            if i.number == n:
                return i
        else:
            return '用户未找到'

    def failed_students(self):
        result = filter(lambda stu: stu.score < 60, self.students)
        for j in result:
            print(j)

    def order_student(self):
        # self.students.sort(key=lambda s: s.score, reverse=True)  # 直接修改 self.students 属性
        return sorted(self.students, key=lambda s: s.score, reverse=True)


# 如果数字以0开头,在Python2里表示八进制
s1 = Student(1, 'zhangsan', 18, 'male', 80)
s2 = Student(5, '李四', 19, 'male', 50)
s3 = Student(10, 'tony', 20, 'male', 70)
s4 = Student(7, 'jack', 18, 'female', 90)
s5 = Student(4, 'henry', 19, 'female', 56)
g = Grade('中二班', [s1, s2, s3, s4, s5])
# g.show_all()
# print(g.get_student_by_number(1))
# g.failed_students()
x = g.order_student()
for student in x:
    print(student)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值