python_面向对象编程

一、面向对象编程

# 1.什么是面向对象
    面向过程与面向对象
        面向过程编程:解决问题从过程出发,解决问题步骤化

        面向对象编程:解决问题从对象出发,解决问题找对象

    对象与类
        类:对象的类型 => 数字
            具有相同特征与行为集合的抽象

        对象:类的具体表现 => 数字10
            类的实例化,就是具有特征与行为实际存在的个体(每一个对象都是唯一的)

# 2.为什么要面向对象编程
        面向过程:开发成本高,解决问题局限性小
        面向对象:开发成本低,解决问题局限于对象

        问题:'abc' => {'a', 'b', 'c'}
            面向过程: 自己写
            面向对象:str => list => set  #(引用模块)

        开发:优选面向对象(找解决问题的对象),
        再考虑找多个对象(面向对象与面向过程的结合),
        最后自己去封装一个可以解决问题的对象(对外是面向对象的体现,内部解决问题的核心是面向过程)

# 例如:
s = 'abc'  # => ['a', 'b', 'c']
# 解决方案
# re.findall()  list初始化方法
# for循环append

# 面向过程:解决问题步骤化
res = []
for c in s:
    res.append(c)
print(res)

# 面向对象:解决问题找对象
#       -- 对象如何解决问题:对象.解决问题的方法()

# 找re对象
import re
res = re.findall(r'[a-z]', s)
print(res)

# 找list对象
res = list(s)
print(res)

# 模块 md.py
def print_num(a):
    print(a)

from md import print_num as pn
pn(100)
pn(200)

二、类的声明语法

class 类名:
    # 在该缩进下(在类下)定义多个函数,类名就可以整体管理所有的函数,通过点语法来调用具体的函数
    def fn1():
        print('fn1 run')
    def fn2():
        print('fn2 run')
    def fn3():
        print('fn3 run')
        
# 类名的命名规范:采用大驼峰

三、点语法与名称空间

def fn():
    pass

class Fn():
    def a_fn():
        pass
    pass

import md

print(fn, fn.__dict__)
#  {}

print(Fn, Fn.__dict__)
#  {'__module__': '__main__', 'a_fn': , '__dict__': , '__weakref__': , '__doc__': None}

