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__)
# <function fn at 0x0000000001CF2EA0> {}

print(Fn, Fn.__dict__)
# <class '__main__.Fn'> {'__module__': '__main__', 'a_fn': <function Fn.a_fn at 0x0000000002947048>, '__dict__': <attribute '__dict__' of 'Fn' objects>, '__weakref__': <attribute '__weakref__' of 'Fn' objects>, '__doc__': None}

print(md, md.__dict__)
#<module 'md' from 'F:\安装包\JetBrains\JetBrains\Projects\09\代码\part2\md.py'> {'__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.

Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>), '__build_class__': <built-in function __build_class__>, '__import__': <built-in function __import__>, 'abs': <built-in function abs>, 'all': <built-in function all>, 'any': <built-in function any>, 'ascii': <built-in function ascii>, 'bin': <built-in function bin>, 'callable': <built-in function callable>, 'chr': <built-in function chr>, 'compile': <built-in function compile>, 'delattr': <built-in function delattr>, 'dir': <built-in function dir>, 'divmod': <built-in function divmod>, 'eval': <built-in function eval>, 'exec': <built-in function exec>, 'format': <built-in function format>, 'getattr': <built-in function getattr>, 'globals': <built-in function globals>, 'hasattr': <built-in function hasattr>, 'hash': <built-in function hash>, 'hex': <built-in function hex>, 'id': <built-in function id>, 'input': <built-in function input>, 'isinstance': <built-in function isinstance>, 'issubclass': <built-in function issubclass>, 'iter': <built-in function iter>, 'len': <built-in function len>, 'locals': <built-in function locals>, 'max': <built-in function max>, 'min': <built-in function min>, 'next': <built-in function next>, 'oct': <built-in function oct>, 'ord': <built-in function ord>, 'pow': <built-in function pow>, 'print': <built-in function print>, 'repr': <built-in function repr>, 'round': <built-in function round>, 'setattr': <built-in function setattr>, 'sorted': <built-in function sorted>, 'sum': <built-in function sum>, 'vars': <built-in function vars>, 'None': None, 'Ellipsis': Ellipsis, 'NotImplemented': NotImplemented, 'False': False, 'True': True, 'bool': <class 'bool'>, 'memoryview': <class 'memoryview'>, 'bytearray': <class 'bytearray'>, 'bytes': <class 'bytes'>, 'classmethod': <class 'classmethod'>, 'complex': <class 'complex'>, 'dict': <class 'dict'>, 'enumerate': <class 'enumerate'>, 'filter': <class 'filter'>, 'float': <class 'float'>, 'frozenset': <class 'frozenset'>, 'property': <class 'property'>, 'int': <class 'int'>, 'list': <class 'list'>, 'map': <class 'map'>, 'object': <class 'object'>, 'range': <class 'range'>, 'reversed': <class 'reversed'>, 'set': <class 'set'>, 'slice': <class 'slice'>, 'staticmethod': <class 'staticmethod'>, 'str': <class 'str'>, 'super': <class 'super'>, 'tuple': <class 'tuple'>, 'type': <class 'type'>, 'zip': <class 'zip'>, '__debug__': True, 'BaseException': <class 'BaseException'>, 'Exception': <class 'Exception'>, 'TypeError': <class 'TypeError'>, 'StopAsyncIteration': <class 'StopAsyncIteration'>, 'StopIteration': <class 'StopIteration'>, 'GeneratorExit': <class 'GeneratorExit'>, 'SystemExit': <class 'SystemExit'>, 'KeyboardInterrupt': <class 'KeyboardInterrupt'>, 'ImportError': <class 'ImportError'>, 'ModuleNotFoundError': <class 'ModuleNotFoundError'>, 'OSError': <class 'OSError'>, 'EnvironmentError': <class 'OSError'>, 'IOError': <class 'OSError'>, 'WindowsError': <class 'OSError'>, 'EOFError': <class 'EOFError'>, 'RuntimeError': <class 'RuntimeError'>, 'RecursionError': <class 'RecursionError'>, 'NotImplementedError': <class 'NotImplementedError'>, 'NameError': <class 'NameError'>, 'UnboundLocalError': <class 'UnboundLocalError'>, 'AttributeError': <class 'AttributeError'>, 'SyntaxError': <class 'SyntaxError'>, 'IndentationError': <class 'IndentationError'>, 'TabError': <class 'TabError'>, 'LookupError': <class 'LookupError'>, 'IndexError': <class 'IndexError'>, 'KeyError': <class 'KeyError'>, 'ValueError': <class 'ValueError'>, 'UnicodeError': <class 'UnicodeError'>, 'UnicodeEncodeError': <class 'UnicodeEncodeError'>, 'UnicodeDecodeError': <class 'UnicodeDecodeError'>, 'UnicodeTranslateError': <class 'UnicodeTranslateError'>, 'AssertionError': <class 'AssertionError'>, 'ArithmeticError': <class 'ArithmeticError'>, 'FloatingPointError': <class 'FloatingPointError'>, 'OverflowError': <class 'OverflowError'>, 'ZeroDivisionError': <class 'ZeroDivisionError'>, 'SystemError': <class 'SystemError'>, 'ReferenceError': <class 'ReferenceError'>, 'BufferError': <class 'BufferError'>, 'MemoryError': <class 'MemoryError'>, 'Warning': <class 'Warning'>, 'UserWarning': <class 'UserWarning'>, 'DeprecationWarning': <class 'DeprecationWarning'>, 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>, 'SyntaxWarning': <class 'SyntaxWarning'>, 'RuntimeWarning': <class 'RuntimeWarning'>, 'FutureWarning': <class 'FutureWarning'>, 'ImportWarning': <class 'ImportWarning'>, 'UnicodeWarning': <class 'UnicodeWarning'>, 'BytesWarning': <class 'BytesWarning'>, 'ResourceWarning': <class 'ResourceWarning'>, 'ConnectionError': <class 'ConnectionError'>, 'BlockingIOError': <class 'BlockingIOError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionAbortedError': <class 'ConnectionAbortedError'>, 'ConnectionRefusedError': <class 'ConnectionRefusedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'FileExistsError': <class 'FileExistsError'>, 'FileNotFoundError': <class 'FileNotFoundError'>, 'IsADirectoryError': <class 'IsADirectoryError'>, 'NotADirectoryError': <class 'NotADirectoryError'>, 'InterruptedError': <class 'InterruptedError'>, 'PermissionError': <class 'PermissionError'>, 'ProcessLookupError': <class 'ProcessLookupError'>, 'TimeoutError': <class 'TimeoutError'>, 'open': <built-in function 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__) # (<class '__main__.Parent1'>,)
print(Son2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
# 自定义的没有显示继承任何类的父类到底有没有偷偷继承某个类呢?
print(Parent1.__bases__) # (<class 'object'>,)
print(Parent2.__bases__) # (<class 'object'>,)
# 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 [<class '__main__.G'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class 'object'>] """
# 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())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
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')) # <function User.func at 0x00000000021F7048>
print(User.__dict__['school']) # oldgirl
print(User.__dict__['func']) # <function User.func at 0x00000000027D7048>
# 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
<class '__main__.User'>
我被打印了,自动触发
"""

# __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个课程 , linuxpy 在北京开, go 在上海开 ----课程、地点
3. 课程包含,周期,价格,通过学校创建课程-----时间、价格、
4. 通过学校创建班级, 班级关联课程、讲师---班级、课程、讲师
5. 创建学员时,选择学校,关联班级 ---学员、学校、班级
5. 创建讲师角色时要关联学校,---讲师、学校
6. 提供两个角色接口
6.1 学员视图, 可以注册, 交学费, 选择班级,---》注册、学费、班级
6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
6.3 管理视图,创建讲师, 创建班级,创建课程
7. 上面的操作产生的数据都通过pickle序列化保存到文件里
原文地址:https://www.cnblogs.com/yangmeichong/p/10893732.html