Python语言系列-06-面向对象1





楔子

#!/usr/bin/env python3
# author:Alnk(李成果)


# 人狗大战例子引入面向对象

# 版本1
def hero(name, sex, hp, ce, level=2, exp=2000, money=10000):
    hero_info = {
        'name': name,
        'sex': sex,
        'hp': hp,  # 血值
        'ce': ce,  # 战斗力
        "level": level,  # 级别
        "exp": exp,  # 经验
        "money": money  # 金币
    }

    return hero_info


def dog(name, dog_type, hp, ce):
    dog_info = {
        'name': name,
        'dog_type': dog_type,
        'hp': hp,
        'ce': ce,
    }
    return dog_info


def bite(dog, hero):
    print("%s咬了%s" % (dog["name"], hero["name"]))


def attack(hero, dog):
    print("%s攻击了%s" % (hero["name"], dog["name"]))


tom = hero("tom", "male", 100, 80)
xiaohei = dog("小黑", "藏獒", 100, 5)

# 但是方法之间没有关联性,就会出现如下问题
bite(tom, xiaohei)  # tom咬了小黑
print("------------ 1 -----------------------------")


# 版本2
def hero(name, sex, hp, ce, level=2, exp=2000, money=10000):
    hero_info = {
        'name': name,
        'sex': sex,
        'hp': hp,
        'ce': ce,
        'level': level,
        'exp': exp,
        'money': money,
    }

    def attack(dog):        # 闭包
        print('%s攻击了%s' % (hero_info['name'], dog['name']))

    hero_info['attack'] = attack

    return hero_info


def dog(name, dog_type, hp, ce):
    dog_info = {
        'name': name,
        'dog_type': dog_type,
        'hp': hp,
        'ce': ce,
    }

    # 这里形成了闭包
    def bite(hero):
        print('%s咬了%s' % (dog_info['name'], hero['name']))

    dog_info['bite'] = bite

    return dog_info


tom = hero('tom', 'm', 100, 80)
xiaohei = dog('xiaohei', '狗子', 100, 5)

tom['attack'](xiaohei)
xiaohei['bite'](tom)


# 这里其实已经有用到面线对象的思维编程了




类的基本定义

#!/usr/bin/env python3
# author: Alnk(李成果)

"""
类的基本结构

class 类名:
    x=10  # 类变量

    def __init__(self, name): # 初始化方法 或 构造函数
        self.name = name      # 实例的属性,实例变量

    def run(self):            # 普通的实例方法
        pass
"""


# 类
# 类变量
#
# 类的实例
# 类的实例的变量
# 类的实例的方法


class Dog:  # 类名首字母大写
    def __init__(self, name, age, sex):  # 注意这里的self就是类的实例对象,此处的self就是Dog('tom', 40, '男')的内存地址或类的实例对象
        self.name = name  # 实例的变量
        self.age = age
        self.sex = sex


tom = Dog('tom', 40, '男')  # 类的实例化
print(tom)     # <__main__.Dog object at 0x0000000002229518>  内存地址。tom叫做实例对象
print("------------- 1 ----------------")


jerry = Dog("jerry", 22, "母")  # 类的实例化
print(jerry)     # <__main__.Dog object at 0x00000000026F9CC0>
print("------------- 2 ----------------")
"""
jerry = Dog("jerry", 22, "母")
实例化的过程:
    1 开辟一块内存空间,假如内存地址0x00000000026F9CC0
    2 执行Dog类的__init__方法,注意,self参数是内存地址0x00000000026F9CC0的内存空间
    3 将实例变量赋值给jerry变量
"""

# 类的实例的变量/属性  增删改查
# 增
tom.gf = '如花'
print(tom.gf)
print("------------- 3 ----------------")

# 删
# del jerry.name
# print(jerry.name)  # 会报错 AttributeError: 'Dog' object has no attribute 'name'

# 改
tom.name = '小李子'
print(tom.name)
print(jerry.name)
print("------------- 4 ----------------")

# 查
print(tom.name)
print(tom.sex)
print(tom.age)
print(jerry.name)
print(jerry.sex)
print(jerry.age)
print("------------- 5 ----------------")