print(md, md.__dict__)
# {'__name__': 'md', '__doc__': None, '__package__': '', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001EA6E10>, '__spec__': ModuleSpec(name='md', loader=<_frozen_importlib_external.SourceFileLoader object at 0x0000000001EA6E10>, origin='F:\\安装包\\JetBrains\\JetBrains\\Projects\\09\\代码\\part2\\md.py'), '__file__': 'F:\\安装包\\JetBrains\\JetBrains\\Projects\\09\\代码\\part2\\md.py', '__cached__': 'F:\\安装包\\JetBrains\\JetBrains\\Projects\\09\\代码\\part2\\__pycache__\\md.cpython-36.pyc', '__builtins__': {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': , 'all': , 'any': , 'ascii': , 'bin': , 'callable': , 'chr': , 'compile': , 'delattr': , 'dir': , 'divmod': , 'eval': , 'exec': , 'format': , 'getattr': , 'globals': , 'hasattr': , 'hash': , 'hex': , 'id': , 'input': , 'isinstance': , 'issubclass': , 'iter': , 'len': , 'locals': , 'max': , 'min': , 'next': , 'oct': , 'ord': , 'pow': , 'print': , 'repr': , 'round': , 'setattr': , 'sorted': , 'sum': , 'vars': , 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': , 'memoryview': , 'bytearray': , 'bytes': , 'classmethod': , 'complex': , 'dict': , 'enumerate': , 'filter': , 'float': , 'frozenset': , 'property': , 'int': , 'list': , 'map': , 'object': , 'range': , 'reversed': , 'set': , 'slice': , 'staticmethod': , 'str': , 'super': , 'tuple': , 'type': , 'zip': , '__debug__': True, 'BaseException': , 'Exception': , 'TypeError': , 'StopAsyncIteration': , 'StopIteration': , 'GeneratorExit': , 'SystemExit': , 'KeyboardInterrupt': , 'ImportError': , 'ModuleNotFoundError': , 'OSError': , 'EnvironmentError': , 'IOError': , 'WindowsError': , 'EOFError': , 'RuntimeError': , 'RecursionError': , 'NotImplementedError': , 'NameError': , 'UnboundLocalError': , 'AttributeError': , 'SyntaxError': , 'IndentationError': , 'TabError': , 'LookupError': , 'IndexError': , 'KeyError': , 'ValueError': , 'UnicodeError': , 'UnicodeEncodeError': , 'UnicodeDecodeError': , 'UnicodeTranslateError': , 'AssertionError': , 'ArithmeticError': , 'FloatingPointError': , 'OverflowError': , 'ZeroDivisionError': , 'SystemError': , 'ReferenceError': , 'BufferError': , 'MemoryError': , 'Warning': , 'UserWarning': , 'DeprecationWarning': , 'PendingDeprecationWarning': , 'SyntaxWarning': , 'RuntimeWarning': , 'FutureWarning': , 'ImportWarning': , 'UnicodeWarning': , 'BytesWarning': , 'ResourceWarning': , 'ConnectionError': , 'BlockingIOError': , 'BrokenPipeError': , 'ChildProcessError': , 'ConnectionAbortedError': , 'ConnectionRefusedError': , 'ConnectionResetError': , 'FileExistsError': , 'FileNotFoundError': , 'IsADirectoryError': , 'NotADirectoryError': , 'InterruptedError': , 'PermissionError': , 'ProcessLookupError': , 'TimeoutError': , 'open': , 'quit': Use quit() or Ctrl-Z plus Return to exit, 'exit': Use exit() or Ctrl-Z plus Return to exit, 'copyright': Copyright (c) 2001-2017 Python Software Foundation.
# All Rights Reserved. ...

# 访问名字的底层
print(Fn.__dict__['__module__'])  # __main__
# 访问名字的语法优化
print(Fn.__module__)  # __main__
# 总结:对象.名字 本质 对象.__dict__['名字']


# 赋值
fn.name = '我写的函数'
print(fn.__dict__)  # {'name': '我写的函数'}
print(fn.__dict__['name']) # 我写的函数
print(fn.name) # 我写的函数

# 了解:对象的名称空间,与对象内部的名称空间不是同一个
print('========================================')
def func():
    a = 10
    b = 20
    print(locals()) # {'b': 20, 'a': 10}
func()
print(func.__dict__)  # {}

# 记住:
# 对象.名字 = 值 是为该对象添加一个名称空间的名字,
# 也只能通过 对象.名字 来使用
func.name = 'func function'
print(func.name) # func function
View Code
# 可以产生名称空间的语法

def fn():  # 具有名称空间:fn.__dict__
    pass

class Fn():  # 具有名称空间:Fn.__dict__
    pass

import md  # 具有名称空间:md.__dict__


# 名称空间如何为一个名字设置值,或访问一个名字对应的值
fn.__dict__[名字] = 值  # 设置值
print(fn.__dict__[名字])  # 取值


# 重点:名称空间取值赋值的语法优化:点语法
fn.名字 = 值  # 设置值
print(fn.名字)  # 取值

四、类与对象的声明

class People:
    name = ''
    
p1 = People()
p2 = People()

# 结论1:类与每一个对象的名称空间都是独立的
print(p1.__dict__)  # {}
print(p2.__dict__)  # {}
print(People.__dict__)  # {'name': '人', ...系统的}

# 结论2:类与每一个对象都可以使用类中的名字
print(People.name)  #
print(p1.name)  #
print(p2.name)  #

# 结论3:对象访问名字,优先访问自己的,自己没有再访问类的
p1.name = '张三'
p2.user = '李四'
print(People.name)  #
print(p1.name)  # 张三
print(p2.user)  # 李四
print(p2.name)  #

