面向对象
对象就是“容器”,用来存放数据和功能的,数据和功能的集合体
类也是“容器”,是用来存放同类对象共同的数据和功能的
# 英雄的数据
# hero_name = '鲁班七号'
# hero_speed = 450
# hero_hp = 3000
# hero_atk = 100
# 英雄的功能
def get_hero_info(hero_obj):
print(f'英雄属性:名字{hero_obj["hero_name"]} 移速:{hero_obj["hero_speed"]}'
f'生命值:{hero_obj["hero_hp"]} 攻击力:{hero_obj["hero_atk"]}')
def set_hero_speen(hero_obj,speed_plus):
hero_obj['hero_speed'] += speed_plus
#玩家的数据
user_name = '张大仙'
user_gender = 'famale'
user_team = 'XYG'
user_dan = '王者荣耀'
#玩家的功能
def get_user_info():
print(f'玩家属性:名字{user_name} 性别:{user_gender}'
f'战队:{user_team} 段位:{user_dan}' )
def set_user_name(name):
global user_name
user_name = name
hero_obj = {
'hero_work':'射手',
'hero_name':'鲁班七号',
'hero_speed':450,
'hero_hp':3000,
'hero_atk':100,
'get_hero_info': get_user_info,
'set_hero_speed': set_hero_speen
}
hero1_obj = {
'hero_work': '射手',
'hero_name':'后羿',
'hero_speed':460,
'hero_hp':3100,
'hero_atk':110,
'get_hero_info': get_hero_info,
'set_hero_speed': set_hero_speen
}
类
归类
解决不同对象存相同数据的问题
类的名字空间实在定义阶段就产生了
class Hero:
hero_work = '射手'
def get_hero_info(hero_obj):
print(f'英雄属性:名字{hero_obj["hero_name"]} 移速:{hero_obj["hero_speed"]}'
f'生命值:{hero_obj["hero_hp"]} 攻击力:{hero_obj["hero_atk"]}')
def set_hero_speen(hero_obj,speed_plus):
hero_obj['hero_speed'] += speed_plus
print('xxx')
# 属性访问
print(Hero.__dict__)
print(Hero.__dict__['get_hero_info'])
print(Hero.hero_work)
hero_obj1 = Hero()
hero_obj2 = Hero()
hero_obj3 = Hero()
print(hero_obj1.__dict__)
print(hero_obj2.__dict__)
print(hero_obj3.__dict__)
print(hero_obj1.hero_work)
# hero_obj1.__dict__['name'] = '鲁班七号'
# hero_obj1.__dict__['speed'] = 450
# hero_obj1.__dict__['hp'] = 3000
# hero_obj1.__dict__['atk'] = 100
# print(hero_obj1.__dict__)
hero_obj1.name = '鲁班七号'
hero_obj1.speed = 450
hero_obj1.hp = 3000
hero_obj1.atk = 100
print(hero_obj1.__dict__)
init
hero_obj1 = Hero()
hero_obj2 = Hero()
hero_obj3 = Hero()
def init(hero_obj, name, speed, hp, atk):
hero_obj.name = name
hero_obj.speed = speed
hero_obj.hp = hp
hero_obj.atk = atk
print(hero_obj.__dict__)
print(hero_obj.hero_work)
init(hero_obj1, '鲁班七号', 450, 3000, 100 )
init(hero_obj2, '后羿', 460, 3100, 110 )
init(hero_obj3, '虞姬', 470, 3200, 120 )
print(hero_obj1.__dict__)
print(hero_obj2.__dict__)
print(hero_obj3.__dict__)
class Hero:
hero_work = '射手'
def __init__(hero_obj, name, speed, hp, atk):
hero_obj.name = name
hero_obj.speed = speed
hero_obj.hp = hp
hero_obj.atk = atk
print(hero_obj.__dict__)
print(hero_obj.hero_work)
def get_hero_info(hero_obj):
print(f'英雄属性:名字{hero_obj["hero_name"]} 移速:{hero_obj["hero_speed"]}'
f'生命值:{hero_obj["hero_hp"]} 攻击力:{hero_obj["hero_atk"]}')
def set_hero_speen(hero_obj,speed_plus):
hero_obj['hero_speed'] += speed_plus
print('xxx')
# 实例化
hero1_obj = Hero('鲁班七号', 450, 3000, 100) # Hero.__init__(空对象,)
调用类的过程
1、创建空对象
2、调用__init__方法,同时把空对象,以及调用类的时候括号里传的参数,一同传递给__init__方法
3、返回初始化之后的对象
属性查找顺序
对象自己没有,才会去类里面查找
# 实例化
hero1_obj = Hero('鲁班七号', 450, 3000, 100) # Hero.__init__(空对象,)
hero2_obj = Hero('后羿', 460, 3100, 110 )
hero3_obj = Hero('虞姬', 470, 3200, 120 )
# print(hero1_obj.name)
print(hero1_obj.hero_work)
print(hero2_obj.hero_work)
print(hero3_obj.hero_work)
print(id(hero1_obj.hero_work))
print(id(hero2_obj.hero_work))
print(id(hero3_obj.hero_work))
数据属性的特点
class Hero:
hero_work = '射手'
count = 0
def __init__(hero_obj, name, speed, hp, atk):
hero_obj.name = name
hero_obj.speed = speed
hero_obj.hp = hp
hero_obj.atk = atk
Hero.count += 1
def get_hero_info(hero_obj):
print(f'英雄属性:名字{hero_obj["hero_name"]} 移速:{hero_obj["hero_speed"]}'
f'生命值:{hero_obj["hero_hp"]} 攻击力:{hero_obj["hero_atk"]}')
def set_hero_speen(hero_obj,speed_plus):
hero_obj['hero_speed'] += speed_plus
print('xxx')
hero1_obj = Hero('鲁班七号', 450, 3000, 100) # Hero.__init__(空对象,)
hero2_obj = Hero('后羿', 460, 3100, 110 )
hero3_obj = Hero('虞姬', 470, 3200, 120 )
print(Hero.count)
隐藏属性
封装:整合
隐藏属性
1、隐藏的本质,知识一种改名操作
2、对外不对内
3、改名操作,只会在类的定义阶段检查子代码语法的时候执行一次,之后定义的__开头的属性都不会改名
1、隐藏的本质,知识一种改名操作
class Test:
x = 10
def f1(self):
print('f1')
print(Test.x)
print(Test.f1)
#运行结果
#10
#<function Test.f1 at 0x00000190BF6790D8>
class Test:
__x = 10
def __f1(self):
print('f1')
obj = Test()
print(obj.__x)
print(obj.__f1)
print(Test.x)
print(Test.f1)
#运行结果
#Traceback (most recent call last):
# File "C:\Users\4C69\PycharmProjects\python_basics\小飞\进阶篇\01-面向对象介绍.py", line 196, in <module>
# print(obj.__x)
#AttributeError: 'Test' object has no attribute '__x'
class Test:
__x = 10
def __f1(self):
print('f1')
obj = Test()
print(Test.__dict__)
print(obj._Test__x)
print(Test._Test__x)
#{'__module__': '__main__', '_Test__x': 10, '_Test__f1': <function Test.__f1 at 0x000001BFDAC690D8>, #'__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' #objects>, '__doc__': None}
#10
#10
2、对外不对内
class Test:
__x = 10
def __f1(self):
print('f1')
def f2(self):
print(self.__x)
print(self.__f1)
obj = Test()
obj.f2()
#运行结果
#10
#<bound method Test.__f1 of <__main__.Test object at 0x0000018576CDF188>>
3、改名操作,只会在类的定义阶段检查子代码语法的时候执行一次,之后定义的__开头的属性都不会改名
class Test:
__x = 10
def __f1(self):
print('f1')
def f2(self):
print(self.__x)
print(self.__f1)
Test.__y = 20
print(Test.__dict__)
# 运行结果
#{'__module__': '__main__', '_Test__x': 10, '_Test__f1': <function Test.__f1 at 0x0000015FA6689168>, 'f2': ##<function Test.f2 at 0x0000015FA6692798>, '__dict__': <attribute '__dict__' of 'Test' objects>, #'__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, '__y': 20}
property
class Test:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
@property
def age(self):
return self.__age
@age.setter
def age(self, new_age):
if type(new_age) is not int:
print('你个傻子,必须传整型!')
return
if not 0 <= new_age <= 150:
print('你个傻子,年龄必须在0-150岁!')
self.__age = new_age
@age.deleter
def age(self):
del self.__age
obj = Test('xxx', 18)
print(obj.age)
obj.age = 5
print(obj.age)
#运行结果
#18
#5
继承
继承:创建新类的方式,通过继承创建的类称为子类,被继承的类称之为父类(基类)
# 在Python2里面,有新式类和经典类的区分
# 新式类:继承了object类的子类,以及继承了这个子类的子子孙孙类
# 经典类:没有继承object类的子类,以及继承了这个子类的子子孙孙类
# 继承的特性:遗传
# 多继承
# 优点:一个子类可以同时遗传多个父类的属性
# 缺点
# 1、多继承违背了人的思维习惯
# 2、多继承会让代码的可读性变差
# 如果必须用多继承,应该用Mixins
# 属性查找
对象-类-父类-……object
class Human:
star = 'earth'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Chinese(Human):
nation = 'China'
# def __init__(self, name, age, gender):
# self.name = name
# self.age = age
# self.gender = gender
def speak_chinese(self):
print(f'{self.name}在说普通话')
class American(Human):
nation = 'America'
# def __init__(self, name, age, gender):
# self.name = name
# self.age = age
# self.gender = gender
def speak_english(self):
print(f'{self.name}在说英语')
dy_obj = Chinese('董永', 18, '男')
print(dy_obj.__dict__)
print(dy_obj.nation)
print(dy_obj.star)
dy_obj.speak_chinese()
# 运行结果
#{'name': '董永', 'age': 18, 'gender': '男'}
#China
#earth
#董永在说普通话
class Human:
star = 'earth'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Chinese(Human):
nation = 'China'
def __init__(self, name, age, gender, balance):
Human.__init__(self, name, age, gender)
self.balance = balance
def speak_chinese(self):
print(f'{self.name}在说普通话')
class American(Human):
nation = 'America'
# def __init__(self, name, age, gender):
# self.name = name
# self.age = age
# self.gender = gender
def speak_english(self):
print(f'{self.name}在说英语')
dy_obj = Chinese('董永', 18, '男')
print(dy_obj.__dict__)
print(dy_obj.nation)
print(dy_obj.star)
dy_obj.speak_chinese()
# 运行结果
#{'name': '董永', 'age': 18, 'gender': '男', 'balance': 2000}
#China
#earth
#董永在说普通话
单继承查找
class Test1:
def f1(self):
print('Test1.f1')
def f2(self):
print('Test1.f2')
self.f1()
class Test2(Test1):
def f1(self):
print('Test2.f1')
obj = Test2()
obj.f2()
# 运行结果
#Test1.f2
#Test2.f1
多继承属性查找
菱形问题(钻石问题)
MRO列表,C3算法实现
class A:
def f1(self):
print('A.f1')
class B(A):
def f1(self):
print('B.f1')
class C(A):
def f1(self):
print('C.f1')
class D(B,A):
def f2(self):
print('D.f2')
obj = D()
obj.f1()
print(D.mro())
# 运行结果
#B.f1
#[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
非菱形查找
class A:
def f1(self):
print('A.f1')
class B:
def f1(self):
print('B.f1')
class C(A):
def f1(self):
print('C.f1')
class D(B):
def f1(self):
print('D.f1')
class E:
def f1(self):
print('E.f1')
class F(C, D, E):
def f2(self):
print('F2')
print(F.mro())
obj = F()
obj.f1()
# 运行结果
#[<class '__main__.F'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.D'>, <class #'__main__.B'>, <class '__main__.E'>, <class 'object'>]
#C.f1
深度优先查找
广度优先查找
# 菱形继承
# 经典类:深度优先查找,找第一条分支的时候,就要找共同的父类
# 新式类:广度优先查找,找完最后一条分支之后,才找共同的父类
class Z:
def f1(self):
print('Z.f1')
class A(Z):
def f2(self):
print('A.f1')
class B(Z):
def f2(self):
print('B.f1')
class C(A):
def f2(self):
print('C.f1')
class D(B):
def f2(self):
print('D.f1')
class E(Z):
def f2(self):
print('E.f1')
class F(C, D, E):
def f2(self):
print('F.f2')
print(F.mro())
obj = F()
obj.f1()
# 运行结果
#[<class '__main__.F'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.D'>, <class #'__main__.B'>, <class '__main__.E'>, <class '__main__.Z'>, <class 'object'>]
#Z.f1
Mixins
注意:
1、继承结构不要太复杂
2、满足什么“是"什么的关系(is-a)
MixIns机制
class Fowl: #家禽类
pass
class SwimMixIn:
def swimming(self):
pass
class Chicken(Fowl): #鸡
pass
class Duck(SwimMixIn, Fowl):
pass
class Goose(SwimMixIn, Fowl): #鹅
pass
super
super是参照对象所属类的mro列表, 从mro列表里super所处的类的下一个类开始找
class Human:
star = 'earth'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Chinese(Human):
nation = 'China'
def __init__(self, name, age, gender, balance):
# Human.__init__(self, name, age, gender)
# super(Chinese, self).__init__(name, age, gender) #python2写法
super().__init__(name, age, gender) #python3写法
self.balance = balance
def speak_chinese(self):
print(f'{self.name}在说普通话')
obj = Chinese('大仙', 18, 'female', 2500)
print(Chinese.mro())
print(obj.__dict__)
# 运行结果
#[<class '__main__.Chinese'>, <class '__main__.Human'>, <class 'object'>]
#{'name': '大仙', 'age': 18, 'gender': 'female', 'balance': 2500}
多态
def run(self):
print('开始跑', end=' ')
class Benz(Car):
def run(self):
super().run()
print('加98号汽油')
class Lx(Car):
def run(self):
super().run()
print('充电')
class Auto(Car):
def run(self):
super().run()
print('加92号汽油')
car1 = Benz()
car2 = Lx()
car3 = Auto()
car1.run()
car2.run()
car3.run()
def drive_car(car):
car.run()
drive_car(car1)
drive_car(car2)
drive_car(car3)
# 运行结果
#开始跑 加98号汽油
#开始跑 充电
#开始跑 加92号汽油
#开始跑 加98号汽油
#开始跑 充电
#开始跑 加92号汽油
抽象基类
抽象基类它提供了接口,但是又没有去把接口实现的类,需要由子类完成。
import abc
class Car(metaclass=abc.ABCMeta):
@abc.abstractmethod
def run(self):
pass
class Benz(Car):
def run(self):
pass
class Lx(Car):
def run(self):
pass
class Auto(Car):
def run(self):
pass
car1 = Benz()
car2 = Lx()
car3 = Auto()
car1.run()
car2.run()
car3.run()
类方法
settings.py
IP = '127.0.0.1'
PORT = 3306
import settings
class Mysql:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def f1(self):
print(self.ip, self.port)
@classmethod
def instance_from_conf(cls):
print(cls)
obj = cls(settings.IP, settings.PORT)
return obj
obj = Mysql.instance_from_conf()
print(obj.__dict__)
# 运行结果
#<class '__main__.Mysql'>
#{'ip': '192.168.1.8', 'port': '3306'}
静态方法
class Mysql:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def f1(self):
print(self.ip, self.port)
@staticmethod
def f2():
print('嘿嘿嘿')
Mysql.f2()
# 运行结果
#嘿嘿嘿
反射机制
hasattr() :判断该对象是否有指定名字的属性或方法,返回值是bool类型
getattr() :获取对象指定名称的属性或方法,返回值是str类型
setattr() :给指定的对象添加属性以及属性值
delattr() :删除对象指定名称的属性或方法值,无返回值
class Ftp:
def put(self):
print('正在长传数据。。。')
def get(self):
print('正在下载数据。。。')
def interact(self):
opt = input('>>>')
# if hasattr(self, opt):
# getattr(self, opt)()
# else:
# print('功能不存在')
getattr(self, opt, self.warning)()
def warning(self):
print('功能不存在')
obj = Ftp()
obj.interact()
obj2 = Ftp()
obj2.interact()
# 运行结果
#>>>xxx
#功能不存在
#>>>get
#正在下载数据。。。
内置方法
以 开头 结尾的
会在满足条件的时候自动执行
如:__ init __
str
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print('__str__运行了')
return '嘿嘿嘿'
obj = Human('张大仙', 73)
print(obj)
# 运行结果
#__str__运行了
#嘿嘿嘿
del
在删除对象的时候,先执行
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print('__del__运行了。。。')
obj = Human('张大仙', 73)
# print(obj)
print('='*20)
obj2 = Human('李白', 80)
del obj2
print('*'*20)
# 运行结果
#====================
#__del__运行了。。。
#********************
#__del__运行了。。。
元类
实例化产生类的类
元类 -- 实例化 -- 类 -- 实例化 -- 对象
用class这个关键字,定义的所有的类,以及内置的类,都是由内置的元类type,实例化产生的。
# 1、类名
class_name = 'Human'
# 2、基类
class_bases = (object,)
# 3、执行类子代码,产生名称空间
class_dic = {}
class_body = '''
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('name:', self.name, 'age:', self.age)
'''
exec(class_body, {}, class_dic)
print(class_dic)
# 4、调用元类
Human = type(class_name, class_bases, class_dic)
print(Human)
obj = Human('张大仙', 73)
obj.info()
# 运行结果
#{'__init__': <function __init__ at #0x0000015AA88490D8>, 'info': <function info at #0x0000015AA8849168>}
#<class '__main__.Human'>
#name: 张大仙 age: 73
自定义元类
class Mytype(type):
def __init__(self, class_name, class_bases, class_dic):
print('Mytype.init')
print(self)
print(class_name)
print(class_bases)
print(class_dic)
if '_' in class_name:
raise NameError('类名不能有下划线')
if not class_dic.get('__doc__'):
raise SyntaxError('定义类必须写注释!')
# Human = Mytype(class_name, class_bases, class_dic)
# 1、调用Mytype的__new__方法,产生一个空对象Human
# 2、调用Mytype的init方法,初始化对象Human
# 3、返回初始化好的对象Human
class Human(metaclass=Mytype):
"""
aaa
"""
def __init__(self, name, age):
self.name = name
self.age = age
# 运行结果
#Mytype.init
#<class '__main__.Human'>
#Human
#()
#{'__module__': '__main__', '__qualname__': 'Human', #'__doc__': '\n aaa\n ', '__init__': <function #Human.__init__ at 0x000001B3E5992318>}
new
class Mytype(type):
def __init__(self, class_name, class_bases, class_dic):
print('Mytype.init')
# print(class_name)
# print(class_bases)
# print(class_dic)
# print(self.__base__)
# print(type(self))
def __new__(cls, *args, **kwargs):
print('Mytype.__new__')
# print(cls)
# print(args)
return super().__new__(cls, *args, **kwargs)
class Human(object, metaclass=Mytype):
"""
aaa
"""
def __init__(self, name, age):
self.name = name
self.age = age
# 结果
# Mytype.__new__
# Mytype.init
call
# 自定义元类
class Mytype(type):
def __call__(self, *args, **kwargs):
human_obj = self.__new__(self)
self.__init__(human_obj, *args, **kwargs)
dic = {}
for key in human_obj.__dict__:
dic[f'H_{key}'] = human_obj.__dict__[key]
human_obj.__dict__ = dic
return human_obj
class Human(metaclass=Mytype):
'''
测试元类,嘿嘿嘿~
'''
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('name:', self.name, 'age:', self.age)
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
return obj
# def __call__(self, *args, **kwargs):
#
obj = Human('张大仙', 73)
# 触发Mytype的__call__方法
# 1、调用Human的__new__方法
# 2、调用Human的__init__方法
# 3、返回初始化好的对象
print(obj.__dict__)
# 运行结果
# {'H_name': '张大仙', 'H_age': 73}
属性查找
# 属性查找
# 对象=》类=》父类=》object
class Mytype(type):
age = 18
def __call__(self, *args, **kwargs):
# print(object.__new__ is self.__new__)
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
class Animal(object):
# age = 17
pass
class Human(Animal):
# age = 16
pass
class Chinese(Human, metaclass=Mytype):
# age = 15
pass
class ScPerson(Chinese):
# age = 14
pass
obj = ScPerson()
# print(obj.age)
# print(ScPerson.age)
print(type(Human))
# 运行结果
# <class 'type'>
单例模式
settings.py
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
obj = Human('张大仙', 73)
# 1、模块 (python的模块就是一个天然的单例模式)
from settings import obj
print(obj)
# 2、装饰器
def singleton_mod(cls):
obj = None
def wrapper(*args, **kwargs):
nonlocal obj
if not obj:
obj = cls(*args, **kwargs)
return obj
return wrapper
@singleton_mod # Human = singleton_mod(Human)
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
obj = Human('张大仙', 73)
obj2 = Human('张大仙', 73)
print(obj)
print(obj2)
# 结果
# <__main__.Human object at 0x00000160D8E55E48>
# <__main__.Human object at 0x00000160D8E55E48>
# 3、类绑定方法
class Human:
obj = None
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def get_obj(cls, *args, **kwargs):
if not cls.obj:
cls.obj = cls(*args, **kwargs)
return cls.obj
obj = Human.get_obj('张大仙', 73)
obj2 = Human.get_obj('张大仙', 73)
print(obj)
print(obj2)
# 运行结果
# <__main__.Human object at 0x00000202310F5D08>
# <__main__.Human object at 0x00000202310F5D08>
# 4、__new__
class Human:
obj = None
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
if not cls.obj:
cls.obj = super().__new__(cls)
return cls.obj
obj = Human('张大仙', 73)
obj2 = Human('张大仙', 73)
print(obj)
print(obj2)
# 运行结果
# <__main__.Human object at 0x00000252C07A5E88>
# <__main__.Human object at 0x00000252C07A5E88>
# 5、元类
class Mytype(type):
obj = None
def __call__(self, *args, **kwargs):
if not self.obj:
# self.obj = super().__call__(*args, **kwargs)
self.obj = self.__new__(self)
self.__init__(self.obj, *args, **kwargs)
return self.obj
class Human(metaclass=Mytype):
def __init__(self, name, age):
self.name = name
self.age = age
obj = Human('张大仙', 73)
obj2 = Human('张大仙', 73)
print(obj)
print(obj2)
# 运行结果
# <__main__.Human object at 0x0000020B6761FC08>
# <__main__.Human object at 0x0000020B6761FC08>
# 如果要定义许多类,这些类都要设计成单例模式,那么每个类都要加上metaclass就比较麻烦
# 解决方案:创建一个singleton类,继承元类,然后让所有要设计成单例模式的类,继承自singleton
class Mytype(type):
obj = None
def __call__(self, *args, **kwargs):
if not self.obj:
# self.obj = super().__call__(*args, **kwargs)
self.obj = self.__new__(self)
self.__init__(self.obj, *args, **kwargs)
return self.obj
class singleton(metaclass=Mytype):
pass
class Human(singleton):
def __init__(self, name, age):
self.name = name
self.age = age
obj = Human('张大仙', 73)
obj2 = Human('张大仙', 1)
print(obj)
print(obj2)