# 类实例对象的名称空间
print(tom.__dict__)  # {'name': '小李子', 'age': 40, 'sex': '男', 'gf': '如花'}




一切皆对象

#!/usr/bin/env python3
# author: Alnk(李成果)

# python中一切数据皆为对象
# 我们使用的所有数据都是具体类的实例对象,比如str,list等等


# 可以实例化出无数个对象 可以点击去看源码,就是一个类
s1 = "hello"
s2 = str("world")
print(s1, s2)

l1 = list([1, 2, 3])
l2 = list([3, 4, 5])
print(l1, l2)

# 特殊的,只能实例化出2个对象
b1 = bool(1)
b2 = bool(0)
print(b1)
print(b2)




类的组合使用

#!/usr/bin/env python3
# author: Alnk(李成果)
# 在一个类中以另外一个 类的对象(类的实例对象) 作为数据属性,称为类的组合


class Weapon:
    def __init__(self, name, color, hurt):
        self.name = name
        self.color = color
        self.hurt = hurt  # 伤害


class Hero:
    def __init__(self, name, sex, hp, exp, ce, weapon):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.exp = exp
        self.ce = ce
        self.weapon = weapon


laser_gun = Weapon('激光枪', 'red', 1000)
tom = Hero('tom', 'male', 100, 70, 60, laser_gun)  # 把一个类的实例作为参数传入另外一个类的实例化过程

# 获取tom的武器属性
print(tom.weapon.name)
print(tom.weapon.color)
print(tom.weapon.hurt)




类的实例方法

#!/usr/bin/env python3
# author:Alnk(李成果)
# 类的实例方法


class Hero:
    def __init__(self, name, sex, hp, exp, ce):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.exp = exp
        self.ce = ce

    def attack(self, dog):  # 类的实例方法,简称方法
        print('%s 攻击了 %s' % (self.name, dog))


tom = Hero('tom', 'male', 100, 70, 60, )  # 类的实例化
tom.attack('小黑')  # 调用方法

jerry = Hero('jerry', 'male', 100, 70, 20, )
jerry.attack('大黄')




类对象的内存空间

# 实例方法会存在类空间里,不会存在实例空间里





类实例对象变量查找顺序

#!/usr/bin/env python3
# author: Alnk(李成果)

# 一个实例对象查找某个对象一定严格按照如下顺序
# 实例对象的内存空间 ---> 实例对象对应的类空间里查找  ---> 实例对象对应的类空间的父类空间查找




练习1

#!/usr/bin/env python3
# author: Alnk(李成果)
# 人狗大战


class Hero:
    def __init__(self, name, sex, hp, exp, ce):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.exp = exp
        self.ce = ce

    def attack(self, dog):
        print("%s 攻击了 %s" % (self.name, dog.name))


class Dog:
    def __init__(self, name, kind, hp, ce):
        self.name = name
        self.type = kind  # 种类
        self.hp = hp
        self.ce = ce

    def bite(self, hero):
        print("%s 咬了 %s" % (self.name, hero.name))


tom = Hero('tom', 'male', 100, 70, 60)
jerry = Dog('jerry', '藏獒', 100, 5)

tom.attack(jerry)  # 人攻击狗
jerry.bite(tom)    # 狗咬人




练习2

#!/usr/bin/env python3
# author: Alnk(李成果)
# 计算环形面积和总周长
from math import pi


class Circle:
    """计算圆的面积和周长"""
    def __init__(self, r):
        self.r = r  # 半径

    def get_area(self):
        """
        面积
        @return:
        """
        area = pi * self.r * self.r
        return area

    def get_perimeter(self):
        """
        周长
        @return:
        """
        perimeter = 2 * pi * self.r
        return perimeter


class Ring:
    """计算环形面积和总周长"""
    def __init__(self, outer_r, inner_r):
        """
        @param outer_r: 外圈圆半径
        @param inner_r: 内圈圆半径
        """
        self.outer_r = outer_r
        self.inner_r = inner_r
        self.outer_circle = Circle(self.outer_r)
        self.inner_circle = Circle(self.inner_r)

    def get_area(self):         # 环形面积
        return self.outer_circle.get_area() - self.inner_circle.get_area()

    def get_perimeter(self):    # 总周长
        return self.outer_circle.get_perimeter() + self.inner_circle.get_perimeter()