# 重点:
# 对象操作名字,操作的是对象的,类操作名字操作的是类的,之间相互不干预
# 类只能访问类的名字
# 对象访问名字,优先访问自身的,自身没有再访问类的

五、类的初始化方法

# 可以快速为类实例化出的每一个对象,产生对象名称空间中的多个名字

class NewTeacher:
    def __init__(self, name, sex, age):
        # print(id(self))  # self就是实例化产生的对象(nt1)
        # print('init 被调用了')
        self.name = name
        self.sex = sex
        self.age = age
    pass

# 类()就是在调用类的__init__方法
nt1 = NewTeacher('王大锤', '', 58)
# print(id(nt1))
print(nt1.name, nt1.sex, nt1.age)


nt2 = NewTeacher('王小锤', '', 48)
print(nt2.name, nt2.sex, nt2.age)

演化:

class Teacher:
    name = '教授'

def set_obj(obj, name, sex, age):
    obj.name = name
    obj.sex = sex
    obj.age = age

t1 = Teacher()
# t1.name = 'C老师'
# t1.sex = "女"
# t1.age = 36
set_obj(t1, 'C老师', "", 36)
print(t1.name, t1.sex, t1.age)

t2 = Teacher()  # 类()应该就是函数的调用,函数调用可以传参,能优化属性的赋值
# t2.name = 'W老师'
# t2.sex = "女"
# t2.age = 28
set_obj(t2, 'W老师', "", 28)
print(t2.name, t2.sex, t2.age)

# t3 = Teacher()
# set_obj(t3, '王大锤', '男', 58)

# 能不能再优化 => t3 = Teacher('王大锤', '男', 58)
# print(t3.name, t3.sex, t3.age)
例子

六、类的方法分类

# 对象方法:直接定义的方法,建议由对象调用,类中内部需要使用对象的数据时的方法要定义为对象方法
# 1.对象方法对象调用,默认传入对象给第一个形参 
class 类名:
    def fn(self, *args, **kwargs): pass

# 类方法:被classmethod修饰的方法,建议由类调用,类中内部需要使用类的数据时的方法要定义为类方法
# 2.类方法由类调用,默认传入类给第一个形参
class 类名:
    @classmethod
    def fn(cls, *args, **kwargs): pass

# 静态方法:被staticmethod修饰的方法,建议由类调用,类中内部不需要类相关数据时的方法要定义为静态方法
# 3.静态方法建议由类调用,默认不传入调用者
    @staticmethod
    def fn(*args, **kwargs): pass

案例1:

class Student:
    name = '学生'
    def __init__(self, name, id_num):
        self.name = name
        self.id_num = id_num

    # 对象(成员)方法
    def study(self):  # 在类中产生的所有方法,都是属于类的,但是对象可以调用
        # print('self>>', id(self))
        print("%s在学习" % self.name)

    # 类方法: 第一个参数就是用来接收调用者,类方法的调用者一定是类,所以第一个参数命名约定为cls
    @classmethod
    def fn(cls):
        print(id(cls))


    # 静态方法
    @staticmethod
    def func():
        print('func run')

stu1 = Student('Bob', 1)
print(stu1.__dict__)  # {'name': 'Bob', 'id_num': 1}
print(stu1.name) # Bob
# stu1.__dict__.clear()  # 清空stu1
# print(stu1.__dict__)  # {}
# print(stu1.name) # 学生

print("====================")
stu2 = Student('Tom', 2)
stu1.study() # Bob在学习
print(id(stu1)) # 32140984
stu2.study() # Tom在学习
print(id(stu2)) #
print("====================")
# 结论1:对象调用类中的方法,默认隐式将对象自身传入,在方法中,第一个参数用self来接受传入的对象
# Student.fn(Student) => Student.fn()
# print(id(Student))

Student.fn() # 41758904
print(id(Student)) # 41758904

# 结论2:类中用@classmethod装饰的方法,是类方法,用类来调用,默认会将类传入给方法的第一个参数

