面向对象学不会看不懂?一文详解面向对象知识点总结
前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。
PS:如有需要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 = name
self.s = sex
self.a = age
self.h = hobby
obj = Human('barry', '男', 18, '运动')
1.3.2、对象操作对象空间属性
1)对象查询对象中所有属性:对象.__ dict__
class Human:
mind = '有思想'
language = '实用语言'
def __init__(self, name, sex, age, hobby):
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
self.n = name
self.s = sex
self.a = age
self.h = hobby
obj = 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 = name
self.s = sex
self.a = age
self.h = hobby
obj = 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 = name
self.s = sex
self.a = age
self.h = hobby
obj = 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 = name
self.s = sex
self.a = age
self.h = hobby
def 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 = name
def 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 = name
def func(self, sex):
self.sex = sex
def 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 = name
def 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 = name
def 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 = name
def meet(self, girl_friend=None):
self.girl_friend = girl_friend
def 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 = name
self.age = age
def 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 = name
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}血')
def equit_weapon(self, weapon):
self.weapon = weapon # 组合: 给对象封装了一个为weapon属性
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
print(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, abstractmethod
class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
@abstractmethod
def pay(self, money): # 抽象方法
pass
class 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 pay
def 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 = name
self.age = age
self.sex = sex
class Person(Aniaml):
pass
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
继承优点:
- 1)增加了类的耦合性(耦合性不宜多,宜精)
- 2)减少了重复代码
- 3)使得代码更加规范化,合理化
2.2、单继承
2.2.1、类名,对象执行父类方法
class Aniaml(object):
type_name = '动物类'
def __init__(self, name, sex, age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(self)
print('吃东西')
class Person(Aniaml):
pass
class Cat(Aniaml):
pass
class 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 = name
self.age = age
self.sex = sex
def eat(self):
# print(self)
print('吃东西')
class Person(Aniaml):
def eat(self):
# print('%s 吃饭' % self.name)
print(f'{self.name} 吃饭')
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
p1 = 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 = name
self.age = age
self.sex = sex
def eat(self):
print('吃东西')
class Person(Aniaml):
def __init__(self, name, sex, age, mind):
Aniaml.__init__(self, name, sex, age) # 方法一
self.mind = mind
def eat(self):
super().eat()
print('%s 吃饭' % self.name)
class Cat(Aniaml):
pass
class 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 = name
self.age = age
self.sex = sex
def 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 = mind
def eat(self):
super().eat()
print('%s 吃饭' % self.name)
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
p1 = Person('春哥', 'laddboy', 18, '有思想')
print(p1.__dict__) # {'name': '春哥', 'age': 18, 'sex': 'laddboy', 'mind': '有思想'}
2.2.4、单继承练习
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
111 2
222 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.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:
pass
class B(A):
pass
obj = B()
# isinstance(a,b) 判断的是 a是否是b类 或者 b类派生类 实例化的对象.
print(isinstance(obj, B)) # True
print(isinstance(obj, A)) # True
# ----------------------------------------
# issubclass 类与类之间的关系
class A:
pass
class B(A):
pass
class 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 = name
self.age = age
obj1 = 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 = name
self.age = age
def detail(self):
print(self.name)
print(self.age)
obj1 = Foo('wupeiqi', 18)
obj1.detail()
obj2 = Foo('alex', 73)
obj2.detail()
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容
四、面向对象:多态
4.1、什么是多态
多态指的是一类事物有多种形态,多态指出了如何通过他们共同的属性和动作来操作及访问,而不需要考虑他们集体的类
# 多态
import abc
class Animal(metaclass=abc.ABCMeta): # 同一类事物:动物
@abc.abstractmethod
def talk(self):
pass
class 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 = name
self.temperature = temperature
def 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):
pass
class Ice(H2O):
pass
class Steam(H2O):
pass
w1 = Water('水', 25)
i1 = Ice('冰', -20)
s1 = Steam('蒸汽', 3000)
4.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两个类里面的相似的功能让其命名相同.
# 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): # 普通方法
pass
def __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):
pass
def 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):
pass
def __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 = 0
def __init__(self, name, age):
self.name = name
self.age = age
Student.addNum() # 写在__new__方法中比较合适,暂且放到这里
@classmethod
def addNum(cls):
cls.__num += 1
@classmethod
def getNum(cls):
return cls.__num
a = Student('A', 18)
b = Student('B', 36)
c = Student('C', 73)
print(Student.getNum())
3)静态方法
定义:使用装饰器@staticmethod。参数随意,没有self和cls参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
import time
class TimeTest(object):
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
@staticmethod
def 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 = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height ** 2)
p1 = People('egon', 75, 1.85)
print(p1.bmi)
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
class Foo:
@property
def AAA(self):
print('get的时候运行我啊')
@AAA.setter
def AAA(self, value):
print('set的时候运行我啊')
@AAA.deleter
def 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
@property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self):
del self.original_price
obj = Goods()
print(obj.price) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
5.5、函数 VS 方法
1)通过打印函数(方法)名确定
def func():
pass
print(func) # <function func at 0x00000260A2E690D0>
class A:
def func(self):
pass
print(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 MethodType
def func():
pass
class A:
def func(self):
pass
obj = 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 MethodType
class A:
def func(self):
pass
@classmethod
def func1(self):
pass
@staticmethod
def func2(self):
pass
obj = 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 = name
self.age = age
def 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,egon
print(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'
@staticmethod
def bar():
return 'bar'
f = Foo()
print(getattr(Foo, 'staticField'))
print(getattr(Foo, 'func')(f))
print(getattr(Foo, 'bar')())
6.3、当前模块的反射
import sys
def 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.py
name = '酸菜鱼'
def func():
print('in tbjx func')
class C:
area = '北京'
def __init__(self,name):
self.name = name
def func(self):
print('in B func')
其他模块的反射:
import tbjx
print(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 = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a)) # 2
7.2、__ hash__方法
class A:
def __init__(self):
self.a = 1
self.b = 2
def __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 = name
self.age = age
def __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 = name
self.age = age
def __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__')
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
7.6、__ eq__方法
比较两个对象是否相等,类似java中的equals()方法
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self, obj):
if self.a == obj.a and self.b == obj.b:
return True
a = 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 = 1
print('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 = None
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
obj = 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 = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key] = value
def __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': '酸菜鱼'}