初识面向对象

面向对象总结

一,初识

class Person(object):
    # 类属性:静态属性 默认这个类所有对象都有的,不能更改的属性可以放在这里
    # 一般不用对象调用类属性,对象不能修改类属性,一旦修改:
    # 会在实例属性中新增被修改的类属性,将真实的类属性覆盖
    language = '语言'
    mind = '感情'
    def __init__(self,name,age,sex):
        # 实例属性
        # 可以用对象修改实例属性,只会修改这个对象自己的,对其他对象没影响
        # 如果在类内部修改实例属性,所有的对象的这个属性的值都会被修改
        self.name = name
        self.age = age
        self.sex = sex
    def eat(self):
        print('会吃饭')
    def run(self):
        print('会跑')

pp1 = Person('alex',83,'男')
pp2 = Person('baoyuan',18,'男')

一般不用对象调用类属性,对象不能修改类属性,一旦修改:
会在实例属性中新增被修改的类属性,将真实的类属性覆盖
pp1.mind = 'buqingchu'
print(pp1.mind) # buqingchu
print(pp1.__dict__) # {'name': 'alex', 'age': 83, 'sex': '男', 'mind': 'buqingchu'}

可以用对象修改实例属性,只会修改这个对象自己的,对其他对象没影响
pp1.name = 'ALEX'
print(pp1.name,pp2.name) # ALEX baoyuan

pp1.hooby = '女'
print(pp1.__dict__)
# {'name': 'ALEX', 'age': 83, 'sex': '男', 'hooby': '女'}
print(pp2.__dict__)
# {'name': 'b

二,类之间的关系

1.依赖关系/ 关联关系

  • 依赖关系也叫关联关系
  • 就是在一个类的方法中调用了另一个类的对象
  • 或者说:将一个类的对象放在另一个类的方法中
# 定义一个英雄类和一个反派类
# • 两个类都包含名字、血量,攻击力(ATK),和一个技能(skill)
# • 两派对象互殴
# • 血量为0死亡,删除对象(del 对象名)
class Hero:
    def __init__(self,name,hp,atk):
        self.name = name
        self.hp = hp
        self.atk = atk
    def skill(self,tool):
        print(f'{self.name}攻击了{tool.name}{self.atk}滴血')
        tool.hp = tool.hp - self.atk

class Fan:
    def __init__(self,name,hp,atk):
        self.name = name
        self.hp = hp
        self.atk = atk
    def skill(self, tool):
        print(f'{self.name}攻击了{tool.name}{self.atk}滴血')
        tool.hp = tool.hp - self.atk

baoyuan = Hero('宝哥哥',100,50)
alex = Fan('大烧饼',70,20)

while True:
    baoyuan.skill(alex)
    alex.skill(baoyuan)
    if alex.hp <= 0:
        del alex
        print('游戏结束')
        break
    if baoyuan.hp <= 0:
        del baoyuan
        print('游戏结束')
        break

2.组合关系

  • 将一个类的对象放在另一个类的属性中
class Boy:
    def __init__(self,name,girlFriend=None):
        self.name = name
        self.tool = girlFriend
    def dinner(self):
        if self.tool:
            print(f'{self.name}和{self.tool.name}共进晚餐')
        else:
            print('单身狗吃什么吃')

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

alex = Boy('alex')
tang = Girl('tang')
baoyuan = Boy('baoyuan',tang)

alex.dinner()
baoyuan.dinner()

3.继承关系--三大特性之一

  • 继承是在不改变现有类的情况下扩展这个类
  • 子类可以获得父类的全部属性和方法
  • 子类可以定义自己的方法,也可以定义和父类重名的方法(方法重写),这时子类方法会覆盖掉父类的同名方法,因此如果子类和父类都拥有自己的初始化方法,需要在子类的初始化方法中调用父类的init方法
  • 如果只是想操作另一个类的对象,用依赖
  • 如果两个类当中存在has a的关系,用组合
  • 如果两个类当中存在is a的关系,用继承(尽量少用继承,多用组合)
class Father:
    def livelikeyemen(self):
        print('打妈妈')

class Son(Father):
    def abc(self):
        print(123)
    # 父类方法重写
    def livelikeyemen(self):
        print('打妹妹')
class Animal:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def run(self):
        print('会跑')