print("====================")
Student.func() # func run
stu1.func() # func run
# 结论3:类中用@staticmethod装饰的方法,是静态方法,可以被类和对象调用,默认不会将类或对象传入
View Code

案例二:类的不同方法应用

# 案例
class Book:
    name = ''
    def __init__(self, name, price):
        self.name = name
        self.price = price

    # 书的详情信息 => 一定需要知道哪本书
    # @classmethod  # 类调用cls就是类,对象调用处理成 对象.__class__

    def detail(self):
        # print(cls.name)
        print("%s的价格为:%s元" % (self.name, self.price))

book1 = Book('西游记', 38.8)
book2 = Book('三国', 88.8)
book1.detail()
book2.detail()
# print(book1.__class__)


# 静态方法:方法的内部不需要对象及类的参与,所以定义为静态方法,但是方法必须由调用者,建议用类就可以了
class NumTool:  # 工具类 => 模块
    def max_two(self, n1, n2):
        max_num = n1 if n1 > n2 else n2
        print('大数是%s' % max_num)

    @staticmethod
    def new_max_two(n1, n2):
        max_num = n1 if n1 > n2 else n2
        print('大数是%s' % max_num)

n1 = NumTool()
n2 = NumTool()
n1.max_two(10, 20)
n2.max_two(10, 20)

NumTool.new_max_two(10, 20)
n1.new_max_two(10, 20)


# 类方法:方法的内部需要类的参与,所以定义为类方法,第一个参数默认传类
class NewNumTool:
    PI = 3.14

    @classmethod
    def new_max_two(cls, n1, n2):
        max_num = n1 if n1 > n2 else n2
        return max_num

    @classmethod
    def new_max_three(cls, n1, n2, n3):
        # max_num = "想去复用new_max_two"
        max_num = cls.new_max_two(n1, n2)
        max_num = cls.new_max_two(max_num, n3)
        return max_num

    @classmethod
    def is_PI(cls, num):
        if num == cls.PI:
            return True
        return False


res = NewNumTool.new_max_three(1, 5, 3)
print('大数是%s' % res)

print(NewNumTool.is_PI(3.149))
View Code

 七、封装

# 什么是封装:将类的一下属性和方法对外隐藏,对内可见
# 为什么要封装:为属性和方法的操作添加权限,具体权限都是通过自定义逻辑来处理

# 封装的手段:在类属性方法,对象属性方法,静态方法名字前添加 __
# 只要是通过 __名字 这种命名规范,就是对外隐藏
    # 本质:__名字 封装隐藏变量的本质是 将名字修饰成 _类名__名字

# 对外解决封装的方式
# 1.如果真的不想让外界访问,就不对外提供访问数据的方法
# 2.如果想让外界访问,可以对外提供访问数据的方法,方法具有逻辑,使用可以添加操作权限
class Test:
    def __init__(self, name):
        # __name只是对外隐藏,对内可见
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self, name):
        if 'sb' not in name:  # 对数据的修改可能会产生数据的安全性问题,可以添加限制条件
            self.__name = name
# 重点:封装的对外访问语法的优化
class User:
    def __init__(self, name):
        self.__name = name

    @property  # 将方法伪装成属性
    def name(self):
        return self.__name

    @name.setter  # 能为有伪装get方法的(方法)属性,再伪装set方法
    def name(self, value):
        self.__name = value

    @name.deleter
    def name(self):
        del self.__name
        
    # 总结:
    # 1.对象没了,对象的属性也就没了,所以不需要属性 @名字.deleter
    # 2.对外提供get方法是基础,@property,如果没有,外界不可读不可写
    # 3.如果有@property,则可以 @名字.setter,有set,为可读可写,无set为只读

    @property  # 伪装的属性方法,不需要一定有 __开头 的名字与之对应
    def pwd(self):
        return '123456'

u1 = User('Owen')
print(u1.name)  # 如果一个方法伪装成属性,对象.方法名 就会自动调用该方法