r = Ring(5, 4)
print(r.get_area())         # 面积
print(r.get_perimeter())    # 总周长




继承

继承的变量查找

#!/usr/bin/env python3
# author: Alnk(李成果)


class Animal:
    """动物类"""
    def __init__(self, name):
        self.name = name

    def run(self):
        print('running')

    def sleep(self):
        print('sleeping')


class Dog(Animal):
    """狗类"""
    def tongue_out(self):
        print('吐舌头')


class Cat(Animal):
    """猫类"""
    def climb_tree(self):
        print('爬树')

    def run(self):  # 会覆盖父类的run方法
        print('cat running')


t = Dog('tom')  # 注意虽然Dog类没有 __init__ 构造方法,但是父类有,所以还是需要传参
print(t.name)
t.run()  # 在父类中找到了run方法
t.tongue_out()

j = Cat('jerry')
print(j.name)
j.run()
print("---------------------------")


# 面试题
class Base:
    def __init__(self):
        self.func()

    def func(self):
        print('in base')


class Son(Base):
    def func(self):
        print('in son')


s = Son()  # in son
# 一个实例对象查找某个对象一定严格按照如下顺序
# 实例对象的内存空间 ---> 实例对象对应的类空间里查找  ---> 实例对象对应的类空间的父类空间查找


多重继承

#!/usr/bin/env python3
# author:Alnk(李成果)
# 多重继承


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

    def run(self):
        print('running')

    def sleep(self):
        print('sleeping')


class Fly:
    def fly(self):
        print('芜湖起飞...')


class Bat(Animal, Fly):     # 多重继承
    pass


class Ying(Animal, Fly):    # 多重继承
    pass


y = Ying('鹰')
y.run()
y.fly()


C3算法与多重继承查找顺序

#!/usr/bin/env python3
# author: Alnk(李成果)


# 示例 1
class O: pass
class F(O): pass
class E(O):pass
class D(O):pass
class C(E,F):pass
class B(D,E):pass
class A(B,C):pass


for s in A.__mro__:
    print(s)    # A/B/D/C/E/F/O 查找顺序
print("--------------- 1 ----------------")
# 从左往右,依照C3算法进行查找


# 示例 2
class A1: pass
class A2: pass
class A3: pass
class B1(A1,A2): pass
class B2(A2): pass
class B3(A2,A3): pass
class C1(B1): pass
class C2(B1,B2): pass
class C3(B2,B3): pass
class D(C1, C2, C3): pass

print("从D开始查找")
for s in D.__mro__:
    print(s)    # D/C1/C2/B1/A1/C3/B2/B3/A2/A3/OBJ
print("--------------- 2 ----------------")


print("从C3开始查找")
for s in C3.__mro__:
    print(s)    # C3/B2/B3/A2/A3


图1


图2




