第四章 面向对象
1.面向对象初识
1.1 面向对象过程vs函数式编程vs面向对象编程
s1 = 'fkjgkrsge'
count = 1
for i in s1:
count += 1
l1 = [1,2,3,4,5]
def my_len(a):
count = 1
for i in a:
count += 1
提高了代码的可读性,减少了代码的重复性....
上面统称为面向过程式编程.
面向过程式编程:
好处:出色的完成你之前布置的所有的需求.
坏处:但凡更改或者增加一条需求,可能整个项目都随之改变.
1.2面向对象的结构
1. 类是相似功能的集合体.
2. 类 你要站在上帝的角度去考虑问题.
类: 具有相似功能和特性的一类事物.
对象:类的具体体现.
一定要有宏观的概念,区分类与对象.
类的第二个优点: 你要站在 的角度去考虑,类一个公共模板,对象是从这个公共的模板产出的.
结构上分析:
Human 类名要具有描述性,类名首字母大写,类名不宜用_
1.3从类名的角度使用类
class Student:
"""
此类是构建学生类
"""
daily = '学习'
examination = '考试'
def work(self):
print('每天要上课')
def homework(self):
print('家庭作业')
类名的角度调用类中的属性,
1.查看类中的所有的内容.类名.__dict__
只用于获取类中的全部.
print(Student.__dict__)
print(Student.__dict__['daily'])
2.万能的 . 点
class Student:
daily = '学习'
examination = '考试'
def work(self):
print('每天上课')
def homework(self):
print('家庭作业')
print(Student.daily)#查
Student.cloth = '校服'#增
Student.examination = '不考试'#改
del Student.daily #删
print(Student.__dict__)
一般类中的属性都是通过类名. 的方式 去操控的.
类名的角度调用类中的方法.(一般类中的方法(除去类方法,静态方法外)不通过类名调用)
Student.work(5565) # 工作中不用类名调用
1.4从对象的角度分析类
class Student:
"""
此类是构建学生类
"""
daily = '学习'
examination = '考试'
def __init__(self,n,a,h):
self.name = n
self.age = a
self.hobby = h
def work(self,c):
self.color = c
print(f'{self.name}每天要上课')
def homework(self):
# 利用self 对象空间,为所欲为
print('家庭作业')
obj = Student() # 类名() 过程就叫做实例化过程,实例化一个对象
print(obj) # 对象,实例
obj1 = Student()
print(obj1)
obj = Student()
print(obj)
对象可以操作对象空间的属性 万能的点
obj = Student('xiaohong',12,'运动')
obj.age = '29' # 增
del obj.name # 删
obj.sex = '女'# 改
print(obj.age) # 查
daming = Student('大明',21,'工作')
Tom = Student('汤姆',12,'学习')
对象查看全部属性
print(obj.__dict__)
{'age': '29', 'hobby': '运动', 'sex': '女'}
对象查看类中的属性
print(daming.daily)
daming.daily = '活动'不会修改,只会在对象空间的属性中增加这样一个属性
对象调用类中的方法
liye = Student('小黑',21,'音乐')
liye.work('红色')
print(liye.__dict__)
1.5实例化对象
obj = Student() # 类名() 过程就叫做实例化过程,实例化一个对象
print(obj) # 对象,实例
实例化一个对象时发生了三件事:
1. 在内存中创建一个对象空间.
2. 自动执行__init__方法,并且将对象空间传给self参数.
3. 执行__init__方法里面的代码,给对象空间封装其属性.
1.6self
self 就是类中方法的第一个位置参数, 如果通过对象执行此方法,解释器就自动的将此对象空间当做实参传给self.约定俗称: 类中的方法第一个参数一般都设置成self.
1.7从空间角度研究类
class A:
address = '美丽富饶的沙河'
def __init__(self, name):
self.name = name
def func(self):
if self.name == 'aa':
self.skins = '吉利服'
def func1(self):
print(self.__dict__)
A.aaa = '易水寒'
obj = A('aa')
类外面可以给对象封装属性
response = input('今天天气热不热')
if response == '热':
obj.weapon = 'abc'
print(obj.__dict__)
>>>{'name': 'aa', 'weapon': 'abc'}
类内部封装属性
obj.func()
print(obj.__dict__)
>>>{'name': 'aa', 'skins': '吉利服'}
obj = A('db')
A.func1(111)
A.func1(obj)把对象传到类的方法中
print(A.__dict__)#类空间增加了一个静态属性
class Person:
mind = '有思想'
language = '会使用语言'
def __init__(self, name, age):
self.name = name
self.age = age
def work(self):
print('人类一般都需要工作')
p1 = Person('dsb', 21)
del p1.mind # 报错,不能通过对象删除类的静态属性
p1.mind = '无脑'# 对象空间增加了一个属性
print(p1.mind)#无脑
print(Person.mind)#有思想
对象如果查询一个属性: 对象空间 ----> 类空间 ----> 父类空间 --->
类查询一个属性: 类空间 ----> 父类空间 ---->
单向不可逆
对象与对象之间原则上互相独立(除去组合这种特殊的关系之外).
1.8类与类之间的关系
1.依赖关系(主从关系)
大象进冰箱
方法一:将一个对象传给另一个类的的方法中:
class Elephant:
def __init__(self,name):
self.name = name
def open(self,ref1):
print(f'{self.name}大象默念三声:芝麻开门')
ref1.open_door()
def close(self,ref2):
print(f'{self.name}大象默念三声:芝麻关门')
ref2.close_door()
class Refrigerator:
def __init__(self,name):
self.name = name
def open_door(self):
print(f'{self.name}冰箱门被打开了')
def close_door(self):
print(f'{self.name}冰箱门被关上了')
ele = Elephant('琪琪')
re = Refrigerator('美菱')
ele.open(re)
ele.close(re)
注:当传的是对象的时候,无需再ref1.open_door()括号中添加东西,调用这个方法,会自动将对象传给self.
方法二:将一个类名传到另一个类的方法中:
class Elephant:
def __init__(self,name):
self.name = name
def open(self,ref1):
print(f'{self.name}大象默念三声:芝麻开门')
ref1.open_door(re)
def close(self,ref2):
print(f'{self.name}大象默念三声:芝麻关门')
ref2.close_door(re)
class Refrigerator:
def __init__(self,name):
self.name = name
def open_door(self):
print(f'{self.name}冰箱门被打开了')
def close_door(self):
print(f'{self.name}冰箱门被关上了')
ele = Elephant('琪琪')
re = Refrigerator('美菱')
ele.open(Refrigerator)
ele.close(Refrigerator)
'''
琪琪大象默念三声:芝麻开门
美菱冰箱门被打开了
琪琪大象默念三声:芝麻关门
美菱冰箱门被关上了
'''
注:当传的是类名的时候,需再ref1.open_door()括号中添加东西,调用这个方法,需将对象re传给self.
依赖关系: 将一个类的类名或者对象传给另一个类的方法中.
实现两个:
大象执行open方法:
显示: '哪个大象 大象默念三声: 芝麻开门'
显示: '哪个冰箱门 冰箱门被打开了....'
关门的流程也需要完成.
2.组合:(聚合,组合,关联)
class Boy:
def __init__(self, name):
self.name = name
def meet(self, girl_friend=None):
self.girl_friend = girl_friend # wu对象空间 : girl_friend : object对象
def have_diner(self): # self = wu这个对象空间
if self.girl_friend:
print(f'{self.name}请年龄为:{self.girl_friend.age},姓名为{self.girl_friend.name}一起吃六块钱的麻辣烫')
self.girl_friend.shopping(self) # (self = wu对象空间)
else:
print('单身狗,吃什么吃')
class Girl:
def __init__(self, name, age):
self.name = name
self.age = age
def shopping(self,boy_friend):
print(f'{boy_friend.name},{self.name}一起去购物!')
wu = Boy('吴超')
flower = Girl('如花', 28)
wu.meet(flower)
wu.have_dinner()
>>>
吴超请年龄为:28,姓名为如花一起吃六块钱的麻辣烫
吴超,如花一起去购物!
组合: 将一个类的对象封装成另一个类的对象的属性.
上面例题的难点:
一个类的方法只能有此类的对象去调用.
一个类的方法的第一个self只接受此类的对象.
3.模拟英雄联盟写一个游戏人物的类(升级题).
要求:
1. 创建一个 Game_role的类.
2. 构造方法中给对象封装name,ad(攻击力),hp(血量).三个属性.
3. 创建一个attack方法,此方法是实例化两个对象,互相攻击的功能:
例: 实例化一个对象 盖伦,ad为10, hp为100
实例化另个一个对象 剑豪 ad为20, hp为80
盖伦通过attack方法攻击剑豪,此方法要完成 '谁攻击谁,谁掉了多少血, 还剩多少血'的提示功能.
方法一:
class GameRole:
def __init__(self,n,ad,hp):
self.name = n
self.ad = ad
self.hp = hp
def attack(self,p1):
p1.hp = p1.hp - self.ad
print(f'{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血')
gailun = GameRole('草丛伦', 10, 100)
jianhao = GameRole('风男', 20, 80)
gailun.attack(jianhao)
gailun.attack(jianhao)
返回结果:
草丛伦攻击了风男,风男掉了10血,还剩70血
草丛伦攻击了风男,风男掉了10血,还剩60血
方法二:
class GameRole:
def __init__(self,n,ad,hp):
self.name = n
self.ad = ad
self.hp = hp
def equit_weapon(self,wea):
self.weapon = wea
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def weapon_attack(self,p1,p2):
p2.hp = p2.hp - self.ad
if p2.hp >= 0:
print(f'{p1.name}利用{self.name}攻击了{p2.name},{p2.name}还剩{p2.hp}血')
else:
print('%s已死'%p2.name)
gailun = GameRole('盖伦',10,100)
zhaoxin = GameRole('赵信',20,90)
great_sword = Weapon('大宝剑',30)
spear = Weapon('红缨枪',50)
gailun.equit_weapon(spear)#依赖关系
gailun.weapon.weapon_attack(gailun,zhaoxin)# gailun.weapon == spear
gailun.weapon.weapon_attack(gailun,zhaoxin)
返回结果:
盖伦利用红缨枪攻击了赵信,赵信还剩40血
赵信已死
2.三大特性之继承(单,多继承)
-
什么是继承?
- 专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法.
- 字面意思: 继承就是继承父母所有的资产.
- 单继承,多继承.
- 如果多各类中有相同的方法,为了避免重复编写,可以将其放在父类中(基类)中
-
继承的优点:
- 节省代码.
- 增强的耦合性.
- 代码规范化.
继承分为单继承与多继承.
Person Dog Cat : 子类,派生类
Animal: 父类, 基类, 超类
单继承: 使用.
多继承:有区别.
2.1从类名执行父类的属性。
class Animal(object):
live = '有生命的'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(f'self----> {self}')
print('动物都需要进食')
class Person(Animal):
pass
print(Person.__dict__)
print(Person.live)
Person.eat(55)
返回结果:
{'__module__': '__main__', '__doc__': None}
有生命的
self----> 55
动物都需要进食
2.2从对象执行父类的一切。
实例化对象一定一定会执行三件事. 一定会执行__init__
class Animal(object):
live = '有生命的'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(f'self----> {self}')
print('动物都需要进食')
class Person(Animal):
pass
p1 = Person('dsb', 21, 'laddy_boy')
print(p1.__dict__)
print(p1.live)
p1.eat()
print(f'p1--->{p1}')
返回结果:
{'name': 'dsb', 'age': 21, 'sex': 'laddy_boy'}
有生命的
self----> <__main__.Person object at 0x0000006797AB8A20>
动物都需要进食
p1---> <__main__.Person object at 0x0000006797AB8A20>
注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).
class Animal(object):
live = '有生命的'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(f'self----> {self}')
print('动物都需要进食')
class Person(Animal):
def eat(self):
print('人类需要进食')
p1 = Person('dsb', 21, 'laddy_boy')
# 子类将父类的方法覆盖了,(重写父类的方法)
p1.eat = '李业'
print(p1.__dict__)
p1.eat() # 对象查找顺序先从对象空间找名字, 子类找名字, 父类找名字.会直接报错
2.3同时执行父类方法和执行子类方法
class Animal:
def __init__(self,n,a,s):
self.name = n
self.age = a
self.sex = s
def eat(self):
print(f'self------->{self}')
print('动物需要进食')
class Person(Animal):
def __init__(self,name,age,sex,hobby):
# 方法一:
Animal.__init__(self,name,age,sex)
# 方法二:
# super(Person, self).__init__(name,age,sex)
super().__init__(name,age,sex) # 和上面的一样,默认不写,已经传了Person,self
self.hobby = hobby
def eat(self):
print('人类需要进食')
super().eat()
p1 = Person('小红',12,'女','唱歌')
print(p1.__dict__)
print(f'p1--------->{p1}')
p1.eat()
返回结果:
{'name': '小红', 'age': 12, 'sex': '女', 'hobby': '唱歌'}
p1---------><__main__.Person object at 0x0000007F50BB1B38>
人类需要进食
self-------><__main__.Person object at 0x0000007F50BB1B38>
动物需要进食
习题
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
pass
obj = Foo(123)
obj.func1()
返回结果:123
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
def func1(self):
print("Foo. func1", self.num)
obj = Foo(123)
obj.func1()
返回结果:Foo. func1 123
class Base:
def __init__(self, num): # 2
self.num = num
def func1(self): # 4
print(self.num) # 123
self.func2() # self ---> obj # 对象查询顺序:
def func2(self):
print("Base.func2")
class Foo(Base):
def func2(self):
print("Foo.func2")
obj = Foo(123) # 1
obj.func1() # 3
返回结果:
123
Foo.func2
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func2()
返回结果:
111,1
222,2
333,3
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func1()
返回结果:
1
111 1
2
111 2
3
222 3
2.4多继承
面向对象:
python2.2之前:都是经典类。
python2.2直至python2.7之间存在两种类型: 经典类,新式类.
经典类: 基类不继承object类,查询规则:深度优先的原则.
新式类: 基类继承object类,python3x 只有新式类.查询规则: mro算法.
经典类:Foo-> H -> G -> F -> E -> D -> B -> A -> C.深度优先 | |
---|---|
python2x
class A: # 经典类
pass
class B(object): # 新式类
pass
python3x:(默认继承object)
class C: # 新式类
pass
class O:
pass
class D(O):
pass
class E(O):
pass
class F(O):
pass
class B(D,E):
pass
class C(E,F):
pass
class A(B,C):
pass
# 工作中用mro()方法研究新式类的继承顺序
print(A.mro())
返回结果:
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.O'>, <class 'object'>]
mro算法 面试中有可能会遇到
2.5c3算法
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
mro(Foo(H,G)) = [Foo] + merge(mro(H), mro(G),[H,G])
表头:
列表的第一个元素
表尾:
列表中表头以外的元素集合(可以为空)
表头,表尾
[A,B,C] : 表头: A 表尾: [B,C]
[A] : 表头: A 表尾: []
mro(A) = mro(A(B,C))
= [A] + merge(mro(B), mro(C), [B,C])
mro(B) = mro(B(D,E))
= [B] + merge(mro(D), mro(E), [D,E])
= [B] + merge([D,O], [E,O], [D,E])
= [B,D] + merge([O], [E,O], [E])
= [B,D,E,O]
mro(C) = mro(C(E,F))
= [C] + merge(mro(E), mro(F),[E,F])
= [C] + merge([E,O],[F,O],[E,F])
= [C,E] + merge([O],[F,O],[F])
= [C,E,F,O]
mro(A) = mro(A(B,C))
= [A] + merge([B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge([D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge([E,O], [C,E,F,O], [C])
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O])
= [A,B,D,C,E,F,O]
3.三大特性封装多态(鸭子类型)
3.1多态,封装
1.方法封装到类中.
2.数据封装到对象中.
封装:将一些东西内容封装到一个地方,你还可以取出来.
类设置静态属性,设置一些方法,
对象.对象可以在其对象空间中封装一些属性.
多态: 一个事物产生多种形态. 水: 气态液态固态.
python中 默认支持多态.
python中 定义变量不用规定变量的类型
3.2鸭子类型
class A:
def login(self):
pass
def register(self):
pass
class B:
def login(self):
pass
def register(self):
pass
A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类
里面的相似功能让其命名相同
1.A,B虽然无关系,但是很默契的制定了一个规范,让你使用起来更方便.
3.3super()
1.
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class Foo(A):
def f1(self):
# super().f2()
super(Foo, self).f2()
print('in A Foo')
obj = Foo()
obj.f1()
'''
in A f2
in A Foo
'''
2.
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super(Foo,self).f1()
print('in Foo') # 2
class Bar(A):
def f1(self):
print('in Bar') # 1
class Info(Foo,Bar):
def f1(self):
super(Info,self).f1()
print('in Info f1') # 3
obj = Info()
print(Info.mro()) # [Info, Foo, Bar, A]
obj.f1()
'''
[<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
in Bar
in Foo
in Info f1
'''
super() 严格意义并不是执行父类的方法.
单继承: super() 肯定是执行父类的方法.
多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self): # self = obj
print('in Bar')
class Info(Foo,Bar):
def f1(self): # self = obj
super(Foo,self).f1()
print('in Info f1')
obj = Info() # [Info, Foo, Bar, A]
obj.f1()
多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.
super补充
特别注意:super().__init__
会给对象封装新的属性,直接将原有的实例化对象中的name,a值覆盖掉.
class A:
def __init__(self):
self.name = 'Myclass'
self.a = 3
class B(A):
def __init__(self,name,a):
self.name = name
self.a = a
super().__init__()
def run(self):
print(self.name)
b = B('xiaohong',1)
print(b.__dict__)
b.run()
输出结果:
{'name': 'Myclass', 'a': 3}
Myclsoas
继承父类的方法中没有封装此属性,则不会覆盖.
class A:
def __init__(self):
self.a = 3
def rer(self):
self.name = 'Myclass'
class B(A):
def __init__(self,name,a):
self.name = name
self.a = a
super().__init__()
def run(self):
print(self.name)
b = B('xiaohong',1)
print(b.__dict__)
b.run()
返回结果:
{'name': 'xiaohong', 'a': 3}
xiaohong
3.4类的约束
class QQpay:
def pay(self, money):
print(f'利用qq支付了{money}')
class Alipay:
def pay(self, money):
print(f'利用支付宝支付了{money}')
支付功能 规划一下
def pay(obj,money): # 归一化设计
obj.pay(money)
obj1 = QQpay()
obj2 = Alipay()
pay(obj1,100)
pay(obj2,200)
在上面的情况下(在一些重要的逻辑,与用户数据相关等核心部分),我们要建立一种约束,避免发生此类错误.类的约束有两种解决方式:1. 在父类建立一种约束.2. 模拟抽象类(指定一种规范)的概念,建立一种约束.
第一种解决方式:
class Payment:
def pay(self,money): # 约定俗称定义一种规范,子类要定义pay方法.
raise Exception('子类必须定义此方法')
class QQpay(Payment):
def pay(self, money):
print(f'利用qq支付了{money}')
class Alipay(Payment):
def pay(self, money):
print(f'利用支付宝支付了{money}')
class Wechatpay(Payment):
def pay(self,money):
print(f'利用微信支付了{money}')
class Wechatpay(Payment):
def fuqian(self,money):
print(f'利用微信支付了{money}')
支付功能 规划一下
def pay(obj,money,choice): # 归一化设计
obj.pay(money)
obj3 = Wechatpay()
pay(obj3,300)
obj3.fuqian(300)
print(11)
raise Exception('子类必须定义此方法')
Exception: 子类必须定义此方法
第一种约束:在父类定义一个pay方法,主动抛出异常,如果子类没有定义pay方法,并且沿用了父类的pay方法
即会报错. python推荐的一种约束方式.
第二种:
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
# 抽象类 接口类 规范和约束 metaclass指定的是一个元类
@abstractmethod
def pay(self, money):
pass # 抽象方法
class QQpay(Payment):
def pay(self, money):
print(f'利用qq支付了{money}')
class Alipay(Payment):
def pay(self, money):
print(f'利用支付宝支付了{money}')
class Wechatpay(Payment):
def fuqian(self,money):
print(f'利用微信支付了{money}')
# def pay(self,money):
# pass
obj3 = Wechatpay()
TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
利用抽象类的概念: 基类如上设置,子类如果没有定义pay方法,在实例化对象时就会报错.
4.类的私有成员
- 对于类的公有静态属性,类的外部,类的内部,派生类都可以访问.
class B:
school_name = '老男孩教育'
class A(B):
class_name = 'python23'
def func(self):
print(self.class_name)
obj = A()
print(obj.class_name)
obj.func()
print(obj.school_name)
'''
python23
python23
老男孩教育
'''
- 私有静态属性:类外部,派生类不能访问,类内部可以访问
class B:
school_name = '老男孩教育'
__consc_edu = '良心教育'
class A(B):
class_name = 'python23'
__girlnum = '1个'
def func(self):
print(self.class_name)
print(self.__girlnum) # 可以访问
print(self.__consc_edu)# 派生类不可访问
obj = A()
# 私有静态属性:类外部不能访问
print(obj.__girlnum) #不能访问
print(A.__girlnum) #不能访问
# 私有静态属性:类内部可以访问
obj.func()#派生类不可以访问
- 对象的私有属性
class B:
school_name = '老男孩教育'
__consc_edu = '教育'
def __init__(self,weight):
self.__weight = weight
class A(B):
def __init__(self,name,age,weight):
super().__init__(weight)
self.name = name
self.__age = age
def func(self):
print(self.__age) #类的内部可以使用
# print(self.__weight) #派生类中也不可以访问
obj = A('张强',18,180)
# print(obj.__age)#类的外部不能访问
obj.func()
- 私有方法
class B:
def __func(self):
print('B的类内部可以访问')
def func3(self):
self.__func()
class A(B):
def __func1(self):
print('类外部不可以访问')
def func(self):
self.__func1()
super().func3()
super(A, self).func3()
obj = A()
obj.func()
'''
类外部不可以访问
B的类内部可以访问
B的类内部可以访问
'''
- 如果想设定一些私有的或者是不想让类外面用到,密码,加密方式,等设置成私有成员.
- 拓展: 私有成员除了在类内部,当真访问不到么?
class A:
__girlnum = '1个'
print(A.__dict__)
{'__module__': '__main__', '_A__girlnum': '1个', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
python中所有的私有成员: 就是在私有成员前面加上 _类名而已.
print(A._A__girlnum)#在前面加上_就可以访问,千万不要这么去访问!!!
print(A.__dict__['_A__girlnum'])# 和上面的一样的
5.类方法与静态方法
5.1.类方法:
class A:
num = 1
def func(self):
print('实例方法')
@classmethod #类方法:由类名直接调用的方法,他会自动的将类名传给cls
def a_func(cls):
print(cls.num)
'''
类内部可以实例化
obj1 = cls()
print(obj1)
'''
print(cls)
obj = A()
A.a_func()
print(A)
obj.a_func() #对象也可以调用类方法,但是会自动将其从属于的类名传给cls
'''
1
<class '__main__.A'>
<class '__main__.A'>
'''
定义一个Student类,我要统计学生的个数.
class Student:
num = 0
def __init__(self,name):
self.name = name
self.count()
@classmethod
def count(cls):
cls.num += 1
@classmethod
def get_num(cls):
return cls.num
obj = Student('xi')
obj1 = Student('xi')
obj2 = Student('xi')
obj3 = Student('xi')
obj4 = Student('xi')
print(Student.get_num())
5.2静态方法:
不依赖于类,也不依赖于对象,他就是一个普通的函数放置于类中是结构更加清晰与合理.
class A:
def func(self):
print(111)
@classmethod
def a_func(cls):
print(cls)
@staticmethod
def static_func(a,b,c):
print(f'{a},{b},{c}静态方法')
# def static_func(a,b,c):
# print(f'{a},{b},{c}静态方法')
A.static_func(2,3,4)
obj = A()
obj.static_func(1,2,3)
2,3,4静态方法
1,2,3静态方法
import time
class TimeTest(object):
def __int__(self,hour,minute,second):
self.hour = hour
self.minute = minute
self.second = second
def get_year(self):
pass
def get_day(self):
pass
def last_year(self):
pass
@staticmethod
def showTime():
return time.strftime('%H:%M:%S',time.localtime())
print(TimeTest.showTime())
obj = TimeTest(1,20,60)
obj.showTime()
6.属性
bmi值测试人体体脂:
class Bmi:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
def bmi(self):
return self.weight / self.height**2
tb = Bmi('太白',80, 1.75)
print(tb.bmi())
我们要让bmi方法伪装成属性,虽然在代码级别没有提升,但是看起来更合理.
class Bmi:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / self.height**2
xw = Bmi('小王',60,1.72)
print(xw.bmi)# 伪装属性时,不用在函数名后面加()了
print(xw.weight)
6.1property setter deleter
class Foo:
def __init__(self,name):
self.name = name
@property
def aaa(self):
print('get的时候运行我啊')
@aaa.setter
def aaa(self,v):
print('修改的时候运行我啊')
@aaa.deleter
def aaa(self):
print('删除的时执行我')
obj = Foo('alex')
obj.aaa
obj.aaa = 'taibai'
del obj.aaa
返回结果:
get的时候运行我啊
修改的时候运行我啊
删除的时执行我
6.2设置属性的另外一种写法:
class Foo:
def get_AAA(self):
print('get的时候运行我啊')
def set_AAA(self,value):
print('set的时候运行我啊')
def delete_AAA(self):
print('delete的时候运行我啊')
bbb = property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
f = Foo()
f.bbb
f.bbb = 'aaa'
del f.bbb
'''
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
'''
7.isinstance,issubclass
- isinstance
class A:
pass
class B(A):
pass
class C(B):
pass
obj = B()
print(isinstance(obj,B))
print(isinstance(obj,A))
print(isinstance(obj,C))
True
True
False
- 对象与类之间的关系
isinstance(obj,N): 判断 obj对象 是由N类(N的派生类)实例化的对象 返回 True.
print(isinstance(obj, A))
2.issubclass
class A:
pass
class B(A):
pass
class C(B):
pass
类与类之间的关系
issubclass(M,N) 判断是M类是N类的子孙.
print(issubclass(C, B))
print(issubclass(C, A))
7.type元类
from collections import Iterable
from collections import Iterator
s1 = 'seewfsdkfl' # class str(Iterable) Iterable
l1 = [1, 2, 3]
print(type(s1)) # 判断的是对象从属于哪个类
print(type(l1))
print("__iter__" in dir(s1))
print(isinstance(s1, Iterable))
- type 到底是什么?
- type 元类 python中一切皆对象 , 一个类也是一个对象.么这个(类)对象肯定是由类实例化出来的.python中你创建的所有类,以及大部分list str等等这些类,都是从type元类实例化得来的.
- python中继承object类都是新式类.object 也是由type元类实例化得来的.type
8.异常处理
- 什么叫异常?
- 你的程序出现中断,飘红,致使你的整个项目中断了.
9.函数vs方法
9.1通过函数名可以大致判断
def func():
pass
class A:
def func(self):
pass
print(func)#<function func at 0x00000000005D1EA0>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x0000000001DE1CF8>>
9.2通过types模块去验证
from types import FunctionType
from types import MethodType
def func():
pass
class A:
def func(self):
pass
@staticmethod
def f():
pass
print(isinstance(func,FunctionType))# True
print(isinstance(func,MethodType))# False
类名调用func 就是一个函数
print(isinstance(A.func, FunctionType))
print(isinstance(A.func, MethodType))
obj = A()
对象调用func 就是一个方法
print(isinstance(obj.func, FunctionType))
print(isinstance(obj.func, MethodType))
对于静态方法的研究,是一个函数
print(isinstance(A.f,FunctionType))
print(isinstance(A.f,MethodType))
obj = A()
对象调用func,也是一个函数
print(isinstance(obj.f,FunctionType))
print(isinstance(obj.f,MethodType))
9.3函数与方法
- 函数:全部都是显性传参
- 方法:存在隐性传参
10.反射
通过字符串去操作一个对象
字符串:字符串类型
对象:实例,类,当前文件(模块),其他模块.
10.1从实例的角度去研究反射
class A:
static_field = '静态属性'
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print('in A func')
obj = A('小王',18)
print(obj.name)
print(obj.__dict__)
print(hasattr(obj,'name')) #True
print(hasattr(obj,'name1'))#False
print(getattr(obj,'name')) #小王
print(getattr(obj,'name1',None)) #None
setattr(obj,'hobby','玩')#增加了一个属性
print(getattr(obj,'hobby'))
delattr(obj,'name') 删除
print(hasattr(obj,'name'))False
if hasattr(obj,'static_field'):
print(getattr(obj,'static_field'))#静态属性
if hasattr(obj,'func'): #字符串操作.
print(getattr(obj,'func')) # 得到一个方法
getattr(obj,'func')() #可以执行函数.
10.2从类的角度研究反射
class A:
static_field = '静态属性'
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print('in A func')
obj = A('小张',18)
print(hasattr(A, 'static_field'))
print(getattr(A, 'static_field'))
print(getattr(A, 'func')) # <function A.func at 0x0000003423EDFEA0>
getattr(A, 'func')(obj)
返回结果:
True
静态属性
<function A.func at 0x0000009C6A2732F0>
in A func
10.3从当前脚本研究反射.
class B:
static = 'B类'
import sys
# print(sys.modules)
this_modules = sys.modules[__name__]
cls = getattr(this_modules, 'B')
print(cls)#<class '__main__.B'>
obj = cls()
print(obj.static)#B类
2.
def func1():
print('in func1')
def func2():
print('in func2')
def func3():
print('in func3')
l1 = [func1,func2,func3]
l1 = [f'func{i}'for i in range(1,4)]
for i in l1:
getattr(this_modules,i)()
'''
in func1
in func2
in func3
'''
other_modules
def test():
print('in test')
在其它模块研究反射
import other_modules as om
om.test()
getattr(om,'test')() 也可以执行
class Auth:
function_list = [('login','请登录'), ('register','请注册'), ('exit', '退出')]
def login(self):
print('登录函数')
def register(self):
print('注册函数')
def exit(self):
print('退出...')
while 1:
obj = Auth()
for num,option in enumerate(Auth.function_list,1):
print(num,option[1])
choice_num = input('请选择:').strip()
if hasattr(obj,Auth.function_list[int(choice_num)-1][0]):
getattr(obj,Auth.function_list[int(choice_num)-1][0])()
11.python中特殊的双下方法
11.1__len__
class A:
def __init__(self,name,age,hobby):
self.name = name
self.age = age
self.hobby = hobby
# print(111)
def __len__(self):
# print('触发__len__方法')
return len(self.__dict__)
obj = A('亚伟',1,2)
ret = len(obj)#触发__len__
print(ret)>>>3
一个对象之所以可以使用len()函数,根本原因是这个对象从输入的类中有__len__方法,
11.2__hash__
class A:
pass
hash(obj) 会调用obj这个对象的类(基类)的__hash__方法
obj = A()
print(hash(obj))#53552261170
11.3 __str__ ,
__repr__
***
class Student:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __str__(self):
return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'
obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
obj2 = Student('mc智', 18, '男')
#
print(str(obj))
print(str(obj)) # 会触发__str__
print(obj) # 打印输出实例会触发__str__
print('此对象为%s' %obj) # 格式化输出会触发__str__
'''
姓名:小智年龄:18性别:男123
姓名:小智年龄:18性别:男123
姓名:小智年龄:18性别:男123
此对象为姓名:小智年龄:18性别:男123
'''
class Student:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __repr__(self):
return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'
obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
obj2 = Student('mc智', 18, '男')
print(obj) # 触发__repr__
print('此对象是%r' %obj) # 触发__repr__
'''
姓名:小智年龄:18性别:男
此对象是姓名:小智年龄:18性别:男
'''
两者合一
class Student:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __repr__(self):
return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'
def __str__(self):
return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'
obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
print(obj) 先触发__str__方法
'''
姓名:小智年龄:18性别:男123
'''
11.4__call__
class A:
def __init__(self):
self.a = 1
print(111)
def __call__(self, *args, **kwargs):
print('触发__call__')
obj = A()触发__init__
obj()触发__call__
'''
111
触发__call__
'''
11.5__eq__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
print(111)
return True
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b) # 对一个类的两个对象进行比较操作,就会触发__eq__方法
'''
111
True
'''
11.6 __del__
__del__ 析构方法
class A:
def __del__(self):
print(111)
obj = A()
'''
111
'''
11.7__new__
__new__ 构造方法
__new__创造并返回一个新对象.
class A(object):
def __init__(self):
print('in __init__')
def __new__(cls, *args, **kwargs):
# print(cls) cls == A
print('in __new__')
object1 = object.__new__(cls)
return object1
obj = A()
类名() 先触发__new__ 并且将类名自动传给cls.
print(obj)
11.8单例模式
一个类只能实例化一个对象,无论你实例化多少次,内存中都只有一个对象.
class A:
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
object1 = object.__new__(cls)
cls.__instance = object1
return cls.__instance
obj = A()
obj1 = A()
obj2 = A()
print(obj,obj1,obj2)
11.9 __item__
对对象进行类似于字典的操作
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(item)
print('get时 执行我')
def __setitem__(self, key, value):
self.name = value
print('set时执行我')
def __delitem__(self, key):
print(f'del obj{[key]}时,我执行')
obj = Foo('御姐')
# obj.__dict__
# obj['name']
# obj['name'] = '萝莉'
# print(obj.name)
del obj['name']
11.10 __enter__ __exit__
__enter__ __exit__
class A:
def __init__(self,name):
self.name = name
def __enter__(self):
print(111)
def __exit__(self, exc_type, exc_val, exc_tb):
print(222)
# obj = A('mc小龙')
# 对一个对象类似于进行with语句上下文管理的操作, 必须要在类中定义__enter__ __exit__
with A('mc小龙') as obj:
print(555)
# print(obj.name)
class A:
def __init__(self, text):
self.text = text
def __enter__(self): # 开启上下文管理器对象时触发此方法
self.text = self.text + '您来啦'
return self # 将实例化的对象返回f1
def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法
self.text = self.text + '这就走啦'
# f1 = A('大爷')
with A('大爷') as f1:
print(f1.text)
print(f1.text)