self:
1.只是一个参数。
2.在对象使用方法的时候,当前对象会作为第一个参数的实参传入
3.self相当于语言中的代词,表示当前对象本身(其他语言中也有使用this)
4.self的作用连接整个对象的所有信息。桥梁的作用!
5.self不是关键字,只是一个参数变量名而已,可以使用其他单词代替(禁止代替)
6.方法的初步分类:
方法中具有接受对象的参数这个方法,叫做非绑定类的方法
方法中没有接受对象的参数这个方法,叫做绑定类的方法:即 将def func(self)中的self 去掉,在用对象进行访问时因为没有self 接受对象参数,所以不能用对象访问,只能通过类去访问,类和成员方法绑定了.
class Human():
name=“林晓迪”
tall=“180”
def love(self):
print(self.name,“喜欢漂亮的花姑娘”)
def make(self):
self.love()
print(“爱做饭”)
def made():
print(“会做人”)
man=Human()
man.love()
man.make()
man.made() 类和成员方法被绑定,不能使用对象访问
Human.made()
结果:
林晓迪 喜欢漂亮的花姑娘
林晓迪 喜欢漂亮的花姑娘
爱做饭
面向对象的三大特征:
封装,继承与多态
封装特征:
实际工作中很多的成员不方便为对象之外的访问或者操作的,所以需要限定以下是否可以操作成员。
封装特性就是对于成员操作进行限制的保护性措施!
封装方法:__属性 __方法
面向对象的封装分为三个级别:
私有化封装 private
受保护的封装 protected(在继承中讲解)
公共的封装 public
对象/类成员的访问:
1.当前类/对象内部访问 (在类的结构内部)
2.类和对象的外部访问 (在类的结构外部)
3.类和对象的子类/子对象的访问(在类的结构外部,在子类/对象的内部)
公共的封装:
方法: 任何成员在没有进行私有化操作的时候默认都是公共的封装。
特征: 公共的封装成员属性和方法,在任何位置都可以被访问。
一般我们写的class都是公共封装
class FengZhuang:
sex = “机器人”
name = “人工智能”
# 成员方法
def feng(self):
print(“封印起来”)
fz = FengZhuang()
受保护的封装:(警示禁止使用效果,但不具备阻止访问的能力)
内部访问:名称前加_单下划线即可
class Human():
name = “马云”
_money = 100000000
def made(self):
print(“每天忙着赚钱,养家,大佬您辛苦了~”)
class Man(Human):
name = “张文广”
def _make(self):
self.made()
print(“拿到{}钱了,每天吃喝玩乐”.format(self._money))
wenguang = Man()
wenguang._make() #都可以访问
print(wenguang._money)
私有化封装:
方法:在成员属性或者方法名称之前,添加双下划线,就可以私有化成员。
特征:私有化的成员属性和方法,无法在类/对象的外部访问;私有化成员仅允许在类/对象的内部访问
class Human():
name = “人类”
__girlfriend = “女朋友”
def move(self):
print(self.__girlfriend)
self.__love()
print(“人类使用交通工具”)
def __love(self):
print(“开心的造人”)
wenguang = Human()
wenguang.move() #通过内部可访问_love(self)的成员方法
print(wenguang.__girlfriend) 无法输出报错
print(Human.girlfriend) 无法输出报错
python封装秘密(并没有实现真正的私有化!):(了解,但是不允许使用)
其实python没由实现和其他语言一样的面向对象封装策略(还不是很完备)
私有化封装采用了name mangling(改名) 的策略实现的私有化操作。并不是真正的私有化!
改名策略:将原有成员属性或者方法名 修改为 _类名__成员名
访问使用对象._类名__成员名即可
class Human():
name = “人类”
__girlfriend = “女朋友”
def move(self):
print(self.__girlfriend)
self.__love()
print(“人类使用交通工具”)
def __love(self):
print(“开心的造人”)
wenguang = Human()
print(wenguang._Human__girlfriend)
wenguang._Human__love()
继承
继承父母的愿望,继承父母的财产,继承支付宝。。。
计算机中继承:
面向对象中的继承就表示一个类获取另外一个类的成员的操作。(并非所有成员)
继承相关的概念:
被其他类继承的类,这个类叫做父类,也叫做基类或者超类
继承其他类的类,这个类叫做子类,也叫做派生类
继承的意义:
提高代码的重用率,建立新的类与类的关系,方便其他逻辑操作。
继承的特征:
1.在不指定父类的情况下,所有的类均继承自object类(系统提供的)
2.子类继承父类就具有父类的所有成员。
3.子类继承父类,不会将父类成员复制到子类中,子类如果需要成员,可以找父类索取!
4.私有化的成员,允许在子类中单独建立一份,不会找父类索取私有成员
5.子类可以根据需求添加自己独有的成员来进行操作。
6.子类重载父类的成员。仅仅是对子类/对象有效。并不会影响父类
7.子类在重载父类的方法的时候,也可以调用父类的方法来进行操作:
父类名.父类方法名(参数) -> 任何方式都允许
super().父类方法名() -> 必须是带有self的对象方法才可以使用
class Father(object):
__name = “父亲”
sex = “男”
money = “1个亿”
def sell(self):
print("卖包包")
def __love(self):
print("爸爸和妈妈的爱情结晶")
class Son(Father):
name = “儿子”
def sell(self):
super().sell() #Father.sell(1)
print("卖表")
def love(self):
print("儿子喜欢年轻漂亮的小姐姐")
son = Son()
print(Son.dict) #Son的类信息内没有父类的信息
print(son.sex)
son.sell()
son.love()
单继承与多继承?
单继承:一个类只能继承一个父类的方式。 多继承:一个类可以继承多个父类的方式。
单继承:(生物角度) 人类->哺乳类动物->动物->生物->有机物…
多继承:(社会角度)
舞蹈老师(教舞蹈) 体育老师(运动) 爸爸(帅气) 妈妈(打扫卫生)
我(舞蹈,运动,帅气,打扫卫生)
单继承案例:
血缘关系
class GrandFather():
money = 10000000
class Father(GrandFather):
money = 1000
face = “帅气的一张脸”
class Me(Father):
pass
myself = Me()
print(myself.money)
print(myself.face)
多继承案例:
多继承带来的BUG-菱形继承
class Human():
def say(self):
print(“人类向天怒吼:人定胜天!”)
class Man(Human):
def say(self):
super().say() #改为Human.say(1)
print(“男人向天怒吼:女孩的心思我不懂~”)
class WoMan(Human):
def say(self):
super().say() #改为Human.say(1)
print(“女人向天怒吼:男人你们能不能别猜我心思了”)
class Child(Man,WoMan):
def say(self):
super().say() #改为Woman.say(1),Man.say(0)
print(“小孩向天怒吼:哇哇哇~”)
child = Child()
child.say()
print(Child.mro())
结果为
人类向天怒吼:人定胜天!
女人向天怒吼:男人你们能不能别猜我心思了
男人向天怒吼:女孩的心思我不懂~
小孩向天怒吼:哇哇哇~
若修改结果为
人类向天怒吼:人定胜天!
人类向天怒吼:人定胜天!
女人向天怒吼:男人你们能不能别猜我心思了
男人向天怒吼:女孩的心思我不懂~
小孩向天怒吼:哇哇哇~
菱形bug:如果这里super().say()改为向父类调用,就会导致某个方法在继承中被多次调用!
菱形继承的bug解决:MRO列表和super 类
解决办法:将菱形继承改变成类似于单继承的方式
当我们定义一个菱形继承关系的时候,程序会自动生成一个新的MRO列表。
MRO列表: Method Realtion Order 方法关系列表。
MRO列表的生成的原则:1.子类永远在父类的前面 2.同一等级的类,按照子类中的继承顺序摆放
super()调用的时候,不是查找父类, 实际上super是查找MRO列表的上一个类
super()调用对象方法的时候不需要传入对象,自动传入
如果需要查看mro列表,可以使用类名.mro() 方法 或用类名.mro 查看
多态
定义:不同的子类对象调用相同的父类方法,产生不同的执行结果
多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)
多态是调用方法的技巧,不会影响到类的内部设计
关键点:继承 改写(重载)
定义狗类
class Dog:
def work(self):
print(“狗是人类的好朋友”)
定义警犬类
class ArmyDog(Dog):
def work(self):
print(‘追击敌人’)
定义缉毒犬类
class DrugDog(Dog):
def work(self):
print(‘追查毒品’)
定义二哈类
class HaDog(Dog):
def work(self):
print(“欢乐的破坏”)
#定义人类
class Person:
def with_dog(self, dog): # 只要能接收父类对象,就能接收子类对象
dog.work() # 只要父类对象能工作,子类对象就能工作。并且不同子类会产生不同的执行效果。
p = Person()
p.with_dog(ArmyDog())
p.with_dog(DrugDog())
p.with_dog(HaDog())
面向对象常用函数
issubclass()
作用:检测一个类是否是另一个类的子类
格式:issubclass(子类,父类)
返回值:布尔值
注意事项:只要存在于继承关系中 就成立
class Father():
pass
class Son(Father):
pass
res = issubclass(Son,Father)
print(res)
isinstance()
作用:检测一个对象是否是指定类的实例
格式:isinstance(对象,类)
返回值:布尔值
res = isinstance([1,2,3,4,5],tuple)
print(res)
class Son():
pass
wsc = Son()
res = isinstance(wsc,Son)
print(res)
hasattr()
作用:检测类/对象是否包含指定名称的成员
格式:hasattr(对象,‘成员名称’)
返回值:布尔值
注意:可以检测类也可以检测对象,只要可以访问就算存在
class ShengWu:
life = “活着”
class Human(ShengWu):
name = “hello”
def move(self):
print(“yidong”)
wenguang = Human()
res = hasattr(wenguang,“life”)
print(res)
getattr()
作用:获取类.对象的成员值
格式:getattr(对象,‘成员名称’,默认值)
返回值:不确定
class ShengWu:
life = “活着”
class Human(ShengWu):
name = “hello”
def move(self):
print(“yidong”)
wenguang = Human()
res = getattr(wenguang,“li”,“nihao”)
print(res)
setattr()
作用:设置类/对象的成员属性值
格式:setattr(对象,‘成员名称’,设置的值)
返回值:无
class Human():
__name = “hello”
def move(self):
print(“yidong”)
wenguang = Human()
print(wenguang.dict)
setattr(wenguang,“name”,“alice”)
print(wenguang.dict)
setattr(wenguang,“name”,“tommy”)
print(wenguang.dict)
delattr()
作用:删除类/对象的成员
格式:delattr(对象,‘成员名称’)
返回值:无
print(Human.dict)
delattr(Human,“name”)
print(Human.dict)
dir()
作用:获取对象可以访问的所有成员的列表
格式:dir(对象)
返回值:对象可以访问的所有成员的列表
print(dir(wenguang))
结果为:
{‘module’: ‘main’, ‘_Human__name’: ‘hello’, ‘move’: <function Human.move at 0x016B9B70>, ‘dict’: <attribute ‘dict’ of ‘Human’ objects>, ‘weakref’: <attribute ‘weakref’ of ‘Human’ objects>, ‘doc’: None}
property() 后面讲
作用:设置描述符操作的函数