面向对象总结
一,初识
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('请输入有效序号')