u1.name = 'Zero'
print(u1.name)

# del u1.name
# print(u1.name)

print(u1.pwd)

#@property 将方法伪装成属性,从而可以像__init__里的属性一样调用u1.name

 八、类的继承

什么是继承
    继承是一种新建类的方式,继承的类称之为子类或派生类
    被继承的类称之为父类或基类或超类
    子类继承父类,也就意味着子类继承了父类所有的属性和方法
    可以直接调用
为什么要有继承
    减少代码冗余
如何使用
class Parent1:
    pass
class Parent2:
    pass
class Son1(Parent1):
    pass
# python中支持多继承
class Son2(Parent1,Parent2):
    pass
# 如何查看类的父类
print(Son1.__bases__) # (,)
print(Son2.__bases__) # (, )
# 自定义的没有显示继承任何类的父类到底有没有偷偷继承某个类呢?
print(Parent1.__bases__) # (,)
print(Parent2.__bases__) # (,)
# python2:类如果没有显示继承任何类的情况下,不继承任何类
# python3:类如果没有显示继承任何类的情况下,默认都继承object类

经典类与新式类
   经典类:
        不继承object或者其子类的类  叫经典类  
   新式类: 
        继承object或者其子类的类    叫新式类
# ps:经典类与新式类只在python2有区分
#python3中只有新式类

派生:

# 派生:在继承了父类的属性和方法的基础之上 自己定义了其他的属性和方法
# 如果派生出的方法与父类的同名了 那么相当于覆盖了父类的方法

# 类:一系列对象相似的特征与技能的结合体
# 类与类之间相似的特征与技能的结合体  >>> 父类
# 类:一系列对象相似的特征与技能的结合体
# 类与类之间相似的特征与技能的结合体  >>> 父类
import pickle
class OldboyPeople:
    school = 'oldboy'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def save(self):
        with open(self.name,'wb') as f:
            pickle.dump(self,f)

class OldboyStudent(OldboyPeople):
    def choose_course(self):
        print('%s is choosing course'%self.name)


class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,gender,level):
        OldboyPeople.__init__(self,name,age,gender)
        self.level = level

    def score(self):
        print('%s is score'%self.name)

stu = OldboyStudent('simon',18,'male')
print(stu.name) # simon
stu.save() # 创建文件存数据

tea = OldboyTeacher('xc',18,'male',10)
print(tea.name) # simon
tea.save()

子类方法中调用父类的方法:

 # 方法一:指名道姓
# OldboyPeople.__init__(self,name,age,gender)   跟继承一点关系都没有

# 方法二:和继承有关系
# 单继承情况下的属性查找
class B:
    def f1(self):
        print('from B f1')

    def f2(self):
        print('from B f2')
        self.f1()
class A(B):
    def f1(self):
        print('from A f1')
obj = A()
obj.f2()
"""
from B f2
from A f1
"""
# 上面的例子可以看出:类是查找顺序是先查找自己,再查找父类

# 多继承
# 无论是python2还是python3继承都遵循深度优先(菱型继承除外)
# 深度优先:依次先从左边分支查找完后向右查找
# # 多继承
class D:
    # def test(self):
    #     print('D')
    pass
class E:
    def test(self):
        print('E')
class F:
    def test(self):
        print('F')
class A(D):
    # def test(self):
    #     print('A')
    pass
class B(E):
    # def test(self):
    #     print('B')
    pass
class C(F):
    def test(self):
        print('C')
class G(A,B,C):
    # def test(self):
    #     print('G')
    pass

obj = G()
obj.test() # E
View Code
# 调用方式
import pickle
class OldboyPeople:
    school = 'oldboy'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
    def save(self):
        with open(self.name,'wb') as f:
            pickle.dump(self,f)


class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,gender,level):
        # OldboyPeople.__init__(self,name,age,gender)
        # super(OldboyTeacher,self).__init__(name,age,gender)
        super().__init__(name,age,gender) # 调用
        self.level = level