class Dog(Animal):
    # 如果子类也有自己的初始化方法会报错
    # 解决方式:在子类的init方法里面,调用父类的init方法
    def __init__(self,name,age):
        self.kengutou = False
        Animal.__init__(self,name,age)
        # 也可以写成:super().__init__()
    def jump(self):
        print('会跳')

class Cat(Animal):
    def __init__(self):
        self.xihuanyu = True
    def jiao(self):
        print('喵喵')

anm = Animal('动物',18)
gg = Dog('小黑',11)
print(gg.name,gg.age)
cc = Cat()

三,三大特性

1.封装

a.概念

  • 封装就是将抽象得到的数据和行为相结合形成一个整体
  • 封装就是将复杂的事物封装成一个整体,对外只有简单的接口
  • 目的:简化编程,增强安全性,明确区分内外

b.私有属性和私有方法

  • 在类的属性和方法名字前面加上两个下划线,就变成私有属性和方法
  • 在类的外部不能直接调用私有属性和私有方法,子类也不能访问
  • 可以提供外部访问的接口
  • 私有属性和私有方法在继承给子类时,子类是无法覆盖的
  • 破解方法(一般不用):在名字前面加上一个下划线+类名(如:a._A__N) ; 因为在底层代码中就是按上述命名的,所以可以这样破解
class Animal:
    def __init__(self):
        self.__name = '动物'
        self.__age = '18'

    def get_name(self):
        return '宠物'

    def get_age(self,num):
        if isinstance(num,int):
            if 0 < num < 200:
                return num

class Dog(Animal):
    pass

dog = Animal()
print(dog.get_name())
print(dog.get_age(188))

2.多态

a.多态概念

  • 体现1:一类事物可以有多种形态
  • 体现2:python中一个引用可以指向不同数据类型
class Bird:
    def move(self,field):
        print(f'鸟在{field}自由地飞翔')
class Dog:
    def move(self,field):
        print(f'狗在{field}飞快地奔跑')
b = Bird()
b.move('天空')
d = Dog()
d.move('草地')

b.多态性概念

  • 不同类的对象作为同一个外部函数的参数时得到不同的结果
  • 在多态的基础上定义统一的接口,就是在类外部单独定义一个函数
  • 在继承和方法重写的基础上,定义统一的接口,不关心传入对象的类型,只关心实现了哪些方法
# 继承+方法重写+类外部统一接口
class Car:
    def __init__(self,color):
        self.color = color
    def run(self):
        print(f"{self.color}汽车在跑")

class Cat(Car):
    def run(self):
        print(f"{self.color}小猫在跑")

def run(tool):
    tool.run()

car = Car('红色')
cat = Cat('红色')
run(car)
run(cat)

c.鸭子类型

  • python很崇尚鸭子类型
  • 和多态性很类似,但是不需要继承和方法重写
class Car():

    def __init__(self,color):
        self.color = color
    def run(self):
        print(f'{self.color}的小汽车在跑')

class Cat():

    def __init__(self,name):
        self.name = name
    def run(self):
        print(f'猫咪{self.name}在跑')

qiche = Car('红色')
maomi = Cat('小猫咪')

def run(tools):
    tools.run()

run(qiche)
run(maomi)

四,设计模式

  • 在处理问题时使用的可重用的解决方法

1.单例模式

  • 一个类只能创建一个对象的就是单例
  • 不管创建多少对象,都是同一个
  • 作用:比如闯关游戏,每一关都由不同的程序员制作,如果是非单例的,每个人创建的对象都是一个新的,那就造成:每打完一个关卡获得的经验值,金币或者更新的装备,到下一关就都变成初始值了;如果是单例模式,第一关创建的对象经过一个关卡的升级,这些数值到下一关还存在
class Person(object):
    ins = None
    # 创建对象时,为新对象开辟空间这些都是双下new做的,双下init其实就是把属性赋值而已
    def __new__(cls,*args,**kwargs):
        if not cls.ins:
            cls.ins = object.__new__(cls)
        return cls.ins
