面向对象学不会看不懂?一文详解面向对象知识点总结
前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。
PS:如有需要Python学习资料的小伙伴可以点击下方链接自行获取
Python免费学习资料、代码以及交流解答点击即可加入
一、类与对象
1.1、类的结构
class Human:"""此类主要是构建人类"""mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段dic = {}l1 = []def work(self): # 第二部分:方法 函数 动态属性print('人类会工作')
1.2、从类名的角度研究类
1.2.1、类名操作静态属性
1)查看类中的所有内容:类名__dict __方式
class Human:"""此类主要是构建人类"""mind = '有思想'dic = {}l1 = []def work(self):# print(self)print('人类会工作')print(Human.__dict__)
# {'__module__': '__main__', '__doc__': '\n 此类主要是构建人类\n ', 'mind': '有思想', 'dic': {}, 'l1': [], 'work': <function Human.work at 0x0000017D90897438>, '__dict__': <attribute '__dict__' of 'Human' objects>, '__weakref__': <attribute '__weakref__' of 'Human' objects>}print(Human.__dict__['mind']) # 有思想
# Human.__dict__['mind'] = '无脑' # TypeError: 'mappingproxy' object does not support item assignment
# 通过这种方式只能查询,不能增删改.
2)通过万能的点.
# 通过万能的点 可以增删改查类中的单个属性
class Human:"""此类主要是构建人类"""mind = '有思想'dic = {}l1 = []def work(self):# print(self)print('人类会工作')print(Human.mind) # 查
Human.mind = '无脑' # 改
print(Human.mind)
del Human.mind # 删
Human.walk = '直立行走'
print(Human.walk)
总结:如果想查询类中的所有内容,通过 第一种__ dict__方法,如果只是操作单个属性则用万能的点的方式。
1.2.2、类名操作动态方法
前提:除了两个特殊方法:静态方法,类方法之外,一般不会通过类名操作一个类中的方法
class Human:mind = '有思想'dic = {}l1 = []def work(self):print(self)print('人类会工作')def tools(self):print('人类会使用工具')Human.work(111)
Human.tools(111)
# 下面可以做,但不用
Human.__dict__['work'](111)
1.3、从对象角度研究类
1.3.1、什么是对象
对象是从类中出来的,只要是类名加上(),这就是一个实例化过程,这个就会实例化一个对象
class Human:mind = '有思想'def __init__(self):print(666)print(self) # <__main__.Human object at 0x00000191508AA828>def work(self):print('人类会工作')def tools(self):print('人类会使用工具')obj = Human() # 只要实例化对象,它会自动执行__init__方法
print(obj) # <__main__.Human object at 0x00000191508AA828>
# 并且obj的地址与self的地址相同
对象实例化三件事:
- 1)在内存中开辟了一个对象空间
- 2)自动执行类中的init方法,并将这个对象空间(内存地址)传给了init方法的第一个位置参数self
- 3)在init方法中通过self给对象空间添加属性
class Human:mind = '有思想'language = '使用语言'def __init__(self, name, sex, age, hobby):# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。self.n = nameself.s = sexself.a = ageself.h = hobbyobj = Human('barry', '男', 18, '运动')
1.3.2、对象操作对象空间属性
1)对象查询对象中所有属性:对象.__ dict__
class Human:mind = '有思想'language = '实用语言'def __init__(self, name, sex, age, hobby):# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。self.n = nameself.s = sexself.a = ageself.h = hobbyobj = Human('barry', '男', 18, '运动')
print(obj.__dict__) # {'n': 'barry', 'h': '运动', 's': '男', 'a': 18}
2)对象操作对象中的单个属性:万能的点 .
class Human:mind = '有思想'language = '实用语言'def __init__(self, name, sex, age, hobby):# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。self.n = nameself.s = sexself.a = ageself.h = hobbyobj = Human('barry', '男', 18, '运动')
obj.job = 'IT' # 增
del obj.n # 删
obj.s = '女' # 改
print(obj.s) # 查
print(obj.__dict__) # {'s': '女', 'a': 18, 'h': '运动', 'job': 'IT'}
1.3.3、对象查看类中的属性
class Human:mind = '有思想'language = '实用语言'def __init__(self, name, sex, age, hobby):self.n = nameself.s = sexself.a = ageself.h = hobbyobj = Human('barry', '男', 18, '运动')
print(obj.mind) # 有思想
print(obj.language) # 实用语言
obj.a = 666
print(obj.a) # 666
1.3.4、对象操作类中的方法
class Human:mind = '有思想'language = '实用语言'def __init__(self, name, sex, age, hobby):self.n = nameself.s = sexself.a = ageself.h = hobbydef work(self):print(self)print('人类会工作')def tools(self):print('人类会使用工具')obj = Human('barry', '男', 18, '运动')
obj.work()
obj.tools()
类中的方法一般都是通过对象执行的(除去类方法,静态方法外),并且对象执行这些方法都会自动将对象空间传给方法中的第一个参数self
self定义:self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象
1.4、类空间问题
1.4.1、何处可以添加对象属性
class A:def __init__(self, name):self.name = namedef func(self, sex):self.sex = sex# 类外面可以:
obj = A('barry')
obj.age = 18
print(obj.__dict__) # {'name': 'barry', 'age': 18}# 类内部也可以:
obj = A('barry') # __init__方法可以。
obj.func('男') # func 方法也可以。
总结:对象的属性不仅可以在__ init__里面添加,还可以在类的其他方法或者类的外面添加
1.4.2、何处可以添加类的静态属性
class A:def __init__(self, name):self.name = namedef func(self, sex):self.sex = sexdef func1(self):A.bbb = 'ccc'# 类的外部可以添加
A.aaa = 'taibai'
print(A.__dict__['aaa']) # taibai# 类的内部也可以添加。
A.func1(111)
print(A.__dict__['bbb']) # ccc
总结:类的属性不仅可以在类内部添加,还可以在类的外部添加
1.4.3、对象如何找到类的属性
对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
1.5、类与类之间的关系
1.5.1、依赖关系
依赖关系: 将一个类的类名或者对象传给另一个类的方法中
class Elephant:def __init__(self, name):self.name = namedef open(self, ref):# print(ref)print(f'{self.name}默念三声: 芝麻开门,{ref.name}冰箱门打开')ref.open_door() # 调用其他对象的方法def close(self):print('大象默念三声:芝麻关门')class Refrigerator:def __init__(self, name):self.name = namedef open_door(self):print(f'{self.name}冰箱门被打开了....')def close_door(self):print(f'{self.name}冰箱门被关上了....')ele = Elephant('琪琪')
ref = Refrigerator('美菱')
ele.open(ref)
1.5.2、组合关系
组合: 将一个类的对象封装成另一个类的对象的属性
class Boy:def __init__(self, name):self.name = namedef meet(self, girl_friend=None):self.girl_friend = girl_frienddef have_diner(self):if self.girl_friend:print(f'{self.name}请年龄为:{self.girl_friend.age},姓名为{self.girl_friend.name}一起吃六块钱的麻辣烫')self.girl_friend.shopping(self)else:print('单身狗,吃什么吃')class Girl:def __init__(self, name, age):self.name = nameself.age = agedef shopping(self, boy_friend):print(f'{boy_friend.name},{self.name}一起去购物!')wu = Boy('吴超')
flower = Girl('如花', 48)
wu.meet(flower)
wu.have_diner()
"""
吴超请年龄为:48,姓名为如花一起吃六块钱的麻辣烫
吴超,如花一起去购物!
"""
需求:模拟英雄联盟写一个游戏人物的类
1.创建一个 Game_role的类.
2.构造方法中给对象封装name,ad(攻击力),hp(血量).三个属性.
1.创建一个attack方法,此方法是实例化两个对象,互相攻击的功能: 例: 实例化一个对象 盖伦,ad为10, hp为100 实例化另个一个对象 剑豪 ad为20, hp为80 盖伦通过attack方法攻击剑豪,方法要完成 '谁攻击谁,谁掉了多少血, 还剩多少血'的提示功能.
class GameRole:def __init__(self, name, ad, hp):self.name = nameself.ad = adself.hp = hpdef attack(self, p1):p1.hp = p1.hp - self.adprint(f'{self.name}攻击{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血')def equit_weapon(self, weapon):self.weapon = weapon # 组合: 给对象封装了一个为weapon属性class Weapon:def __init__(self, name, ad):self.name = nameself.ad = addef weapon_attack(self, p1, p2):p2.hp = p2.hp - self.adprint(f'{p1.name}利用{self.name}给了{p2.name}一下,{p2.name}还剩{p2.hp}血')gailun = GameRole('盖伦', 10, 100)
zhaoxin = GameRole('赵信', 20, 90)
great_sword = Weapon('宝剑', 30)
gailun.equit_weapon(great_sword) # 依赖关系
gailun.weapon.weapon_attack(gailun, zhaoxin)
1.6、类的约束
1)方式一
提取⽗类,然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
class Payment:"""此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。"""def pay(self, money):raise Exception("你没有实现pay方法")class QQpay(Payment):def pay(self, money):print('使用qq支付%s元' % money)class Alipay(Payment):def pay(self, money):print('使用阿里支付%s元' % money)class Wechatpay(Payment):# 未实现pay方法报错# def fuqian(self, money):# print('使用微信支付%s元' % money)def pay(self, money):print(f'使用微信支付{money}元')def pay(obj, money):obj.pay(money)a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a, 100)
pay(b, 200)
pay(c, 300)
2)方式二
使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现
from abc import ABCMeta, abstractmethodclass Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类@abstractmethoddef pay(self, money): # 抽象方法passclass Alipay(Payment):def pay(self, money):print('使用支付宝支付了%s元' % money)class QQpay(Payment):def pay(self, money):print('使用qq支付了%s元' % money)class Wechatpay(Payment):def pay(self,money):print('使用微信支付了%s元'%money)# def recharge(self): pass # TypeError: Can't instantiate abstract class Wechatpay with abstract methods paydef pay(a, money):a.pay(money)a = Alipay()
pay(a, 100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能q = QQpay()
pay(q, 100)w = Wechatpay()
pay(w, 100) # 到用的时候才会报错
二、面向对象:继承
2.1、什么是继承
# 继承的用法:
class Aniaml(object):def __init__(self, name, sex, age):self.name = nameself.age = ageself.sex = sexclass Person(Aniaml):passclass Cat(Aniaml):passclass Dog(Aniaml):pass
继承优点:
- 1)增加了类的耦合性(耦合性不宜多,宜精)
- 2)减少了重复代码
- 3)使得代码更加规范化,合理化
2.2、单继承
2.2.1、类名,对象执行父类方法
class Aniaml(object):type_name = '动物类'def __init__(self, name, sex, age):self.name = nameself.age = ageself.sex = sexdef eat(self):print(self)print('吃东西')class Person(Aniaml):passclass Cat(Aniaml):passclass Dog(Aniaml):pass# 类名:
print(Person.type_name) # 可以调用父类的属性,方法。
Person.eat(111)# 对象:
p1 = Person('春哥', '男', 18)
print(p1.__dict__) # {'name': '春哥', 'age': 18, 'sex': '男'}
# 对象执行类的父类的属性,方法。
print(p1.type_name)
p1.type_name = '666'
print(p1.__dict__) # {'name': '春哥', 'age': 18, 'sex': '男', 'type_name': '666'}
p1.eat()
2.2.2、执行顺序
class Aniaml(object):type_name = '动物类'def __init__(self, name, sex, age):self.name = nameself.age = ageself.sex = sexdef eat(self):# print(self)print('吃东西')class Person(Aniaml):def eat(self):# print('%s 吃饭' % self.name)print(f'{self.name} 吃饭')class Cat(Aniaml):passclass Dog(Aniaml):passp1 = Person('barry', '男', 18)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
2.2.3、同时执行类以及父类方法
1)方式一:父类.func(对象,其他参数)
class Aniaml(object):type_name = '动物类'def __init__(self, name, sex, age):self.name = nameself.age = ageself.sex = sexdef eat(self):print('吃东西')class Person(Aniaml):def __init__(self, name, sex, age, mind):Aniaml.__init__(self, name, sex, age) # 方法一self.mind = minddef eat(self):super().eat()print('%s 吃饭' % self.name)class Cat(Aniaml):passclass Dog(Aniaml):pass# 方法一:Aniaml.__init__(self,name,sex,age)
p1 = Person('春哥', 'laddboy', 18, '有思想')
print(p1.__dict__) # {'name': '春哥', 'age': 18, 'sex': 'laddboy', 'mind': '有思想'}
p1.eat()
2)方式二:super().func(参数)
class Aniaml(object):type_name = '动物类'def __init__(self, name, sex, age):self.name = nameself.age = ageself.sex = sexdef eat(self):print('吃东西')class Person(Aniaml):def __init__(self, name, sex, age, mind):# super(Person,self).__init__(name,sex,age) # 方法二super().__init__(name, sex, age) # 方法二self.mind = minddef eat(self):super().eat()print('%s 吃饭' % self.name)class Cat(Aniaml):passclass Dog(Aniaml):passp1 = Person('春哥', 'laddboy', 18, '有思想')
print(p1.__dict__) # {'name': '春哥', 'age': 18, 'sex': 'laddboy', 'mind': '有思想'}
2.2.4、单继承练习
class Base:def __init__(self, num):self.num = numdef func1(self):print(self.num)class Foo(Base):passobj = Foo(123)
obj.func1() # 123# -------------------------------------------------
class Base:def __init__(self, num):self.num = numdef 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): # 2self.num = numdef func1(self): # 4print(self.num) # 123self.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 = numdef 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
111 2
222 3
'''# -------------------------------------------------
class Base:def __init__(self, num):self.num = numdef 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.2.5、super深入理解
super是严格按照类的继承顺序(mro算法)执行
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()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().f1()print('in Foo')class Bar(A):def f1(self):print('in Bar')class Info(Foo, Bar):def f1(self):super().f1()print('in Info f1')obj = Info()
obj.f1()'''
in Bar
in Foo
in Info f1
'''
print(Info.mro()) # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
3)示例三
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):print('in Bar')class Info(Foo, Bar):def f1(self):super(Foo, self).f1() # 多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位print('in Info f1')print(Info.mro()) # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
print(Foo.mro()) # [<class '__main__.Foo'>, <class '__main__.A'>, <class 'object'>]
obj = Info()
obj.f1()
super()总结:
super() 严格意义并不是执行父类的方法.单继承: super() 肯定是执行父类的方法.多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.
2.3、多继承
class God:def fly(self):print('会飞')def climb(self):print('神仙累了也需要爬树')class Monkey:def climb(self):print('爬树')class MonkeySun(God, Monkey):pass# 多继承的难点就是继承顺序的问题
sun = MonkeySun()
sun.climb() # 神仙累了也需要爬树
print(MonkeySun.mro())
# 继承顺序是根据类的mro()算法计算的
# [<class '__main__.MonkeySun'>, <class '__main__.God'>, <class '__main__.Monkey'>, <class 'object'>]
2.4、关键字:isinstance 与 issubclass
# isinstance 判断的是对象与类的关系
class A:passclass B(A):passobj = B()# isinstance(a,b) 判断的是 a是否是b类 或者 b类派生类 实例化的对象.
print(isinstance(obj, B)) # True
print(isinstance(obj, A)) # True# ----------------------------------------
# issubclass 类与类之间的关系class A:passclass B(A):passclass C(B):pass# issubclass(a,b) 判断的是 a类是否是b类 或者 b类派生类 的派生类.
# issubclass(a,b) 判断的是 a类是否是b类 子孙类.
print(issubclass(B, A)) # True
print(issubclass(C, A)) # True
2.5、元类
type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造的
type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类
obj = A()
print(type('abc')) # <class 'str'>
print(type([1, 2, 3])) # <class 'list'>
print(type((22, 33))) # <class 'tuple'># type 获取对象从属于的类
print(type(A)) # <class 'type'>
print(type(str)) # <class 'type'>
print(type(dict)) # <class 'type'># python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的.# type 与 object 的关系.
print(type(object)) # <class 'type'> object类是type类的一个实例.
# object类是type类的父类.
print(issubclass(type, object)) # True
三、面向对象:封装
3.1、什么是封装
封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想
3.2、封装内容调用
1)通过对象直接调用被封装的内容
class Foo:def __init__(self, name, age):self.name = nameself.age = ageobj1 = Foo('wupeiqi', 18)
print(obj1.name) # 直接调用obj1对象的name属性
print(obj1.age) # 直接调用obj1对象的age属性obj2 = Foo('alex', 73)
print(obj2.name) # 直接调用obj2对象的name属性
print(obj2.age) # 直接调用obj2对象的age属性
2)通过self间接调用被封装的内容
class Foo:def __init__(self, name, age):self.name = nameself.age = agedef detail(self):print(self.name)print(self.age)obj1 = Foo('wupeiqi', 18)
obj1.detail()obj2 = Foo('alex', 73)
obj2.detail()
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容
四、面向对象:多态
4.1、什么是多态
多态指的是一类事物有多种形态,多态指出了如何通过他们共同的属性和动作来操作及访问,而不需要考虑他们集体的类
# 多态
import abcclass Animal(metaclass=abc.ABCMeta): # 同一类事物:动物@abc.abstractmethoddef talk(self):passclass People(Animal): # 动物的形态之一:人def talk(self):print('say hello')class Dog(Animal): # 动物的形态之二:狗def talk(self):print('say wangwang')class Pig(Animal): # 动物的形态之三:猪def talk(self):print('say aoao')# -------------------------------------------
class H2O:def __init__(self, name, temperature):self.name = nameself.temperature = temperaturedef turn_ice(self):if self.temperature < 0:print('[%s]温度太低结冰了' % self.name)elif self.temperature > 0 and self.temperature < 100:print('[%s]液化成水' % self.name)elif self.temperature > 100:print('[%s]温度太高变成了水蒸气' % self.name)class Water(H2O):passclass Ice(H2O):passclass Steam(H2O):passw1 = Water('水', 25)
i1 = Ice('冰', -20)
s1 = Steam('蒸汽', 3000)
4.2、鸭子模型
class A:def login(self):passdef register(self):passclass B:def login(self):passdef register(self):pass# A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类里面的相似的功能让其命名相同.
# A,B虽然无关系,但是很默契的制定了一个规范.让你使用起来更方便.
# str tuple list 都有 index方法,这就是统一了规范
五、类的成员
5.1、细分类的成员
class A:company_name = '点筹' # 静态变量(静态字段)__iphone = '1353333xxxx' # 私有静态变量(私有静态字段)def __init__(self, name, age): # 特殊方法self.name = name # 对象属性(普通字段)self.__age = age # 私有对象属性(私有普通字段)def func1(self): # 普通方法passdef __func(self): # 私有方法print(666)@classmethod # 类方法def class_func(cls):""" 定义类方法,至少有一个cls参数 """print('类方法')@staticmethod # 静态方法def static_func():""" 定义静态方法 ,无默认参数"""print('静态方法')@property # 属性def prop(self):pass
5.2、类的私有成员
5.2.1、静态字段
静态字段(静态属性):
- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
- 私有静态字段:仅类内部可以访问
1)公有静态字段
class C:name = "公有静态字段"def func(self):print(C.name)class D(C):def show(self):print(C.name)# 类访问
print(C.name)
# 类内部可以访问
obj = C()
obj.func()
# 派生类中可以访问
obj_son = D()
obj_son.show()
2)私有静态字段
class C:__name = "私有静态字段"def func(self):print(C.__name)class D(C):def show(self):print(C.__name)# print(C.__name) # 不可在外部访问obj = C()
# print(obj.__name) # 不可在外部访问
obj.func() # 类内部可以访问# obj_son = D()
# obj_son.show() # 不可在派生类中可以访问
5.2.2、普通字段(对象属性)
普通字段(对象属性)
- 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
- 私有普通字段:仅类内部可以访问;
1)公有普通字段
class C:def __init__(self):self.foo = "公有字段"def func(self):print(self.foo) # 类内部访问class D(C):def show(self):print(self.foo) # 派生类中访问obj = C()
print(obj.foo) # 通过对象可以访问
obj.func() # 类内部可以访问obj_son = D()
obj_son.show() # 派生类中访问
2)私有普通字段
class C:def __init__(self):self.__foo = "私有字段"def func(self):print(self.__foo) # 类内部访问class D(C):def show(self):print(self.__foo) # 派生类中访问obj = C()# print(obj.__foo) # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确# obj_son = D()
# obj_son.show() # 派生类中访问 ==> 错误
5.2.3、方法
方法:
- 公有方法:对象可以访问;类内部可以访问;派生类中可以访问
- 私有方法:仅类内部可以访问;
1)公有方法
class C:def __init__(self):passdef add(self):print('in C')class D(C):def show(self):print('in D')def func(self):self.show()obj = D()
obj.show() # 通过对象访问
obj.func() # 类内部访问
obj.add() # 派生类中访问
2)私有方法
class C:def __init__(self):passdef __add(self):print('in C')class D(C):def __show(self):print('in D')def func(self):self.__show()obj = D()
# obj.__show() # 通过不能对象访问
obj.func() # 类内部可以访问
# obj.__add() # 派生类中不能访问
总结:
对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用
PS:非要访问私有成员的话,可以通过 对象._ 类__属性名,但是绝对不允许
因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
5.3、类的其他成员
1)实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为self,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
2)类方法
定义:使用装饰器@classmethod。第一个参数是当前类对象,该参数名一般约定为cls,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。
class Student:__num = 0def __init__(self, name, age):self.name = nameself.age = ageStudent.addNum() # 写在__new__方法中比较合适,暂且放到这里@classmethoddef addNum(cls):cls.__num += 1@classmethoddef getNum(cls):return cls.__numa = Student('A', 18)
b = Student('B', 36)
c = Student('C', 73)
print(Student.getNum())
3)静态方法
定义:使用装饰器@staticmethod。参数随意,没有self和cls参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
import timeclass TimeTest(object):def __init__(self, hour, minute, second):self.hour = hourself.minute = minuteself.second = second@staticmethoddef showTime():return time.strftime("%H:%M:%S", time.localtime())print(TimeTest.showTime()) # 类直接调用
t = TimeTest(2, 10, 10)
nowTime = t.showTime() # 对象调用
print(nowTime)
4)双下方法(后面会讲到)
定义:双下方法是特殊方法,他是解释器提供的由双下划线加方法名加双下划线具有特殊意义的方法,双下方法主要是python源码程序员使用的,
我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码
5.4、属性
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
class People:def __init__(self, name, weight, height):self.name = nameself.weight = weightself.height = height@propertydef bmi(self):return self.weight / (self.height ** 2)p1 = People('egon', 75, 1.85)
print(p1.bmi)
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
class Foo:@propertydef AAA(self):print('get的时候运行我啊')@AAA.setterdef AAA(self, value):print('set的时候运行我啊')@AAA.deleterdef AAA(self):print('delete的时候运行我啊')# 只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1 = Foo()
f1.AAA
f1.AAA = 'aaa'
del f1.AAA
"""
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
"""# -------------------------------------------------------
# 或者:
class Foo:def get_AAA(self):print('get的时候运行我啊')def set_AAA(self, value):print('set的时候运行我啊')def delete_AAA(self):print('delete的时候运行我啊')AAA = property(get_AAA, set_AAA, delete_AAA) # 内置property三个参数与get,set,delete一一对应f1 = Foo()
f1.AAA
f1.AAA = 'aaa'
del f1.AAA
商品实例:
class Goods(object):def __init__(self):# 原价self.original_price = 100# 折扣self.discount = 0.8@propertydef price(self):# 实际价格 = 原价 * 折扣new_price = self.original_price * self.discountreturn new_price@price.setterdef price(self, value):self.original_price = value@price.deleterdef price(self):del self.original_priceobj = Goods()
print(obj.price) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
5.5、函数 VS 方法
1)通过打印函数(方法)名确定
def func():passprint(func) # <function func at 0x00000260A2E690D0>class A:def func(self):passprint(A.func) # <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>
2)通过types模块验证
from types import FunctionType
from types import MethodTypedef func():passclass A:def func(self):passobj = A()print(isinstance(func, FunctionType)) # True
print(isinstance(A.func, FunctionType)) # True
print(isinstance(obj.func, FunctionType)) # False
print(isinstance(obj.func, MethodType)) # True
3)静态方法是函数
from types import FunctionType
from types import MethodTypeclass A:def func(self):pass@classmethoddef func1(self):pass@staticmethoddef func2(self):passobj = A()# 类方法
print(isinstance(A.func1, MethodType)) # True
print(isinstance(obj.func1, MethodType)) # True
# 静态方法其实是函数
print(isinstance(A.func2, FunctionType)) # True
print(isinstance(obj.func2, FunctionType)) # True
总结:函数都是显性传参,方法都是隐性传参
六、反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
6.1、对象的反射
class Foo:f = '类的静态变量'def __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print('hi,%s' % self.name)obj = Foo('egon', 73)# 检测是否含有某属性
print(hasattr(obj, 'name')) # True
print(hasattr(obj, 'say_hi')) # True# 获取属性
n = getattr(obj, 'name')
print(n) # egon
func = getattr(obj, 'say_hi')
func() # hi,egonprint(getattr(obj, 'aaaaaaaa', '不存在啊')) # 默认设置# 设置属性
setattr(obj, 'sb', True)
setattr(obj, 'show_name', lambda self: self.name + 'abc')
print(obj.__dict__) # {'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x000002E2F1EDE828>}
print(obj.show_name(obj)) # egonabc# 删除属性
delattr(obj, 'age')
delattr(obj, 'show_name')
# delattr(obj, 'show_name111') # 不存在,则报错
print(obj.__dict__) # {'name': 'egon', 'sb': True}
6.2、类的反射
class Foo(object):staticField = "酸菜鱼"def __init__(self):self.name = 'wupeiqi'def func(self):return 'func'@staticmethoddef bar():return 'bar'f = Foo()
print(getattr(Foo, 'staticField'))
print(getattr(Foo, 'func')(f))
print(getattr(Foo, 'bar')())
6.3、当前模块的反射
import sysdef s1():print('s1')def s2():print('s2')this_module = sys.modules[__name__]
print(this_module)print(hasattr(this_module, 's1')) # True
getattr(this_module, 's2')() # s2
6.4、其他模块的反射
其他模块:
# 文件名:tbjx.pyname = '酸菜鱼'def func():print('in tbjx func')class C:area = '北京'def __init__(self,name):self.name = namedef func(self):print('in B func')
其他模块的反射:
import tbjxprint(getattr(tbjx, 'name'))
getattr(tbjx, 'func')()# 1. 找到tbjx对象 的C类,实例化一个对象.
print(getattr(tbjx, 'C'))
obj = getattr(tbjx, 'C')('123')
print(obj)# 2. 找到tbjx对象 的C类,通过对C类这个对象使用反射取到area.
print(getattr(tbjx.C, 'area'))# 3. 找到tbjx对象 的C类,实例化一个对象,对对象进行反射取值.
obj = getattr(tbjx, 'C')('abc')
print(obj.name)
print(getattr(obj, 'name'))
6.5、反射的应用
class User:def login(self):print('欢迎来到登录页面')def register(self):print('欢迎来到注册页面')def save(self):print('欢迎来到存储页面')user = User()
while 1:choose = input('>>>').strip()if hasattr(user, choose):func = getattr(user, choose)func()else:print('输入错误。。。。')
七、双下划线方法
7.1、__ len__方法
# len 一个对象就会触发 __len__方法
class A:def __init__(self):self.a = 1self.b = 2def __len__(self):return len(self.__dict__)
a = A()
print(len(a)) # 2
7.2、__ hash__方法
class A:def __init__(self):self.a = 1self.b = 2def __hash__(self):return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
7.3、__ str__方法
如果一个类中定义了__ str__方法,那么在打印 对象 时,默认输出该方法的返回值,类似java的toString()方法
class A:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):return f'A [name = {self.name}, age = {self.age}]'a = A('酸菜鱼', 18)
print(a) # A [name = 运维人在路上, age = 18]
7.4、__ repr__方法
# repr
# print('我叫%s' % ('运维人在路上')) # 我叫运维人在路上
# print('我叫%r' % ('运维人在路上')) # 我叫'运维人在路上'
# print(repr('fdsaf')) # 'fdsaf'class A:def __init__(self, name, age):self.name = nameself.age = agedef __repr__(self):print(666)return f'姓名: {self.name} 年龄: {self.age}'a = A('AA', 35)
b = A('BB', 56)
c = A('CC', 18)
# print(a)
print(repr(a))
7.5、__ call__方法
对象后面加括号,触发执行。
注:构造方法__ new__的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __ call__ 方法的执行是由对象后加括号触发的,即:对象()或者类()()
class Foo:def __init__(self):print('__init__')passdef __call__(self, *args, **kwargs):print('__call__')obj = Foo() # 执行 __init__
obj() # 执行 __call__
7.6、__ eq__方法
比较两个对象是否相等,类似java中的equals()方法
class A:def __init__(self):self.a = 1self.b = 2def __eq__(self, obj):if self.a == obj.a and self.b == obj.b:return Truea = A()
b = A()
print(a == b) # True
7.7、__ del__方法
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
7.8、__ new__方法
对象是object类的__ new__方法 产生的,使用** 类名()**创建对象,发生了如下事情:
1.先触发 object的__ new__方法,此方法在内存中开辟一个对象空间.
2.执行__init __方法,给对象封装属性.
class A(object):def __init__(self):self.x = 1print('in init function')def __new__(cls, *args, **kwargs):print('in new function')return object.__new__(A)# 对象是object类的__new__方法 产生的.
a = A()
'''
in new function
in init function
'''
单例模式:
class A:__instance = Nonedef __init__(self, name):self.name = namedef __new__(cls, *args, **kwargs):if not cls.__instance:cls.__instance = object.__new__(cls)return cls.__instanceobj = A('AAA')
print(obj.name) # AAA
obj1 = A('BBB')
print(obj1.name) # BBB
print(obj.name) # BBB
7.9、__ item__系列
class Foo:def __init__(self, name):self.name = namedef __getitem__(self, item):print(self.__dict__[item])def __setitem__(self, key, value):self.__dict__[key] = valuedef __delitem__(self, key):print('del obj[key]时,我执行')self.__dict__.pop(key)def __delattr__(self, item):print('del obj.key时,我执行')self.__dict__.pop(item)f1 = Foo('AAA')
f1['age'] = 18
f1['height'] = 19
print(f1.__dict__) # {'name': 'AAA', 'age': 18, 'height': 19}del f1.height # del obj.key时,我执行
del f1['age'] # del obj[key]时,我执行
f1['name'] = '酸菜鱼'
print(f1.__dict__) # {'name': '酸菜鱼'}
面向对象学不会看不懂?一文详解面向对象知识点总结相关推荐
- 一文详解JavaBean 看这篇就够了
一文详解JavaBean 看这篇就够了 JavaBean的历史渊源 JavaBean的定义(通俗版) JavaBean应用 < jsp:useBean > < jsp:getProp ...
- 从基础到进阶,一文详解RocketMQ事务消息,看完不会跪键盘
本文转载自:从基础到进阶,一文详解RocketMQ事务消息,看完不会跪键盘 事务消息是RocketMQ提供的非常重要的一个特性,在4.x版本之后开源,可以利用事务消息轻松地实现分布式事务.本文对Roc ...
- 【卷积神经网络结构专题】一文详解AlexNet(附代码实现)
关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! [导读]本文是卷积神经网络结构系列专题第二篇文章,前面我们已经介绍了第一个真正意义 ...
- 一文详解 YOLO 2 与 YOLO 9000 目标检测系统
一文详解 YOLO 2 与 YOLO 9000 目标检测系统 from 雷锋网 雷锋网 AI 科技评论按:YOLO 是 Joseph Redmon 和 Ali Farhadi 等人于 2015 年提出 ...
- python面向对象编程的三大特性_Python面向对象总结及类与正则表达式详解
Python3 面向对象 -------------------------------------------------------------------------------- 一丶面向对象 ...
- 一文详解决策树算法模型
AI有道 一个有情怀的公众号 上文我们主要介绍了Adaptive Boosting.AdaBoost演算法通过调整每笔资料的权重,得到不同的hypotheses,然后将不同的hypothesis乘以不 ...
- 详解面向对象、构造函数、原型与原型链
详解面向对象.构造函数.原型与原型链 为了帮助大家能够更加直观的学习和了解面向对象,我会用尽量简单易懂的描述来展示面向对象的相关知识.并且也准备了一些实用的例子帮助大家更加快速的掌握面向对象的真谛. ...
- php获取数据3中方式,PHP面向对象之3种数据访问方式详解(代码实例)
PHP面向对象之3种数据访问方式详解(代码实例) 本文目标 掌握PHP中数据访问的3种方式的定义和作用 1.public 2.protected 3.private (一).数据访问的3种方式 1.P ...
- 一文详解宏基因组组装工具Megahit安装及应用
要点 Megahit简介 Megahit的基本组装原理 Megahit的安装和使用 Megahit实战 hello,大家好,今天为大家带来关于宏基因组组装工具Megahit的超详细安装及应用教程. 我 ...
最新文章
- 用于高保真自然图像合成的大规模GAN训练(Large Scale GAN Training For High Fidelity Natural Images)论文 pdf
- Python闭包与延迟绑定
- 「后端小伙伴来学前端了」Vue脚手架中 render 函数
- 五十八、如何对一个数进行分解质因数
- Django输入日期返回第几天time
- 无法安装软件之解决其一 (windows installer服务篇)
- Linux APT VIM 的一些指令
- 四、StringBuffer StringBuilder String 区别
- 2021-04-22 宠店流程图
- 【非公开】#include
- 可爱的PNG免扣新年装饰素材,让你海报增加节日气氛
- web linux进程管理,详解Supervisor安装与配置(Linux/Unix进程管理工具)
- vscode配置c 环境_SAST Weekly教你在macOS上用VS Code配置C/C++编程环境
- 记因循环依赖的解决方案
- python机器学习案例系列教程——最小生成树(MST)的Prim算法和Kruskal算法
- C#编程基础(简单概述与理解)
- Java在W10_java——基础 在w10环境下如何配置java环境
- GBDT 特征提取(2)
- APISpace 行驶证OCR API
- 网页yy语音(歪歪语音) 网页版
热门文章
- MATLAB中的矩阵乘法与实际矩阵乘法的差异
- 深度学习(DeepLearning)最最基础的科普ppt
- java 音频转码_javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)...
- PIC16F887 单片机 proteus SHT11
- jQueryAjax学习笔记
- 微信公众号之全局计时器的案例
- 洛达应用层开发教程系列5-程序下载
- 洛达应用层开发教程系列4-创建项目
- Android设置横屏
- 教你批量查询苏宁快递多个已签收单号的物流情况