抽象类

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
# @Author: Alnk(李成果)
# @Email: 1029612787@qq.com
# @Date: 2021/4/20 4:07 下午
"""

import abc

# 有时,我们抽象出一个基类,知道要有哪些方法,但只是抽象方法,并不实现功能,只能继承,而不能被实例化,但子类必须要实现该方法
class Foo(abc.ABC):
    @abc.abstractmethod
    def fun_test(self):
        pass

    def test(self):
        pass

# a = Foo()  # 此时实例化报错 TypeError: Can't instantiate abstract class Foo with abstract methods fun


# 下面子类继承该方法
class Sub_foo(Foo):

    def f(self):
        print("in sub_foo")

# 此时实例化仍然报错,因为没有实现父类中的方法fun_test
# TypeError: Can't instantiate abstract class Sub_foo with abstract methods fun
# c = Sub_foo()


# 在子类中实现父类必须实现的方法 fun_test
class Son_foo(Foo):

    def fun_test(self):
        print("in son_foo")


s = Son_foo()
s.fun_test()  # in son_foo

# 此时实例化 Foo 类,仍然报错
# 因为抽象基类只能继承而不能实例化,子类要实例化必须先实现父类 @abc.abstractmethod 装饰的方法
# f = Foo()




练习题3

#!/usr/bin/env python3
# author: Alnk(李成果)
# 1、简述类、对象、实例化、实例是分别是什么
# 看图1


# 2、请简述面向对象三大特性?
# 封装
# 在类中对 数据的赋值、内部调用 对外部用户是透明的(这里透明的意思是类的外部不能调用这些数据,但是类的内部可以调用),
# 这使类变成了一个胶囊或容器,里面包含着类的数据和方法

# 继承
# 一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承

# 多态
# 多态是面向对象的重要特性,简单点说:“一个接口,多种实现”。
# 指一个基类(父类)中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
# 多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。
# 这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定。


# 3、说说python中所说的封装是什么意思?
# 封装
# 在类中对 数据的赋值、内部调用 对外部用户是透明的(这里透明的意思是类的外部不能调用这些数据,但是类的内部可以调用),
# 这使类变成了一个胶囊或容器,里面包含着类的数据和方法


# 4、多态是怎么回事?在python中是如何体现的?
# 多态:指的是一类事物有多种形态
# 动物有多种形态:人,狗,猪
import abc

class Animal(metaclass=abc.ABCMeta):  # 同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal):  # 动物形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal):  # 动物的形态之二:狗
    def talk(self):
        print('say wangwangwang')

class Pig(Animal):  # 动物的形态之三:猪
    def talk(self):
        print('say aoao')

# 多态性
peo = People()
dog = Dog()
pig = Pig()

# peo、dog、pig都是动物,只要是动物肯定有talk方法
# 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
print("------------------- 1 ----------------")

# 更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()

func(peo)
func(dog)
func(pig)
print("------------------- 2 ----------------")


# 5、说说面向对象中“私有”的概念以及应用
# 有私属性和私有方法,可以把不需要对外提供的内容和属性都隐藏起来,将变化隔离,便于应用,提高重用性,提高安全性。


# 6、在面向对象中有一些被装饰器装饰的方法,先说说有哪些装饰器,再说说这些装饰器的作用,以及装饰之后的效果
# property属性:改变一个方法的调用方式,把一个方法属性化,例如之前调用一个方法:obj.func() 加了property属性以后,可以用 obj.func 调用
# classmethod方法:类方法,增加这个属性以后,可以直接由类调用方法,当然实例对象也可以调用此方法
# staticmethod方法:静态方法,不涉及到类属性和实例属性的时候使用,调用该方法的时候,不再需要传递self参数了,定义该方法的时候也没有self参数


# 7、请说明新式类和经典类的区别,至少两个
# 多重继承查找顺序不同,
# 经典类按照深度优先的方法查找
# 新式类按照C3算法查找,即广度优先


# 8、请说出上面一段代码的输出并解释原因
class Foo:
    def func(self):
        print('in father')

class Son(Foo):
    def func(self):
        print('in son')

s = Son()
s.func()        # in son
# 一个实例对象查找某个属性方法一定严格按照如下顺序
# 实例对象的内存空间 ---> 实例对象对应的类空间里查找  ---> 实例对象对应的类空间的父类空间查找

图1




练习题4 校园管理系统

#!/usr/bin/env python3
# author: Alnk(李成果)

需求:
从“学生选课系统” 这几个字就可以看出来,我们最核心的功能其实只有选课

角色:
    学生、管理员

功能:
    登陆 : 管理员和学生都可以登陆,且登陆之后可以自动区分身份
    选课 : 学生可以自由的为自己选择课程
    创建用户 : 选课系统是面向本校学生的,因此所有的用户都应该由管理员完成
    查看选课情况 :每个学生可以查看自己的选课情况,而管理员应该可以查看所有学生的信息

工作流程:
    登陆 :用户输入用户名和密码
    判断身份 :在登陆成功的时候应该可以直接判断出用户的身份是学生还是管理员

    学生用户 :对于学生用户来说,登陆之后有三个功能
        1、查看所有课程
        2、选择课程
        3、查看所选课程
        4、退出程序

    管理员用户:管理员用户除了可以做一些查看功能之外,还有很多创建工作
        1、创建课程
        2、创建学生账号
        3、查看所有课程
        4、查看所有学生
        5、查看所有学生的选课情况
        6、退出程序


逻辑图


School_system.py

#!/usr/bin/env python3
# author:Alnk(李成果)
import os
import sys
import json


class Basic:
    """基础类"""

    def read_courses(self, file):
        """读取所有课程或所有学生"""
        kecheng_lis = []
        if os.path.isfile('db/courses/%s' % file):
            with open('db/courses/%s' % file, encoding='utf-8', mode='r') as f:
                for i in f:
                    kecheng_lis.append(i.strip('\n'))
                return kecheng_lis
        else:
            return []

    def read_users(self, file):
        """读取所有课程或所有学生"""
        kecheng_lis = []
        if os.path.isfile('db/users/%s' % file):
            with open('db/users/%s' % file, encoding='utf-8', mode='r') as f:
                for i in f:
                    kecheng_lis.append(i.strip('\n'))
                return kecheng_lis
        else:
            return []

    def write_courses(self, name, file):
        """创建课程"""
        if not os.path.isdir("db/courses"):
            os.makedirs("db/courses")

        with open('db/courses/%s' % file, encoding='utf-8', mode='a+') as f:
            f.write('%s\n' % name)

    def write_users(self, name, file):
        """创建学生"""
        if not os.path.isdir("db/users"):
            os.makedirs("db/users")

        with open('db/users/%s' % file, encoding='utf-8', mode='a+') as f:
            f.write('%s\n' % name)

    def write_dic(self,stu_name, stu_dict):
        """把学生详细信息字典写入到文件"""
        if not os.path.isdir('db/users'):
            os.makedirs('db/users')

        with open('db/users/%s' % stu_name, encoding='utf-8', mode='w') as f:
            json.dump(stu_dict,f)

    def read_dic(self, stu_name):  # 读取账号密码信息
        if  os.path.isfile('db/users/%s' % stu_name):
            with open('db/users/%s' % stu_name, encoding='utf-8', mode='r') as f:
                stu_dic = json.load(f)
            return stu_dic
        else:
            return {}

    def see_all_kecheng(self):  # 查看所有课程
        kecheng_lis = self.read_courses('kecheng_list')
        print('\n所有课程:%s' % kecheng_lis)

    def login_out(self):  # 退出
        sys.exit('退出!')


class Student(Basic):
    '''学生类'''

    def xuanke(self):  # 选择课程
        kecheng_list = self.read_courses('kecheng_list')
        print('\n课程列表:%s' % kecheng_list)

        hava_select = self.read_dic(user_name)['course']
        print('\n已选课程:%s' % hava_select)

        for i in hava_select:  # 不可重复添加相同的课程
            if i in kecheng_list:
                kecheng_list.remove(i)
        print('\n可选课程:%s' % kecheng_list)

        if len(kecheng_list) == 0:
            print('\n所有课程都已经添加过了哦,暂时没有课程啦!')
            return

        choice = input('\n请输入你想选择的课程>>>:').strip()
        if choice in kecheng_list:  # 选课
            stu_dic = self.read_dic(user_name)
            stu_dic['course'].append(choice)
            self.write_dic(user_name, stu_dic)
            print('\n[%s]课程选择成功!' % choice)
        elif choice in hava_select:  # 已经选取的课程
            print('\n[%s]课程已经添加过了,不可重复添加' % choice)
        else:
            print('\n[%s]该课程不存在!' % choice)

    def see_all_xuanke(self):  # 查看所选课程
        stu_dic = self.read_dic(user_name)
        print('\n[%s]所选的课程有:%s' % (user_name, stu_dic['course']))


class Admin(Basic):
    """管理类"""

    def create_kecheng(self):
        """创建课程"""
        kecheng = input('\n请输入你要创建的课程>>>:')
        all_kecheng_lis = self.read('kecheng_list')

        if kecheng in all_kecheng_lis:
            print('\n课程[%s]已经创建过了,不可重复创建哟' % kecheng)
        else:
            self.write_courses(kecheng, 'kecheng_list')
            print('\n[%s]课程创建成功!' % kecheng)

    def create_stu(self): # 创建学生
        stu_name = input('\n学生账号>>>:')
        stu_pwd = input('密码>>>:')
        all_stu_dic = self.read_users('student_list')

        if stu_name in all_stu_dic:
            print('\n学生账号[%s]已经被注册了!' % stu_name)
        else:
            stu_dict = {'name':stu_name, 'passwd':stu_pwd, 'role':'1', 'course':[],}
            self.write_dic(stu_name, stu_dict)  # 学生个人信息写入单独文件
            self.write_users(stu_name, 'student_list')  # 统计所有学生姓名
            print('\n学生账号[%s]创建成功\n' % stu_name)

    def see_all_stu(self):  # 查看所有学生
        all_stu_dic = self.read_users('student_list')
        print('\n所有学生:%s' % all_stu_dic)

    def see_stu_xuanke(self):  # 查看所有学生选课情况
        student_lis = self.read_users('student_list')
        if student_lis:
            for stu_name in student_lis:
                stu_dic = self.read_dic(stu_name)
                print('\n学生[%s]的选课情况: %s' % (stu_name,stu_dic['course']))
        else:
            print('\n还没有学生哟!')


class View:
    """视图类"""

    def student_user(self): # 学生视图
        msg = '''------- 欢迎来到学生界面 -------
        1、查看所有课程
        2、选择课程
        3、查看所选课程
        4、退出程序      
        '''
        dic = {
            '1': Student().see_all_kecheng,
            '2': Student().xuanke,
            '3': Student().see_all_xuanke,
            '4': Student().login_out,
        }
        while 1:
            print('\n%s' % msg)
            choice = input('请输入编号>>:')
            if dic.get(choice):
                dic[choice]()
            else:
                print('请输入正确的编号\n')

    def admin_user(self):  # 管理员视图
        msg = '''------- 欢迎来到管理员界面 -------
        1、创建课程
        2、创建学生账号
        3、查看所有课程
        4、查看所有学生
        5、查看所有学生的选课情况
        6、退出程序
        '''
        dic = {
            '1': Admin().create_kecheng,
            '2': Admin().create_stu,
            '3': Admin().see_all_kecheng,
            '4': Admin().see_all_stu,
            '5': Admin().see_stu_xuanke,
            '6': Admin().login_out,
        }
        while 1:
            print('\n%s' % msg)
            choice = input('请输入编号>>:')
            if dic.get(choice):
                dic[choice]()
            else:
                print('请输入正确的编号\n')


class Login(View, Basic):
    """登录类"""

    def __init__(self, user_name, user_pwd):
        self.name = user_name
        self.passwd = user_pwd

    def login(self):
        user_dict = self.read_dic(self.name)  # 获取以账号名返回的字典

        if user_dict:
            if user_dict['passwd'] == self.passwd:  # 判断密码
                if user_dict['role'] == '0':        # 管理员角色
                    self.admin_user()               # 调用视图
                elif user_dict['role'] == '1':      # 学生角色
                    self.student_user()
            else:
                print('账号或密码有误啊!\n')
        else:
            print('账号或密码有误!\n')


def init_admin():
    admin_dict = {
        'username': 'admin',
        'passwd': '123',
        'role': '0',  # 0:管理员用户   1:学生用户
    }

    if not os.path.isdir("db/users"):
        os.makedirs("db/users")

    if not os.path.isfile("db/users/admin"):
        with open('db/users/admin', encoding='utf-8', mode='w') as f:
            json.dump(admin_dict, f)


if __name__ == '__main__':
    init_admin()
    user_name = input('请输入登录账号>>>:')
    user_pwd = input('请输入密码>>>:')
    l = Login(user_name, user_pwd)
    l.login()


posted @ 2021-04-20 17:18  李成果  阅读(78)  评论(0编辑  收藏  举报