alex = Person()
baoyuan = Person()
# 这个类的意思就是,重写object的双下new方法:如果创建对象时看看ins有没有值,如果有就用已经有的;如果没有就执行object的双下new(这个就跟没重写一样).
# 1. 创建alex这个对象时调用双下new方法,"if not cls.ins:"这个判断可以理解为"if cls.ins = None:";
# 2. 第一次创建对象时cls.ins肯定是None,然后执行cls.ins=object.__new__(cls)就是运行object的双下new方法(结果就是创建一个新的对象空间)然后将结果赋值给cls.ins;最后将cls.ins的值return给调用双下new的地方
# 3. 如果创建对象时cls.ins有值,就直接将cls.ins的值return给调用双下new的地方
# 这样就保证了不管创建多少对象,都是同一个对象


# 注意if下面两种写法的不同:

# 此时不管if成立与否都必须return
if cls.ins == None:
    cls.ins = object.__new__(cls)
return cls.ins

# 此时只有if不成立时才return
if cls.ins == None:
    cls.ins = object.__new__(cls)
else:
    return cls.ins

2.工厂模式

class Cat:
    pass
class Dog:
    pass

class Gongchang:
    def choice(self,arg):
        if arg == 'C':
            return Cat()
        if arg == 'D':
            return Dog()
        print('错误')

五,约束

  • 约束指的是对类的约束,规定在类中必须实现哪些方法

1.方式一: 提取父类并在父类中抛出异常

class QQpay:
    def pay(self):
        pass
class Zhifubao:
    def pay(self):
        pass
class Weixin:
    def zhifu(self):
        pass
wx = Weixin()
def jiekou(tool):
    tool.pay()
jiekou(wx) # 报错
# 因为接口中叫pay(),所以类中方法名字要相同
# 提取父类,在父类的方法中设置抛出异常
class Father:
    def pay(self):
        raise Exception('听话,别闹!!!')
class QQpay(Father):
    def pay(self):
        print('qq支付')
class Zhifubao(Father):
    def pay(self):
        print('支付宝支付')
class Weinxin(Father):
    def zhifu(self):
        print('微信支付')
def jiekou(tool):
    tool.pay()
qq = QQpay()
zfb = Zhifubao()
wx = Weinxin()
jiekou(wx)  # 执行时抛出异常.
# 执行时,先执行wx.pay(),pay()方法在Weixin类中没有,就去父类找,
# 执行父类的pay()方法时,直接抛出异常

2.方式二: 定义抽象类

  • 类都是继承于object
  • 类都是由元类(metaclass)创造的. mataclass默认值是Type(普通类的元类),把抽象类的元类ABCMeta的值赋给metaclass,就能创造抽象类
# 定义抽象类,抽象类中的方法都pass,
# 但是继承这个抽象类的类都必须实现,起到约束作用
from abc import ABCMeta,abstractmethod
class Aaa(metaclass=ABCMeta):
    @abstractmethod
    def abc(self):
        pass
    @abstractmethod
    def dfg(self):
        pass

# 下面定义一个类继承上面的抽象类
# 抽象类中的方法都要在此类中实现,有一个不实现就报错
class Bbb(Aaa):
    def abc(self):
        print('123')
bb = Bbb() # TypeError: Can't instantiate abstract class Bbb with abstract methods dfg

六,特殊方法

1.@classmethod类方法

  • 一个类通过@classmethod修饰的方法
  • 类方法就是将类本身作为对象进行操作的方法
  • 第一个参数必须是当前类对象,该参数名约定为cls,通过cls来传递类的属性和方法(不能传递实例的属性和方法)
  • 实例对象和类对象都可以调用(类对象就是类,因为万物皆对象),但是推荐使用类名调用,因为这个方法是属于类的
  • self和cls只能在类内使用,在类外无效
  • 实例方法:对象调用,类名不建议调用
  • 实例属性:对象调用,类名不能调用
  • 类方法:通过类名调用,对象也可以调用,但是不建议
  • 类属性:通过类名调用,对象也可以调用,但是不建议
class Student:
    __num = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
        Student.set_num()
    
    @classmethod
    def get_num(cls):
        return cls.__num
    @classmethod
    def set_num(cls):
        cls.__num += 1

2.@staticmethod静态方法

  • 使用@staticmethod修饰的方法
  • 就是在类中定义的一个普通函数
  • 当前类对于静态方法来说,只是相当于一个名称空间
  • 参数随意,没有self和cls参数,方法体中不能由类或实例的任何属性和方法
  • 实例对象和类对象都可以调用
  • 为了代码模块化,代码应该是由若干个类组成的,但是有时需要用一些函数,和任何类和对象都没有关系的普通函数,这些函数会破坏代码的模块化,这样设置静态方法,将这些函数放进类中,对类和这种函数也没有影响