tea = OldboyTeacher('ymc',18,'male',10)
print(tea.name) # ymc
tea.save()

MRO列表,C3算法

# mro列表   C3算法
class D:
    pass
class E:
    pass
class F:
    pass
class A(D):
    pass
class B(E):
    pass
class C(F):
    pass
class G(A,B,C):
    pass

print(G.mro()) """ G A D B E C F [, , , , , , , ] """
# super是严格按照mro列表的顺序调用父类的方法的!!!
class A:
    def f1(self):
        print('from a f1')
    def f2(self):
        print('from a f2')
        super().f1()
class B:
    def f1(self):
        print('from b f1')
    def f2(self):
        print('from b f2')
class C(A,B):
    def f1(self):
        print('from c f1')
print(C.mro())
# [, , , ]
obj = C()
obj.f2()
"""
from a f2
from b f1
"""

九、多态与多态性

# 什么是多态
    一种事物的不同形态(动物:人,狗,猫),代码层面上来说其实就是继承      
# 为什么要有多态
    多态仅仅是一个概念
# 多态性:在不需要考虑对象具体类型的情况下 调用对象的方法    
# 如何使用
class Animal:
    def talk(self):
        pass
class People(Animal):
    def talk(self):
        print('hello')
class Dog(Animal):
    def talk(self):
        print('wangwang')
class Cat(Animal):
    def talk(self):
        print('miaomiao')
people = People()
dog = Dog()
cat = Cat()

people.talk()
dog.talk()
cat.talk()

# 例如:len获取长度

十、反射

# 通过字符串来操作对象的属性或方法
# 通过字符串来操作对象的属性或方法
class User:
    school = 'oldgirl'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def func(self):
        print('func')

# hasattr判断对象是否有某个属性或方法
print(User.school) # oldgirl
print('school' in User.__dict__) # True
print('xxx' in User.__dict__) # False
print(hasattr(User,'school')) # True
print(hasattr(User,'xxx')) # False
print(hasattr(User,'func')) # True
print('func' in User.__dict__) # True
d = {'name':"jason"}
print(d.get('password','hahahahahaha'))  # hahahahahaha

# getattr 取类中的属性或方法
print(getattr(User,'school')) # oldgirl
print(getattr(User,'func')) # 
print(User.__dict__['school']) # oldgirl
print(User.__dict__['func']) # 
# print(getattr(User,'xxx')) # 获取没有的报错
if hasattr(User,'xxx'):
    getattr(User,'xxx')

# setattr
obj = User('simon',18)
setattr(obj,'gender','male')  # obj.gender = 'male'
print(obj.__dict__)

# delattr
delattr(User,'school')
print(User.__dict__)

十一、内置方法

 

class User:
    def __init__(self,name,password):
        self.name = name
        self.password = password

    def __str__(self):
        # return '%s:%s'%(self.name,self.password)
        return '我被打印了,自动触发'

    def __getattr__(self, item):
        print(item)

    def __setattr__(self, key, value):
        print(key,value)

# __str__对象被执行了打印操作  自动触发
obj = User('simon',123)
print(User)
print(obj)
"""
name simon
password 123

我被打印了,自动触发
"""

# __getattr__ 当对象获取一个不存在的属性时候才会触发
obj = User('simon',18)
print(obj.name)
"""
name simon
password 18
name
None
"""

# __setattr__: obj.name = 'xxx'  固定句式
obj = User('simon',18)
obj.sex = 'sexy'
"""
name simon
password 18
sex sexy
"""

class Demo(dict):
    def __getattr__(self, item):
        return self.get(item)
d = Demo(name='simon',password=123)
print(d.name) # simon
print(d.password) # 123

作业一:

1.自定义一个 Fruit 类:该类有一个 类属性: identify:值为"水果",有两个对象属性: name,price:值由实例化对象时赋值,
一个类方法: get_identify:打印类属性identify的值,
一个对象方法:get_total_price(num):打印『%s个%s值%s钱』,
一个静态方法:packing(*fruits) 静态方法(装箱)的思路分析 red_apple = Fruit("红苹果", 10) green_apple = Fruit("青苹果", 10) yellow_banana = Fruit("黄香蕉", 8) 调用:Frulit.packing(red_apple, green_apple, yellow_banana) 打印:一箱装了2个苹果1个香蕉 2.自定义一个 Person 类,该类具有 name、weight、height、sex 四个对象属性, -- 对name属性进行封装,但是外界任然可以访问name以及设置name -- 有一个方法属性bmi(标准体重),可以获取一个人的bmi,bmi只读不可写,bmi计算规则 -- 男:(身高cm-80)× 70﹪ | 女:(身高cm-70)× 60﹪ 提示:类属性就是直接写在类中的变量,对象属性就是写在__init__方法中的用self.属性 = 值 赋值的属性,方法属性就是用 @property 修饰的方法伪装成的属性 4.用面向对象实现 植物大战僵尸游戏 1).定义一个僵尸Zombie类,该类可以实例化出多种僵尸对象,僵尸对象产生默认都有 名字name、血量HP、防具armor -- 名字:普通僵尸 | 路障僵尸 | 铁桶僵尸 -- 血量:默认就是100,不需要外界提供 -- 防具:不需要外界提供,从名字中分析确定,防具的值是一个列表,从名字分析得到 -- ['', 0] | ['路障', 5] | ['铁桶', 15] => [防具名, 防具的防御值] -- 通过@property的getter、setter方式,对外提供防具的两个访问接口armor_name与armor_count -- armor_name可以取值、赋值、删除值:通过一个 -- eg: 普通僵尸对象.armor_name = '铁桶',不仅改变了防具名 -- 普通僵尸对象的名字name也会变成 铁桶僵尸 -- armor_count只可以取值 2).定义一个角色User类,该类有名字name属性、以及打僵尸的beat方法 -- 名字:随意自定义 -- beat:该方法需要传入一个僵尸对象 -- 在方法内部可以实现:某某用户攻击了某某个僵尸,僵尸损失多少血,还剩多少血 -- 每一次攻击,都固定扣除25滴血,但是不同的僵尸会被防具相应抵消掉一定的伤害值 -- 循环攻击僵尸,3s攻击一次,僵尸被击杀后,打印 某某用户击杀了某某个僵尸 并结束方法 3).定义一个Game类,该类有一个name属性,属性值为 "植物大战僵尸" ,该类中有一个start方法,通过Game.start()来启动游戏 -- 游戏一开始先显示游戏的名字 植物大战僵尸游戏 -- 会随机产生三种僵尸,总共产生三个作为要被击杀的对象 -- 生成一个有角色名的角色,依次去击杀随机产生的每一只僵尸 -- 开始击杀第一只僵尸 => 某某用户攻击了某某个僵尸,僵尸损失多少血,还剩多少血 => 某某用户击杀了某某个僵尸 => 第一只僵尸已被击杀完毕 => 开始击杀第二只僵尸 ... => 第三只僵尸已被击杀完毕

作业二:

角色:学校、学员、课程、讲师
要求:
1. 创建北京、上海 2 所学校---学校
2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开 ----课程、地点
3. 课程包含,周期,价格,通过学校创建课程-----时间、价格、
4. 通过学校创建班级, 班级关联课程、讲师---班级、课程、讲师
5. 创建学员时,选择学校,关联班级 ---学员、学校、班级
5. 创建讲师角色时要关联学校,---讲师、学校
6. 提供两个角色接口
6.1 学员视图, 可以注册, 交学费, 选择班级,---》注册、学费、班级
6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
6.3 管理视图,创建讲师, 创建班级,创建课程
7. 上面的操作产生的数据都通过pickle序列化保存到文件里

转载于:https://www.cnblogs.com/yangmeichong/p/10893732.html

你可能感兴趣的:(python_面向对象编程)