class Student:
    __num = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
        Student.set_num()

    @classmethod
    def get_num(cls):
        return cls.__num
    @classmethod
    def set_num(cls):
        cls.__num += 1

    @staticmethod
    def aaa(a,b,c):
        # 这个就是一个普通函数,跟当前类和对象没有任何关系
        print('aaa')

a = Student()

Student.aaa()
a.aaa()
# 这两种调用方式都可以

3.@property

  • 将一个方法伪装成属性去调用
  • 用@property修饰方法
  • 一定现有property,才能有setter和deleter
  • 为了遵循同意访问的原则
class Square:
    def __init__(self,long,wide):
        self.long = long
        self.wide = wide
    def area(self):
        return self.long*self.wide

s = Square(10,20)
print(s.area()) 

# 上面的实现方法没问题,但是面积这一类比较习惯作为属性,所以可以用property

class Square:
    def __init__(self,long,wide):
        self.long = long
        self.wide = wide
    # 将一个方法伪装成属性
    @property
    def area(self):
        return self.long*self.wide

s = Square(10,20)
print(s.area) # s.area()会报错

# BMI
class Bmi:
    def __init__(self,tizhong,shengao):
        self.tizhong = tizhong
        self.shengao = shengao

    @property
    def bmi(self):
        return self.tizhong/self.shengao**2
bb = Bmi(65,1.82)
print(bb.bmi)
class Person:
    def __init__(self, age):
        self.__age = age

    @property
    def age(self):
        return self.__age # 把self.__age换成18试试

    @age.setter
    def age(self, num):
        if 0 < num < 100:
            self.__age = num

    # @age.deleter
    # def age(self):
    #     print('就不删除')

    @age.deleter
    def age(self):
        print('已删除')
        del self.__age

xiaoli = Person(10)
print(xiaoli.age)
xiaoli.age = 12
print(xiaoli.age)
del xiaoli.age
print(xiaoli.age)

# 只有@property定义只读,加上@setter定义可读可写,再加上@delter定义可读可写可删除

七,反射

  • 以字符串的形式操作对象的相关属性
  • 一切皆对象==>一切都可以用反射
class Girl:
    num = 0
    def __init__(self):
        self.name = 'alex'

    def run(self):
        print('人会跑')

xiaohong = Girl()
print(hasattr(xiaohong,'num'))
print(hasattr(xiaohong,'run'))

print(getattr(xiaohong,'name'))
print(getattr(xiaohong,'run')) # 内存地址
print(getattr(xiaohong,'name1','没有')) # 没有
print(getattr(xiaohong,'name','没有')) # alex

setattr(xiaohong,'name','baoyuan')
print(getattr(xiaohong,'name'))
例题:
# 当我们打开浏览器,访问一个网站,单击登录就跳转到登录界面,单击注册就跳转到注册界面
# 但是,你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理
class User:
    def login(self):
        print('登录页面')
    def register(self):
        print('注册页面')
    def save(self):
        print('存储页面')

# 不用反射的方法:
# while Ture:
#     choose = input('<<<').strip()
#     if choose == 'login':
#         uu = User()
#         uu.login()
#     elif choose == 'register':
#         uu = User()
#         uu.register()
#     elif choose == 'save':
#         uu = User()
#         uu.save()

# 反射方法:
uu = User()
while True:
    choose = input('<<<').strip()
    if hasattr(uu,choose):
        func = getattr(uu,choose)
        func()
    else:
        print('输入错误')

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

    def func(self):
        print(111)

pp = Person('alex',83)
# 1.
# hasattr(对象名,'属性')===>判断该对象是不是有该属性
print(hasattr(pp,'name'))

# 2.
# getattr(对象名,'属性',[默认值])===>获取该对象的该属性的值(相当于 查)
# 默认值可写可不写:如果该对象有该属性,则可以print出来.
#               如果没有,显示默认值,不写默认值则报错
print(getattr(pp,'name'))
print(getattr(pp,'sex','没有'))
# print(pp.sex)

# 3.
# setattr(对象名,'属性',值)===>设置该对象的该属性的值(相当于 改)
# 如果该对象有该属性,则修改成后面的值;如果没有,就增加该属性,该属性的值就是后面的值
setattr(pp,'name','baoyuan')
print(pp.name)
setattr(pp,'sex','女')
print(pp.__dict__)
print(pp.sex)
print(getattr(pp,'sex','XX'))

# 4.
# delattr(对象名,'属性')===>删除该对象的该属性(相当于 删)
delattr(pp,'name')
# print(pp.name)

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

    def func(self):
        print(111)

pp = Person('alex',83)
# 1.
# hasattr(对象名,'属性')===>判断该对象是不是有该属性
# print(hasattr(pp,'name'))

# 2.
# getattr(对象名,'属性',[默认值])===>获取该对象的该属性的值(相当于 查)
# 默认值可写可不写:如果该对象有该属性,则可以print出来.
#               如果没有,显示默认值,不写默认值则报错
# print(getattr(pp,'name'))
# print(getattr(pp,'sex','没有'))
# print(pp.sex)

# 3.
# setattr(对象名,'属性',值)===>设置该对象的该属性的值(相当于 改)
# 如果该对象有该属性,则修改成后面的值;如果没有,就增加该属性,该属性的值就是后面的值
# setattr(pp,'name','baoyuan')
# print(pp.name)
# setattr(pp,'sex','女')
# print(pp.__dict__)
# print(pp.sex)
# print(getattr(pp,'sex','XX'))

# 4.
# delattr(对象名,'属性')===>删除该对象的该属性(相当于 查)
# delattr(pp,'name')
# print(pp.name)

八,异常

1.概念

  • Exception:是影响程序正常执行的一个事件.产生异常之后,程序会停止运行
  • 目的:捕获异常,这样不影响程序继续执行
  • 异常也是对象,有异常类:Exception
  • 常见的异常全部都是Exception(异常类)的子类

2.处理异常的方式

  • 处理方式一:通过算法来进行判断,有缺陷存在大量与业务逻辑无关的代码,导致代码量增大,重复代码增多

  • 处理方式二:

    try:
        需要进行一场检测的代码
    except 异常类的类名:
        捕获异常之后的处理方式
    else:
        如果try下面的子句没有产生异常,就执行else后面的内容
    finally:
        无论是否出现异常,是否正常捕获,都会执行(即使遇到return,break也会先执行)
    
try:
    num = 5/0
    print(345) # 不执行

except ZeroDivisionError:
    print('除数不能为0')


print('123')
# 异常处理可以捕获异常对象,然后做相应处理,让程序继续执行
# 如果代码没出现异常,程序正常执行
# 如果出现异常,except会尝试捕获,
#   如果捕获成功执行except下面的内容
#   如果捕获不成功(如:错误类型不匹配),依然会抛出异常

3.万能异常

  • 可以捕获python定义好的所有异常对象
  • 通过exception:所有异常类的父类
while True:

    try:
        num = int(input('请输入:'))
        num = 5 / num
        print(num)
        break
    except Exception as b:
        print(f'出现了异常:{b}')
        continue
# 运行结果:
# 请输入:0
# 出现了异常:division by zero
try:
    num = int(input('请输入:'))
    num = 5 / num
    print(num)
    
except Exception as b:
    print(f'出现了异常:{b}')
    
else:
    print('只有上面全部正常运行结束,才执行我')
finally:
    print('不管上面运行正常与否,都会执行我..如:关闭文件,需要在return或break执行前需要执行的')

4.断言

  • 表示一种强硬的态度,只要assert后面的条件不成立,就抛出异常,让当前程序终止运行(后面的代码就不执行)
  • 一般用来调试程序
print(111)
print(111)
print(111)
assert False
print(111)
print(111)
print(111)
print(111)

5.自定义异常

  • 创建一个类,将他的父类设置为exception,那么这个类就是一个自定义异常类
  • 通过这个类,我们可以定义自己的异常对象(需要主动抛出)

九,内置方法

class Girl:
    def __init__(self):
        self.name = "alex"
    # def __del__(self):
    #     print("对象死了")
    def __len__(self):
        return 10
    def __hash__(self):
        return 100
    def __str__(self):
        return self.name
    def __eq__(self, other):
        if self.name == other.name:
            return True
        else:
            return False
a = Girl()
b = Girl()
a.name = "bigB"
print(len(b))
# print(hash("123"))

十, 零散知识点

1. 模型与抽象类

1.1 模型

  • 一旦有一个类继承了models.Model,那它就是一个模型。

  • 成为了模型就会自动的为它在数据库中创建一张表。

  • 比如:Django认证系统中内置的用户模型类User;

1.2 抽象类

什么是抽象类?我们来看下面的代码:

class XXX(object):
    ...
    class Meta:
        abstract = True # 这里定义了是抽象类

1.3 抽象模型

我们知道了什么是模型,什么是抽象类,这里说一下抽象模型。

继承了models.Model就是模型,Django会自动地在数据库中为其创建一张表。但是有一些模型只是声明了一些公共字段,没有必要为它在数据库中创建一张表,这时就在它的class Meta中加入abstract=True。这样在做数据迁移时,就不会为他单独创建一张表。这样的模型被Django官方定义为抽象模型。

比如:Django认证系统中内置的抽象用户模型类AbstractUser;

代码如下:

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    """
    An abstract base class implementing a fully featured User model with
    admin-compliant permissions.

    Username and password are required. Other fields are optional.
    """
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        abstract = True

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        """
        Return the first_name plus the last_name, with a space in between.
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        """Return the short name for the user."""
        return self.first_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        """Send an email to this user."""
        send_mail(subject, message, from_email, [self.email], **kwargs)


class User(AbstractUser):
    """
    Users within the Django authentication system are represented by this
    model.

    Username and password are required. Other fields are optional.
    """
    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

十一,习题

# 一、选择题
#
# Python中定义私有属性的方法是(D)。
# A.使用private关键字
# B.使用public关键字
#
# C.使用__XX__定义属性名
# D.使用__XX定义属性名
#
# 2.
# 下列选项中,不属于面向对象程序设计的三个特征的是(A)。
#
# A.抽象
# B.封装
# C.继承
# D.多态
#
# 3.
# 以下C类继承A类和B类的格式中,正确的是(C)。
#
# A. 
# class C A, B: 
# B.
# class C(A:B)
# C.
# class C(A, B)
# D.
# class C A and B:
#
# 4.
# 下列选项中,与class
# Person等价的是(C)。
#
# A.
# class Person(Object)
# B.
# class Person(Animal)
# C.
# class Person(object)
# D.
# class Person: object
#
# 二、判断题
#
# 继承会在原有类的基础上产生新的类,这个新类就是父类。(N)
# 带有两个下划线的方法一定是私有方法。(N)
# 子类能继承父类的一切属性和方法。(N)
# 子类通过重写继承的方法,覆盖掉跟父类同名的方法。(Y)
# 如果类属性和实例属性重名,对象也可以访问类属性的值。(N)
# 使用类名获取到的值一定是类属性的值。(Y)
#
# 三、填空题
#
# 如果属性名的前面加上了两个_下划线______,就表明它是私有属性。
# 在现有类基础上构建新类,新的类称作子类,现有的类称作___父类_________。
# 父类的___私有____属性和方法是不能被子类继承的,更不能被子类访问。
# Python语言既支持单继承,也支持____多_______继承。
# 子类想按照自己的方式实现方法,需要__重写_____从父类继承的方法。
# 子类通过___继承_______可以成功地访问父类的成员。
#
# 四、简答题
#
# 请简述如何保护类的属性。
# 将需要保护的类的属性设置为私有属性

# 什么是继承?
# 在不改变类的基础上对这个类进行扩展

# 请简述私有属性无法访问的原理。
# 在底层代码中,私有属性的名字是下划线+类名+私有属性名,起到封装作用
#
# 五
# 编程题
#
# 1.
# 简述面向对象中为什么要有继承?
# 简化代码
# 2.
# Python继承时,查找成员的顺序遵循什么规则?
# C3算法,MRO
# 3.
# 需求:
# 房子有户型,总面积(私有)和家具名称列表
# 新房子没有任何的家具
# 家具有名字和占地面积,其中
# 床:占4平米
# 衣柜:占2平面
# 餐桌:占1.5平米
# 将以上三件家具添加到房子中
# 打印房子时,要求输出: 户型,总面积,剩余面积,家具名称列表
#

# class House:
#     def __init__(self, mold, __area):
#         self.mold = mold
#         self.__area = __area
#         self.furniture_lst = []
#     def add_fur(self, tools):
#         self.furniture_lst.append(tools.name)
#     def area(self):
#         return self.__area
#     def surplus(self, tools):
#         surplus_area = self.area() - tools.area
#         return surplus_area
# class Furniture:
#     def __init__(self, name, area):
#         self.name = name
#         self.area = area
# bed = Furniture('床',4)
# kas = Furniture('衣柜',2)
# board = Furniture('餐桌',1.5)
# hou = House('三居室',100)
# hou.add_fur(bed)
# hou.add_fur(kas)
# hou.add_fur(board)
# hou.surplus(bed)
# hou.surplus(kas)
# print(hou.mold,hou.area(),hou.surplus(board),hou.furniture_lst)

class House:
    def __init__(self,huxing,area):
        self.huxing = huxing
        self.__area = area
        self.jiaju_lst = []
        self.shengyumianji = self.__area
    def add_jiaju(self,tool):
        if tool.area < self.shengyumianji:
            self.jiaju_lst.append(tool)
            self.shengyumianji -= tool.area
    def show(self):
        print(f'{self.huxing},总面积:{self.__area},剩余面积:{self.shengyumianji}')
        for i in self.jiaju_lst:
            print(i.name)
class Jiaju:
    def __init__(self,name,area):
        self.name = name
        self.area = area
jia = House('三居室',120)
chuang = Jiaju('床',4)
yigui = Jiaju('衣柜',2)
canzhuo = Jiaju('餐桌',1.5)
jia.add_jiaju(chuang)
jia.add_jiaju(yigui)
jia.add_jiaju(canzhuo)
jia.show()
# 4.
# 当买车时,有很多种品牌可以选择,比如北京现代、别克、凯迪拉克、特斯拉等,
# 那么此时该怎样进行设计程序呢?能否根据用户出入的品牌名称来返回对应的汽车对象
class xiandai:
    def func(self):
        print('北京现代')
class bieke:
    def func(self):
        print('别克')
class tesila:
    def func(self):
        print('特斯拉')
class Fac:
    def choice(self,arg):
        if arg == 'x':
            return xiandai()
        if arg == 'b':
            return bieke()
        if arg == 't':
            return tesila()
        print('无效输入')
arg = input('请输入品牌首字母:')
ff = Fac()
ff.choice(arg).func()


# class House:
#     def __init__(self,apartment,area):
#         self.apartment = apartment
#         self.__area = area
#         self.ajlist = []
#         self.shengyumianji = self.__area
#     def add(self,tool):
#         if tool.area < self.shengyumianji:
#             self.ajlist.append(tool)
#             self.shengyumianji -= tool.area
#     def show(self):
#         print(f"{self.apartment},总面积是{self.__area},剩余面积是{self.shengyumianji}")
#         for i in self.ajlist:
#             print(i.name)
#
#
# class Furniture:
#     def __init__(self,name,area):
#         self.name = name
#         self.area = area
#
# wojia = House("独栋别墅",2000)
# chuang = Furniture("大通铺",4)
# yigui = Furniture("品如的衣柜",2)
# wojia.add(chuang)
# wojia.add(yigui)
# wojia.show()
# 1,定义一个银行职员类,尝试根据用户输入来调用银行职员的方法
#
# 举例:
#
# 用户可以选择查询余额,取款,存款,贷款,办理借记卡,办理信用卡等操作,
# 银行职员对象根据用户输入来调用自身的方法(使用反射)
class Clerk:
    def balance(self):
        print('余额')
    def draw(self):
        print('取款')
    def saving(self):
        print('存款')
    def loan(self):
        print('贷款')

cc = Clerk()
while True:
    choose = input('<<<').strip()
    if hasattr(cc,choose):
        func = getattr(cc,choose)
        func()
    else:
        print('输入错误')

#
# 2,简述类方法与静态方法的区别,子类能否调用父类的静态方法?
# 类方法就是将类作为对象进行操作的方法
# 静态方法就是一个在类中的普通函数
# 可以
# 静态方法中如果想要调用所在类的类属性,能否调用的到?
# 可以
# 3,定义一个特工类,特工有真实的姓名,年龄,身高体重肤色等信息。但这些信息应该对外隐藏。
# 再定义各项属性的取值/设置/删除的方法,外界访问到的并不是真实信息,同时将这些方法伪装成属性
class Agent:
    def __init__(self,name,age,height):
        self.__name = name
        self.__age = age
        self.__height = height

    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,arg):
        self.__name = arg
    @name.deleter
    def name(self):
        print('已删除')
        del self.__name

aa = Agent('alex',83,50)
print(aa.name)
aa.name = 'baoyuan'
print(aa.name)
del aa.name
print(aa.name)


#
# 4,编写一个飞机驾驶员类,要求战斗机飞行员,民航驾驶员,滑翔机驾驶员都必须实现其中的方法(使用两种方式来做约束)
# 方式一:通过父类抛出异常方式进行约束
class Pilot:
    def func(self):
        raise Exception('听话,别闹')
class Zd(Pilot):
    def func(self):
        print('战斗机飞行员')
class Mh(Pilot):
    def func(self):
        print('民航驾驶员')
class Hx(Pilot):
    def func(self):
        print('滑翔机驾驶员')

def jiekou(tool):
    tool.func()
zd = Zd()
mh = Mh()
hx = Hx()
jiekou(hx)

# 方式二:通过抽象类的方式进行约束
from abc import ABCMeta,abstractmethod
class Pilot(metaclass=ABCMeta):
    @abstractmethod
    def func(self):
        pass
class Zd(Pilot):
    def func(self):
        print('战斗机飞行员')
class Mh(Pilot):
    def func(self):
        print('民航驾驶员')
class Hx(Pilot):
    def func(self):
        print('滑翔机驾驶员')
zd = Zd()
#
# 5,将反射用到的函数整理成笔记,尝试用自己话来描述每个函数的作用
class Person:
    a = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        print(111)

pp = Person('alex',83)
# 1.
# hasattr(对象名,'属性')===>判断该对象是不是有该属性
# print(hasattr(pp,'name'))

# 2.
# getattr(对象名,'属性',[默认值])===>获取该对象的该属性的值(相当于 查)
# 默认值可写可不写:如果该对象有该属性,则可以print出来.
#               如果没有,显示默认值,不写默认值则报错
# print(getattr(pp,'name'))
# print(getattr(pp,'sex','没有'))
# print(pp.sex)

# 3.
# setattr(对象名,'属性',值)===>设置该对象的该属性的值(相当于 改)
# 如果该对象有该属性,则修改成后面的值;如果没有,就增加该属性,该属性的值就是后面的值
# setattr(pp,'name','baoyuan')
# print(pp.name)
# setattr(pp,'sex','女')
# print(pp.__dict__)
# print(pp.sex)
# print(getattr(pp,'sex','XX'))

# 4.
# delattr(对象名,'属性')===>删除该对象的该属性(相当于 查)
# delattr(pp,'name')
# print(pp.name)

# 1,编写一个计算减法的方法,当第一个数小于第二个数时,抛出“被减数不能小于减数"的异常

def func(a,b):
    if a < b:
        raise Exception('被减数不能小于减数')
    else:
        return a-b

print(func(1,2))


class Js(Exception):
    def __init__(self,a,b):
        self.a = a
        self.b = b

def jianfa(a,b):
    try:
        print(a-b)
        if a < b:
            raise Js(a,b)
    except Js:
        print('JisuanError:被减数不能小于减数')

jianfa(1,2)

# 2,info = ['http://xxx.com','http:///xxx.com','http://xxxx.cm'....]任意多的网址.定义
# 一个方法get_page(listindex) listindex为下标的索引,类型为整数。 函数调用:任意输入一个整
# 数,返回列表下标对应URL的内容,用try except 捕获列表下标越界

def get_page(listindex):
    info = ['http://xxx.com', 'http:///xxx.com', 'http://xxxx.cm']
    listindex = int(input("请输入网址序号:"))
    try:
        print(info[listindex])
    except IndexError:
        print('请输入有效序号')

get_page(1)
# 3,让一个人类对象,可以使用len()方法获得身高属性的值
#
class Person:
    def __init__(self,name,length):
        self.name = name
        self.length = length
    def __len__(self):
        return self.length
pp = Person('alex',1)
print(len(pp))
# 4,定义人类对象,用print直接打印时可以获得该对象的属性信息
#
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):
        return self.name+'
'+str(self.age)
pp = Person('alex',83)
print(pp)
# 5,尝试捕获
# KeyError

dic = {1:'alex',2:'wusir',3:'baoyuan'}
num = int(input('请输入序号:'))
try:
    print(dic[num])
except KeyError:
    print('请输入有效序号')
原文地址:https://www.cnblogs.com/richard_A/p/12157142.html