Python ( 高级 第二部)
作者:互联网
目录
模块和包
面向对象
部分一:
部分二:
部分三:
部分四:
装饰器和面相对像中的方法,property
模块和包
模块部分
1. import 导入
# 导入一次,终身受益,不会重复导入 """ import mymodule import mymodule import mymodule """""" # 模块.变量 print(mymodule.dog) # 模块.函数 mymodule.xboyww() # 模块.类 print(mymodule.MyClass().name)
2. 导入任意路径下的模块
# ### 2.导入任意路径下的模块 """自定义模块时,不能使用中文,也不能使用已存在的模块名,会被覆盖.""" import sys print(sys.path) """ # 把路径添加到系统环境变量path当中, # 执行命令时,系统会自动按照路径找到模块,从而引入 # 如果找不到当前模块所在的路径,直接报错 """ # 在windows中执行 sys.path.append(r"E:\python31_gx") import mymodule2 print(mymodule2.ceshi100) import mymodule2 as m2 print(m2.ceshi200) """ # [linux] ['/mnt/hgfs/python31_gx/day21/import_bao', '/home/wangwen/PycharmProjects/untitled', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages' ] # [windows] ['E:\\python31_gx\\day21\\import_bao', 'E:\\py_mylianxi', 'E:\\py_mylianxi\\venv\\Scripts\\python36.zip', 'C:\\Users\\wangwen\\AppData\\Local\\Programs\\Python\\Python36\\DLLs', 'C:\\Users\\wangwen\\AppData\\Local\\Programs\\Python\\Python36\\lib', 'C:\\Users\\wangwen\\AppData\\Local\\Programs\\Python\\Python36', 'E:\\py_mylianxi\\venv', 'E:\\py_mylianxi\\venv\\lib\\site-packages' ] """
3. from ... import ...
# ### 3.from ... import ... 从 ... 导入 ... # 导入单个 from mymodule import dog print(dog) # 导入多个 from mymodule import cat,xboyww print(cat) xboyww() # 导入所有 """ * 代表所有 """ from mymodule import * print(cat) xgirl() # 导入的同时,起别名 from mymodule import xboyww as ww ww()
*** 关于设置* 号的导入范围:
# 可以设置*号的导入范围 from mymodule import * print(cat) # xboyww() error '''可以在mymodule模块中设置__all__ = ["dog","cat"]来指定*号的导入范围'''
4. __name__ 魔术属性的使用
返回模块名字的魔术属性 __name__
如果当前文件是直接运行的,返回 __main__
如果当前文件是间接导入的,返回当前文件
文件直接被执行的时候,返回 __main__
当成模块被导入的时候,返回模块名本身
包部分
关于包的注意点:
1. 文件就是模块,文件夹就是包
2. __init__ .py 对包( 文件夹) 进行初始化的脚本文件,导包的时候,系统自动调用 __init__ .朋友文件, 把init文件里面成员进行导入
3. 可以通过 __init__ 间接导入其他模块
1. import 导入包
# ### (一)import 导入包的使用 # 1.获取包初始化文件中的成员 import package1 print(package1.ceshi301) # 2.导入包下的某些模块 # 方法一 import package1.mypath package1.mypath.join() # 方法二(模拟os.path.join写法) import package1 package1.mypath.join() package1.mypath.getsize() ''' 注意:在方法二的情况下,需要在包内的__init__.py中写入from package1 import mypath 相当于通过__init__文件间接导入了join和getsize方法 '''
2. from ... import 从包导入响应成员
# 从包当中导入成员属性(__init__) from package1 import ceshi301 print(ceshi301) # 从包当中导入模块 from package1 import mypath mypath.join() # 引入包下的模块下的具体成员 from package1.mypath import getsize getsize() # 在引入的同时,起别名 from package1.mypath import getsize as gs , join as j gs() j() # 导入所有,可以指定*号引入的范围 from package1 import * print(ceshi301) # print(ceshi302) error
3. 单入口模式(相对导入)
# ### (三) 单入口模式(相对导入) import package2.pkg1.pgone_1 as ppp1 # print(ppp1.ceshi1000)
面向对象
部分一:
面向对象程序开发
1. 类的三种定义方式
class MyClass: pass class MyClass(): #(推荐) pass class MyClass(object): # object类是所有类的父类 pass
2. 类的实例化
class MyCar(): color = "黄色的" # 实例化对象 (类的实例化) obj = MyCar()
3. 类的基本结构
类的基本结构包括成员属性和成员方法
""" 1.成员属性 2.成员方法 """ class MyCar(): # 成员属性 color = "天蓝色的" # 成员方法 def didi(): print("小车会滴滴叫")
4. 注意点:在类中不能写逻辑语句或循环语句
这种写法可以直接在Python当中执行,但是严禁使用
如果想要表达逻辑或者循环
需要写在成员方法当中,不能直接裸露的写在类当中,会破坏类中结构
class MyCar(): if 5 == 5: print("打印成功123456")
5. 类的命名
驼峰命名法:推荐起类名的时候,使用大驼峰命名法
mycar -> MyCar mymouse => MyMouse
面向对象封装: 对象的相关操作
1.在类外动态添加成员属性 --> 通过obj对象
# 可以在类外通过对象.属性为对象添加属性 obj.logo = "五菱宏光" print(obj.logo)
如果想确认obj 对象中是否有你新添加的logo属性, 可以使用对象__dict__获取类对象中的成员
2. 在类外动态添加成员方法 --> 通过obj对象
在类外动态添加成员方法,可以为 无参 方法和有参方法
# 1.无参方法 def dahuangfeng(): print("变形! 我是大黄蜂~") obj.dahuangfeng = dahuangfeng obj.dahuangfeng() # 2.有参方法 # 2.1 基础版 def qingtianzhu(name): print("请我叫我一柱擎天,简称{}".format(name)) obj.qingtianzhu = qingtianzhu obj.qingtianzhu("擎天柱") # 2.2 升级版 def qingtianzhu(obj,name): print("请我叫我一柱擎天,简称{},颜色是{}".format(name,obj.color)) obj.qingtianzhu = qingtianzhu obj.qingtianzhu(obj,"擎天柱") # 2.3 究极版 (即使调用类外动态创建的方法,也让系统自己传递obj对象本身) '''在类外调用自定义方法时,系统不会自动传递obj对象参数''' import types def qingtianzhu(obj,name): print("请我叫我一柱擎天,简称{},颜色是{}".format(name,obj.color)) # MethodType(方法,对象) 把哪个方法和哪个对象绑定到一起,形成绑定方法 obj.qingtianzhu = types.MethodType(qingtianzhu,obj) obj.qingtianzhu("擎天柱")
3. 也可以使用lambda表达式实现在类外添加方法
obj.weizhentian = lambda : print("我是威震天~ ") obj.weizhentian()
面向对象封装: 类的相关操作
类调用方法有俩种: 类,成员属性和类,成员方法
但是需要注意的是:类中的无参方法只能 由类来调用
定义一个MyCar类,并定义其公私有属性和方法
class MyCar(): # 公有属性 oil = "2.0T" # 私有属性 __price = "5000千万" # 公有方法 def oil_info(): print("百公里油耗是500升",MyCar.color) # 私有方法 def __price_info(): print("我的油耗信息是保密的")
注意: 对象不能调用类中无参的方法!!!!!!!!!!!!!!
# 对象不能调用类中无参的方法 obj = MyCar() obj.oil_info() # 请注意!!!对象不能调用类中无参的方法 ''' 注意:对象不能调用类中无参的方法!! 原因:对象在调用方法时,会默认将obj对象作为参数传到类中的无参的方法,进而导致参数数量不一致 '''
1. 定义的类访问公有成员和属性
# 访问公有成员属性 print(MyCar.oil) # MyCar.__price error # 无法在类外访问私有成员属性 # 访问公有成员方法 MyCar.oil_info() # MyCar.__price_info() error # 无法在类外访问私有成员方法
2. 定义的类动态添加公有成员和属性
1. 添加成员属性
MyCar.color = "红色" print(MyCar.color) # 查看类对象内部成员使用__dict__,返回的是字典 print(MyCar.__dict__)
2. 添加成员方法
# 1.无参方法 def fangxiangpan(): print("改造方向盘的方法") MyCar.fangxiangpan = fangxiangpan MyCar.fangxiangpan() print(MyCar.__dict__) # 2.有参方法 def fadongji(engin): print("动力引擎改成{}".format(engin)) MyCar.fadongji = fadongji MyCar.fadongji("三缸发动机") # 3.lambda 表达式 MyCar.luntai = lambda name : print("使用{}的轮胎".format(name)) MyCar.luntai("米其林") print(MyCar.__dict__)
3.需要注意: 类不能反过来调用对象中的成员!!!!!!!!
3. 类和对象之间的区别
类和对象之间的区别:
1. 对象可以调用类中的成员属性和方法,反过来,类不能调用对象中的成员
2. 类中的成员属性和方法归属于类本身,对象可以使用,但是没有修改和删除的权限
3. 对象在调用相应成员时,先找自己有没有
如果有,调用自己的
如果没有,调用类中的成员
如果类中成员也没有,直接报错
4. 如何访问类中的私有成员
定义Plane类,并创建如下属性和方法
class Plane(): # 公有属性 captain = "Mike" # 私有属性 __sistem = 10 # 公有绑定方法 def fly1(self): print("我的飞机可以倒着飞1") # 公有普通方法 def fly2(): print("我的飞机可以倒着飞2") # 私有绑定方法 def __fly_info1(self): print("我的飞机,百公里油耗是5万升1") # 私有普通方法 def __fly_info2(): print("我的飞机,百公里油耗是5万升2") # 公有绑定方法->间接调用私有成员 def pub_info1(self): print(self.__sistem) self.__fly_info1() # 公有普通方法->间接调用私有成员 def pub_info2(): print(Plane.__sistem) Plane.__fly_info2()
关于实现Python私有化,有俩种方法
方法一
''' 关于python私有化的实现方法: 改名策略 _类名 + 私有成员 => 改名策略 ''' # 方法一.调用私有成员 (不推荐使用改名策略找到私有成员,破坏封装性) # 对象调用类中的私有成员 obj = Plane() print(obj._Plane__sistem) obj._Plane__fly_info1() # 类调用类中的私有成员 print(Plane._Plane__sistem) Plane._Plane__fly_info2() print(Plane.__dict__)
方法二
# 方法二.类或对象利用公有方法,间接找到私有成员(推荐) obj.pub_info1() Plane.pub_info2() """ 针对于这个方法,我们可以在类中定义公有绑定方法和公有普通方法间接调用私有成员 """ # 公有绑定方法->间接调用私有成员 def pub_info1(self): print(self.__sistem) self.__fly_info1() # 公有普通方法->间接调用私有成员 def pub_info2(): print(Plane.__sistem) Plane.__fly_info2()
实例化的对象/ 定义的类删除公有成员属性和公有成员方法
# 1.公有成员属性 # 对当前对象添加成员属性交captain obj.captain = "王浩" # 删除当前对象中的成员属性captain del obj.captain # 删除类当中的成员属性captain del Plane.captain print(obj.captain) # error 无论是类还是对象都没有改属性,所以报错; # 2.公有成员方法 Plane.add_sistem = lambda self: print("因为业务需要,需要增加乘务员") Plane.add_sistem(1) obj.add_sistem() # 删除类中的成员方法 del Plane.add_sistem obj.add_sistem() # error 发现被删找不到了 obj.chaixie = lambda : print("我的飞机可以用来拆卸") obj.chaixie() # 删除对象中的成员方法 del obj.chaixie obj.chaixie() # error
最后: 对象和类都可以使用 __dict__方法查看当前类/对象中的成员
print(obj.__dict__) # {} print(Plane.__dict__) # {'__module__': '__main__', '_Plane__sistem': 10, 'fly1': <function Plane.fly1 at 0x7f26187360d0>, 'fly2': <function Plane.fly2 at 0x7f2618736158>, '_Plane__fly_info1': <function Plane.__fly_info1 at 0x7f26187361e0>, '_Plane__fly_info2': <function Plane.__fly_info2 at 0x7f2618736268>, 'pub_info1': <function Plane.pub_info1 at 0x7f26187362f0>, 'pub_info2': <function Plane.pub_info2 at 0x7f2618736378>, '__dict__': <attribute '__dict__' of 'Plane' objects>, '__weakref__': <attribute '__weakref__' of 'Plane' objects>, '__doc__': None}
部分二:
单继承衍生类
关于继承的基本概念
1. 什么是子类? 什么是父类? 如果一个类继承另一个类, 该类叫做子类(衍生类), 被继承的类叫做父类(基类,超类)
2. 继承的种类 1单继承 2多继承
3. object类: 在Python中,所有的类都默认继承父类object
定义一个Human类, 并定义一些属性和方法
class Human(object): hair = "黑色" sex = "男" def cry(self): print("人类会哭") def eat(self): print("人类会吃东西") def __makebaby(self): print("人类会繁衍生息")
子类可以调用父类的公有成员
# 1.子父继承之后,子类可以调用父类的公有成员 class Man(Human): # 定义Man类,继承Human类 pass obj = Man() print(obj.hair) # 子类Man直接调用父类的hair属性 obj.cry() # 子类Man直接调用父类的cry方法
子类无法调用父类的私有成员
# 2.子父继承之后,子类不能调用父类的私有成员 class Woman(Human): def pub_func(self): self.__makebaby() obj = Woman() obj.__makebaby() # error 子类无法直接调用父类的私有成员 obj.pub_func() # error 即使在子类定义pub_func用来存放私有成员,那也是父类的私有成员,而非子类的
子类可以给写父类的方法
子父继承之后
1. 如果子类里面有该成员属性或者方法, 优先调用自己的
2. 如果子类没有该成员,则调用父类中的成员
3. 如果子类父类都没有该成员,则直接报错
class Children(): sex = "女" def cry(self): print("小孩会哇哇哇哭") obj = Children() obj.cry() # 子类有cry方法,优先使用子类的
多继承
多继承的基本语法
# 1.基本语法 class Father(): property = "爸爸英姿飒爽" def f_hobby(self): print("爸爸喜欢抽烟") class Mother(): property = "妈妈倾国倾城" def m_hobby(self): print("妈妈喜欢打麻将") class Daughter(Father,Mother): # Daughter类继承Father类和Mother类 pass # 实例化对象 obj = Daughter() print(obj.property) # 优先会继承Father类的property obj.m_hobby() # 妈妈喜欢打麻将
super用法
1. super 本身是一个类, super() 是一个对象,用来调用父类的绑定方法
2. super() 只应用在绑定方法中,默认自动传递self对象(前提super所在作用域存在self)
3,. super用途:解决复杂的多继承调用顺序
class Father(): property = "爸爸英姿飒爽" def f_hobby(self): print("爸爸喜欢抽烟") class Mother(): property = "妈妈倾国倾城" def m_hobby(self): print("妈妈喜欢打麻将") class Son(Father,Mother): property = "儿子喜欢玩游戏" # 1.利用类来调用父类的成员 def skill1(self): Father.f_hobby() print(Mother.property) # 2.利用对象调用父类的成员 def skill2(self): self.m_hobby() print(self.property) # 3.利用super调用父类的属性和方法 """ super()只调用父类的相关公有成员,不会调用自己的本类成员,父类没有直接报错 super()在调用父类方法时,只调用父类的绑定方法,默认传递参数是本类的对象self """ def skill3(self): print(super().property) super().m_hobby() obj = Son() obj.skill1() obj.skill2() obj.skill3()
self和super的区别
self和super()的区别:
self在调用成员时,先看自己的类对象是否存在该成员
1. 如果自己有调用自己的
2. 如果子类没有,调用父类的
3. 如果子类父类都没有,直接报错
super() 在调用成员时,只调用父类的相关成员(属性,绑定方法)
永远不会调用自己的,如果父类没有,就直接报错
菱形继承(钻石继承)
super; 用来解决复杂的多继承调用顺序
class OldWoman(): pass class Human(): pty = 4 def feelT(self): print("原始人类热了,吃冰块1") print(self.pty) print("原始人类冷了,生火取暖2") class Man(Human): pty = 3 def feelT(self): print("现代男人热了,光膀子3") super().feelT() print("现代男人冷了,穿大棉袄4") class Woman(Human): pty = 2 def feelT(self): print("现代女人热了,吹空调5") super().feelT() print("现代女人冷了,喝热水6") class Children(Man,Woman): pty = 1 def feelT(self): print("现代小孩热了,哇哇哭7") super().feelT() print("现代小孩冷了,也要哭8") obj = Children() obj.feelT()
执行顺序是73512648, 继承顺序Children -> Father -> Mother -> Human
执行完毕之后还需要将每个类中的feel 方法中剩余的代码执行完
整个代码的执行顺序像递归中'一来一回'的过程
mro 列表: 返回调用顺序列表
mro列表 super用途的一个体现,解决复杂的多继承调用顺序关系
类.mro() 返回的是方法调用顺序列表,针对于多继承下的同名方法,按照顺序依次的进行调用
lst = Children.mro() print(lst) """ [ <class '__main__.Children'>, <class '__main__.Man'>, <class '__main__.Woman'>, <class '__main__.Human'>, <class 'object'> ] """
issubclass(应用在类当中,判断子父类关系)和isinstence(应用在对象和类之间,判断类型)
issubclass(应用在类当中,判断子父类关系)
# issubclass 判断子父关系 (应用在类当中,判断子父关系) """只要在一条继承链上即可(有血缘关系)""" res = issubclass(Children,Man) print(res) res = issubclass(Children,Woman) print(res) res = issubclass(Children,Human) print(res) res = issubclass(Children,(Human,Woman,Man,OldWoman)) print(res) res = issubclass(Children,OldWoman) print(res)
isinstence(应用在对象和类之间,判断类型)
# isinstance(应用在对象和类之间,判断类型) """只要在一条继承链上即可(有血缘关系)""" res = isinstance(obj,Children) # True res = isinstance(obj,Human) # True res = isinstance(obj,(Human,Children,Woman)) # True res = isinstance(obj,OldWoman) # False
问题: 打印的值是多少?
魔术方法 __init__
__init__方法简介
1. 触发时机 实例化对象,初始化的时候触发
2. 功能: 为对象添加成员
3. 参数: 参数不固定,至少一个self参数
4. 返回值: 无
基本语法
# 1.基本语法 class MyClass(): def __init__(self): print("初始化方法被触发") # 为当前对象self添加成员name self.name = "Mike" # 实例化对象 obj = MyClass() # 初始化方法被触发 print(obj.name) # Mike
带有多个参数的构造方法
# 2.带有多个参数的构造方法 class MyClass(): def __init__(self,name): # self.成员名 = 参数 self.name = name # 实例化对象 obj = MyClass("Mike") # 在实例化对象的时候,给构造方法传递参数 print(obj.name) # Mike
类可以是一个,对象可以是多个
1. 一个类可以实例化多个不同的对象
2. 对象和对象之间彼此独立
3. 但都可以使用类中的公有成员
class Children(): def __init__(self, name, skin): self.name = name self.skin = skin def cry(self): print("小孩一出生就哇哇哇的哭") def drink(self): print("小孩一下生就要喝奶奶") def __la(self): print("小孩拉粑粑是私有的") def pub_info(self): print("该对象的名字是{},该对象的肤色是{}".format(self.name, self.skin)) # 创建第一个小孩 afanda = Children("阿凡达", "蓝色的") afanda.pub_info() afanda.cry() # 创建第二个小孩 afanti = Children("阿凡提", "黄色的") afanti.pub_info() afanti.drink() # 创建第三个小孩 bao = Children("我滴宝强", "绿色的") bao.pub_info() # bao.__la() # 无法在类外调用私有的成员
部分三:
多态模式
什么是多态?
不同的子类对象,屌用相同的父类方法,产生不同的执行结果
多态的关键字: 基础和改写
栗子:
# 定义Soldier类,让空军陆军海军继承这个类 class Soldier(): def attack(self): pass def back(self): pass # 陆军 class Army(Soldier): def attack(self): print("[陆军]搏击,ufc,无限制格斗,太极,八卦,占星,制作八卦符") def back(self): print("[陆军]白天晨跑10公里,也行800百公里") # 海军 class Navy(Soldier): def attack(self): print("[海军]潜泳水下30个小时,手捧鱼雷,亲自送到敌人的老挝,炸掉敌人的碉堡") def back(self): print("[海军]每小时在海底夜行800公里,游的比鲨鱼还快") # 空军 class AirForce(Soldier): def attack(self): print("[空军]空中夺导弹,手撕飞机,在空中打飞机,精准弹幕") def back(self): print("[空军]高中跳伞,落地成盒") # 实例化陆军对象 army_obj = Army() # 实例化海军对象 navy_obj = Navy() # 实例化空军对象 af_obj = AirForce() lst = [army_obj,navy_obj,af_obj] # 对象列表 strvar = """ 1.所有兵种开始攻击训练 2.所有兵种开始撤退训练 3.空军练习攻击,其他兵种练习撤退 """ print(strvar) num = input("将军请下令,选择训练的种类") for i in lst: if num == "1": i.attack() elif num == "2": i.back() elif num == "3": if isinstance(i,AirForce): i.attack() else: i.back() else: print("将军~ 风太大 我听不见~") break
__new__ 魔术方法
关于关于魔术方法__new__
1. 触发的时机: 实例化类生成对象的时候触发( 触发时机在 __init__ 之前)
2. 功能: 控制对象的创建流程
3. 参数: 至少一个cls 接收当前的类,其他根据实际情况决定
4. 返回值: 通过返回对或None
基本语法
# (1)基本语法 class MyClass2(): pty = 100 obj2= MyClass2() class MyClass(): def __new__(cls): print(cls) # 类.方法(自定义类) => 借助父类object创建MyClass这个类的对象 obj = object.__new__(cls) # (1) 借助父类object创建自己类的一个对象 return obj # (2) 返回其他类的对象 return obj2 # (3) 不返回任何对象 return None obj = MyClass() print(obj)
__new__触发时机快于构造方法
__new__ 用来创建对象
__init__ 用来初始化对象
先创建对象,才能在初始化对象,所以__new__快于__init__
class Boat(): def __new__(cls): print(2) return object.__new__(cls) def __init__(self): print(1) obj = Boat() # 因为__new__比__init__先执行,所以会先打印2后打印1.
__new__ 和 __init__ 参数一一对应
单个参数的情况
class Boat(): def __new__(cls,name): return object.__new__(cls) def __init__(self,name): self.name = name obj = Boat("友谊的小船说裂开就裂开") print(obj.name)
多个参数的情况
# 当__init__参数很多的时候,在__new__方法使用*args和**kwargs收集所有的参数!! class Boat(): def __new__(cls,*args,**kwargs): return object.__new__(cls) def __init__(self,name,color,shangpai): self.name = name self.color = color self.shangpai = shangpai obj = Boat("泰坦尼克号","屎绿色","京A66688") print(obj.name) print(obj.color) print(obj.shangpai)
关于 __new__ 的注意点
如果返回的对象不是本类中的对象,不会触发本类的构造方法
"""如果返回的对象不是自己本类中的对象,不会触发本类的构造方法""" class MyClass(): pty = 200 obj = MyClass() class Boat(): def __new__(cls,*args,**kwargs): return object.__new__(cls) # 返回的是自己类的对象,会触发__init__方法 # return obj # 返回的不是自己的对象,所以不会触发下面的__init__方法 # return None # 没有返回对象,不可能触发__init__方法 def __init__(self): print("构造方法被触发") obj = Boat() print(obj)
单态模式
什么是单态?
一个类,无论实例化多个对象,都有且只有一个对象
单态模式的应用场景
优点: 节省内存空间,提升执行效率
针对于不要额外对该对象添加成员的场景(比如: mysql 曾删改查)
基本语法
class SingleTon(): __obj = None def __new__(cls): if cls.__obj is None: # 把创建出来的对象赋值给私有成员__obj cls.__obj = object.__new__(cls) return cls.__obj obj1 = SingleTon() obj2 = SingleTon() obj3 = SingleTon() print(obj1,obj2,obj3) """ 第一次实例化对象时候, 创建一个对象赋值给cls.__obj,返回 cls.__obj 第二次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 第三次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 """
单态模式+ 构造方法
class SingleTon(): __obj = None def __new__(cls,*args,**kwargs): if cls.__obj is None: cls.__obj = object.__new__(cls) return cls.__obj def __init__(self,name): self.name = name obj1 = SingleTon("A") obj2 = SingleTon("B") print(obj1.name) print(obj2.name) # 打印出来的是两个B,原因如下 ''' obj1 = SingleTon(宋云杰) self.name = "A" obj2 = SingleTon(戈隆) self.name = "B" self 代表的是本对象 第一次实例化对象时候,创建一个对象,赋值name为A 第二次实例化对象时候,因为 cls.__obj is None不满足,返回上一个创建好的对象 为上一个对象的name这个属性赋值 为B obj1 和 obj2 所指代的对象是同一个对象 obj1.name => B obj2.name => B 其实有些相当于是B把A覆盖了,因为B和A指向同一个对象 '''
连贯操作
连贯操作,通过在类中的__init__ 方法中传入obj对象,进行实现对象.属性的这种连贯操作
通过 不停的调用下一个对象的操作就是连贯操作
基础版
class MyClass1(): pth1 = 10 class MyClass2(): def __init__(self,obj): self.obj = obj obj = MyClass1() obj2 = MyClass2(obj) # 对象.对象.属性 # obj2.obj = obj # obj.pth1 = 10 print(obj2.obj.pth1) # 10
升级版
class MyClass1(): pty1 = 101 def func1(self): print("我是func1函数") class MyClass2(): def __init__(self,obj): self.pty2 = obj def func2(self): print("我是func2函数") class MyClass3(): pty3 = 103 def __init__(self,obj): self.pty3 = obj def func2(self): print("我是func3函数") obj1 = MyClass1() obj2 = MyClass2(obj1) obj3 = MyClass3(obj2) # 使用obj3调用func1方法? # 对象.pty3 => obj2 | obj2.pty2 => obj1 | obj1.func1() obj3.pty3.pty2.func1() print(obj3.pty3.pty2.pty1) obj3.pty3.func2()
小人射击
用面向对象的思想完成该程序,要求
1. 子弹可以装载到弹夹中
2. 弹夹可以装载到枪支中
3. 人具有拿枪射击的功能,也可以换子弹
小人射击的文件结构
小人射击项目的代码实现
main.py (主函数)
# ### 小人射击 """面向对象的核心思想: 把对象当做程序中的一个最小单元,让对象操作一切""" """ 弹夹: 属性: 子弹数量 bulletcount 方法: 无 枪 : 属性: 弹夹 方法: 射击 shoot 人 : 属性: 枪 方法: (1) 射击 (2) 换子弹 """ from package.bulletbox import BulletBox from package.gun import Gun from package.person import Person # 先创建弹夹 danjia = BulletBox(20) # 在创建一杆枪 ak47 = Gun(danjia) # 在创造一个人 songyunjie = Person(ak47,"宋云杰") # 小人射击 if __name__ == "__main__": # 射击 songyunjie.fire(15) # 填充 songyunjie.fillcount(10) # 在射击 songyunjie.fire(150)
bullerbox.py (弹夹)
# ### 弹夹类 class BulletBox(): def __init__(self,bulletcount): self.bulletcount = bulletcount
gun.py(抢)
# ### 枪类 class Gun(): def __init__(self,bulletbox): # 存放的是弹夹对象 self.bulletbox = bulletbox def shoot(self,shootcount): if self.bulletbox.bulletcount < shootcount: print("对不起,请先填充子弹~") else: # 剩余的子弹 = 总的子弹数量 - 射击的数量 self.bulletbox.bulletcount -= shootcount print("突" * shootcount , "你射出了{}发,还剩下{}发".format(shootcount,self.bulletbox.bulletcount))
person.py( 人)
# ### 人类 class Person(): def __init__(self,gun,name): self.gun = gun self.name = "宋云杰" # 填充子弹 def fillcount(self,fillnum): # 往弹夹里面赛子弹 # self.枪对象 -> 弹夹对象 -> 弹夹数量属性 self.gun.bulletbox.bulletcount += fillnum # 射击 def fire(self,num): print("{}此刻正在野外射击~".format(self.name)) # 枪对象.shoot self.gun.shoot(num)
关于小人射击项目的总结
在小人项目中,要时刻遵循面向对象的西想
1. 在主函数 main.py 中, 不要写任何逻辑,只能写对象,让对象来操作一切
2. 采用连贯操作,虽然实例化了三个对象,但是在调用方法的时候,只需要用一个对象,去调用所有类中的方法
模塑方法与类相关的魔术属性
魔术方法
__del__(析构方法)
1.触发时机: 当对象被内存回收的时候自动触发
(1) 页面执行完毕回收所有变量
92) 所有对象被del的时候
2. 功能: 对象使用完毕后资源回收
3.参数: 一个self接收对象
4.返回值:无
第一种情况
class LangDog(): food = "改吃蔬菜" def __init__(self, name): self.name = name def __del__(self): print("析构方法被触发") print("0001=====") obj = LangDog("肉丝") print("0002=====") # 1.页面执行完毕回收所有变量 print(obj.name) # 当执行完这句话后,才算页面执行完毕,这个时候触发__del__析构方法 ''' 运行结果: ===== ===== 肉丝 析构方法被触发 '''
第二种情况
如何;理解第二种情况中所说到的所有对象
class LangDog(): food = "改吃蔬菜" def __init__(self, name): self.name = name def __del__(self): print("析构方法被触发") obj1 = LangDog("肉丝") obj2 = obj1 print("<=====start=====>") del obj1 print("<=====end=====>")
执行结果
虽然obj1 对象被删除了,但是obj2 对象并没有被删除,所以不会触发析构方法
打印了"析构方法被触发' 是因为整个页面执行完毕了,也会触发析构方法
__del__
# 3.模拟文件操作 import os class ReadFile(): def __new__(cls,filename): if os.path.exists(filename): # 判断文件路径是否存在 return object.__new__(cls) # 如果文件存在,创建文件对象 else: return print("该文件是不存在的") # 如果文件不存在,给予错误提示 def __init__(self,filename): # 打开文件 self.fp = open(filename,mode="r+",encoding="utf-8") def readcontent(self): # 读取文件 return self.fp.read() def __del__(self): # 关闭文件 self.fp.close() obj = ReadFile("1.txt") if obj is not None: res = obj.readcontent() print(res) else: print("没有该类文件") # 当然,也可以用三元运算符来实现 """ 真值 if 条件表达式 else 假值 """ print(obj.readcontent()) if obj is not None else print("没有该类文件")
__str__
1. 触发时机: 使用print(对象) 或者str(对象) 的时候触发
2. 功能: 查看对象
3. 参数: 一个self接收当前对象
4. 返回值: 必须返回字符串类型
class Cat(): gift = "小猫咪会卖萌求猫粮,小猫咪抓老鼠" def __init__(self,name): self.name = name def __str__(self): return self.cat_info() def cat_info(self): return "小猫咪的名字是{},小猫咪{}元".format(self.name,5000) # __repr__ = __str__ tom = Cat("汤姆") # 方法一. print(对象) print(tom) # 方法二. str(对象) res = str(tom) print(res)
__repr__
1. 触发时机:使用repr(对象)的时候触发
2. 功能: 查看对象,与魔术方法__str__相似
3. 参数: 一个self接受当前对象
4.返回值:必须返回字符串类型
class Mouse(): gift = "偷粮食" def __init__(self,name): self.name = name def __repr__(self): return self.mouse_info() def mouse_info(self): return "名字是{},龙生龙,凤生凤,老鼠的儿子会打洞,还会{}".format(self.name,self.gift) # 系统在底层,自动加了一句赋值操作 __str__ = __repr__ jerry = Mouse("杰瑞") res = repr(jerry) print(res) # 因为系统底层赋值的原因,在打印对象或者强转对象为字符串的时候,仍然可以触发; print(jerry) res = str(jerry) print(res)
__call__
1. 触发时机: 把对象当做函数调用对的时候自动触发
2. 功能: 模拟函数化操作
3. 参数: 参数不固定,至少一个self参数
4. 返回值: 看需求
基本用法
# (1) 基本用法 class MyClass(): a = 1 def __call__(self): print("call魔术方法被触发了") obj = MyClass() # 实例化一个对象 obj() # 把对象当做函数调用,此时会触发__call__方法
模拟洗衣服的过程
# (2) 模拟洗衣服的过程 class Wash(): def __call__(self,something): print("我现在要洗{}".format(something)) self.step1() self.step2() self.step3() return "洗完了" def step1(self): print("加热水,家洗衣粉,加洗衣液,加洗涤剂") def step2(self): print("衣服泡进去搅乱 打散 搓一搓~ ") def step3(self): print("脱水,穿上") obj = Wash() # 方法一 # obj.step1() # obj.step2() # obj.step3() # 方法二 res = obj("衣服") # 把对象obj当做函数进行调用,此时触发__call__方法,执行__call__方法所有内容 print(res)
模拟内置的int方法,实现相应的操作
# (3) 模拟内置int 实现相应的操作 import math class MyInt(): def calc(self,num,sign=1): # print(num,sign) # 去掉左边多余的0 strvar = num.lstrip("0") # print(strvar) # 为了防止都是0 ,如果去掉之后为空,返回0 if strvar == "": return 0 # 正常情况下,执行存数字字符串变成数字 , 在乘上相应的符号,得出最后的结果 return eval(strvar) * sign def __call__(self,num): if isinstance(num , bool): if num == True: return 1 elif num == False: return 0 elif isinstance(num,int): return num elif isinstance(num,float): # 方法一 """ strvar = str(num) lst = strvar.split(".") return eval(lst[0]) """ # 方法二 """ if num >= 0: return math.floor(num) else: return math.ceil(num) """ return math.floor(num) if num >= 0 else math.ceil(num) elif isinstance(num,str): if (num[0] == "+" or num[0]== "-") and num[1:].isdecimal(): if num[0] == "+": sign = 1 else: sign = -1 return self.calc(num[1:],sign) elif num.isdecimal(): return self.calc(num) else: return "老铁,这个真转不了" myint = MyInt() # myint(5) => 5 # myint(3.14) => 3 res = myint(True) print(res) res = myint(100) print(res) res = myint(3333.14) print(res, type(res)) # 3 # bool int float "12312312323" # int(3.14) => 3 print(int(3.14)) # 3 print(int(-3.14)) # -3 print("<===>") print(myint(3.14)) print(myint(-0.2)) print("<===>") print(int("0000000000000000000000000000000000000000001230000000")) print(int("00000000000000000000000000000000000000000"),"1111222333") print(int("+000000000000000000000000000000000000000000123")) print(int("-000000000000000000000000000000000000000000123")) print(int("000000000000000000000000000000000000000000123")) print("<==111=>") print(myint("+000000000234")) print(myint("000000000000000000000000000000000000000000123")) print(myint("456899200")) print(myint("3.143434")) print(myint(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>") print(int(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>") """ exec("a = 3") print(a) eval("4") """ # print(math.floor(0.14)) # 0 # print(math.floor(3.14)) # 3 # print(math.ceil(-3.14)) # -3
__bool__
1. 触发时机: 使用bool(对象) 的时候自动触发
2. 功能:强转对象
3. 参数: 一个self接收当前对象
4. 返回值: 必须是布尔类型
class MyClass(): def __bool__(self): return False obj = MyClass() res = bool(obj) print(res)
类似的还有如下(了解)
__complexx__(self) 被complex强转对象时调用
__int__ (self)被int强转对象时使用
__float__(self) 被float强化对象时调用
__add__和__radd__
1. 触发时机:使用对象进行运行算相加的时候自动触发
2. 功能: 对象运算
3. 参数: 俩个对象参数
4. 返回值: 运算后的值
5. 注意点:
对象在加号+的左侧时,自动触发__add__ 方法
对象在加号+的右侧时,自动触发__radd__方法
加号左侧和右侧都是对象时,先触发_add__方法,再触发__radd__方法
class MyClass1(): def __init__(self,num): self.num = num # 对象在加号+的左侧时,自动触发 def __add__(self,other): # print(self) # print(other) return self.num + other # return 10 + 7 = 17 # 对象在加号+的右侧时,自动触发 def __radd__(self,other): # print(self) # print(other) return self.num * 2 + other # 第一种 a = MyClass1(10) res = a + 7 print(res) # 第二种 b = MyClass1(5) res = 20 + b print(res) # 第三种 print("<============>") res = a+b print(res) """ 第一次触发魔术方法, a+ =>触发__add__方法 self => a other => b self.num + other => a.num+ b => 10 + b res = 10 + b 第二次触发魔术方法 __radd__ self => b other=> 10 self.num * 2 + other => b.num*2 + other => 5 * 2 + 10 => 20 res = 20 """
类似的还有如下(了解)
__sub__(self,other) 定义减法的行:-
__mul__(self,other)定义乘法的行为:*
__truediv__(self,other) 定义除法的行为;/
__len__
1. 触发时机: 使用len(对象)的时候自动触发
2. 功能: 用于检测对象中或者类中成员的个数
3.参数: 一个self接收当前对象
4.返回值: 必须返回整型
class MyClass(): pty1 = 1 pty2 = 2 __pty3 = 3 pyt3 =10 pty100 = 90 def func1(): pass def __func2(): pass def __func3(): pass def __len__(self): lst = [] dic = MyClass.__dict__ # 方法一 # print(MyClass.__dict__) # 获取类当中的所有成员 # print(object.__dict__) # 获取对象中的所有成员 dic = MyClass.__dict__ # 遍历类中所有成员 for i in dic: # 遍历类中所有成员 if not(i.startswith("__") and i.endswith("__")): # 如果开头和结尾都不是以双下划线结尾 lst.append(i) # 将符合条件的成员添加到列表中 return len(lst) # 方法二 lst = [i for i in dic if not(i.startswith("__") and i.endswith("__"))] return len(lst)
与类相关的魔术属性
__dict__获取对象或类的内部成员结构
__doc__获取对象或类的内部文档
__name__获取类名函数名
__class__获取当前对象所属的类
__bases__获取一个类直接继承的所有父类,返回元祖
class Man(): pass class Woman(): pass class Children(Man,Woman): """ 功能: 描述小孩天生的属性 成员属性:eye , skin 成员方法:skylight , moonread , __makebaby """ eye = "万花筒血轮眼" skin = "白色" def skylight(self): print("宇智波家族的小孩,天生能够发动天照技能") def moonread(self,func): # func = func111 print("宇智波家族的小孩,能够发动月亮的光照消灭你~") res = func.__name__ print(res,type(res)) def __makebaby(self): print("这一手招数,只能我自己用") # __dict__ 获取对象或类的内部成员结构 obj = Children() print(obj.__dict__) print(Children.__dict__) # __doc__ 获取对象或类的内部文档 print(obj.__doc__) print(Children.__doc__) # __name__ 获取类名函数名 def func111(): print("我是func111方法") # 获取函数名 obj.moonread(func111) # 获取类名 obj.moonread(Man) # __class__ 获取当前对象所属的类 print(obj.__class__) # __bases__ 获取一个类直接继承的所有父类,返回元组 print(Children.__bases__)
装饰器和面相对象中的方法,property
装饰器
1. 装饰器: 在原函数去扩展新的功能,用新函数去替换旧函数
2. 作用: 在不改变原代码的前提下,实现功能上的扩展
3. 符号: @ (语法糖)
装饰器的基本使用
# 1.装饰器的基本用法 '''装饰器是基于闭包函数来实现的''' def kuozhan(func): def newfunc(): print("厕所前,蓬头垢面") func() print("厕所后,精神抖擞") return newfunc def func(): print("我是宋云杰") '''kuozhan()的返回值是newfunc,newfunc替换了func''' func = kuozhan(func) # func = newfunc '''所以调用func就是相当于在调用newfunc''' func() # newfunc()
@符号的使用
@符号的作用:
(1)可以自动把@符号下面的函数当成参数传递给装饰器
(2) 把新函数返回,让新函数去替换旧函数,以实现功能上的扩展(基于原函数)
# 2.@符号的使用 """ @符号作用: (1) 可以自动把@符号下面的函数当成参数传递给装饰器 (2) 把新函数返回,让新函数去替换旧函数,以实现功能上的扩展(基于原函数) """ def kuozhan(func): def newfunc(): print("厕所前,牛头马面") func() print("厕所后,黑白无常") return newfunc '''1.把func当做参数传递给装饰器kuozhan''' '''2.将新函数newfunc返回替换旧函数func,进而实现功能的扩展''' @kuozhan def func(): print("我是高雪峰") func()
装饰器的嵌套
# 3.装饰器的嵌套 def kuozhan1(func): def newfunc(): print("厕所前,人模狗样1") func() print("厕所后,斯文败类2") return newfunc def kuozhan2(func): def newfunc(): print("厕所前,洗洗手3") func() print("厕所后,簌簌口4") return newfunc @kuozhan2 @kuozhan1 def func(): print("我是葛龙0") func()
用装饰器扩展带有参数的原函数
# 4.用装饰器扩展带有参数的原函数 def kuozhan(func): def newfunc(who,where): print("厕所前,萎靡不振") func(who,where) print("厕所后,兽性大发") return newfunc @kuozhan def func(who,where): print("{}在{}解手".format(who,where)) func("孙致和","鸟窝") # func = newfunc => func("孙致和","鸟窝") <=> newfunc("孙致和","鸟窝")
用装饰器扩展带有参数和返回值的原函数
# 5.用装饰器扩展带有参数和返回值的原函数 def kuozhan(func): def newfunc(*args,**kwargs): print("厕所前,饥肠辘辘") res = func(*args,**kwargs) print("厕所后,酒足饭饱") return res return newfunc @kuozhan def func(*args,**kwargs): lst = [] dic = {"gaoxuefeng":"高雪峰","sunzhihe":"孙致和","gelong":"戈隆"} # 解手的地点遍历出来 for i in args: print("拉屎的地点:",i) for k,v in kwargs.items(): if k in dic: strvar = dic[k] + "留下了" + v + "黄金" lst.append(strvar) return lst lst = func("电影院","水下",gaoxuefeng = "15g",sunzhihe = "15顿",gelong="15斤") print(lst)
用类装饰器扩展原函数
# 6.用类装饰器来拓展原函数 class Kuozhan(): def __call__(self,func): return self.kuozhan2(func) def kuozhan1(func): def newfunc(): print("厕所前,老实巴交") func() print("厕所后,咋咋乎乎") return newfunc def kuozhan2(self,func): def newfunc(): print("厕所前,唯唯诺诺") func() print("厕所后,重拳出击") return newfunc # 方法一 """""" @Kuozhan.kuozhan1 def func(): print("厕所进行中....") func() # 方法二 @Kuozhan() # @obj => obj(func) def func(): print("厕所进行中....") func()
带有参数的函数装饰器
# 7.带有参数的函数装饰器 def outer(num): def kuozhan(func): def newfunc1(self): print("厕所前,干净整齐") func(self) print("厕所后,一片狼藉") def newfunc2(self): print("厕所前,大腹便便") func(self) print("厕所后,满口雌黄") if num == 1: return newfunc1 elif num == 2: return newfunc2 elif num == 3: # 把func3方法变成属性 return "我是女性" return kuozhan class MyClass(): @outer(1) # => (1) kuozhan(func1) => newfunc1 (2) 发动技能做替换 func1 = newfunc1 def func1(self): print("向前一小步,文明一大步") @outer(2) # => (2) kuozhan(func2) => newfunc2 (2) 发动技能做替换 func2 = newfunc2 def func2(self): print("来也冲冲,去也冲冲") @outer(3) # => (3) kuozhan(func3) => "我是女性" (2) 发动技能做替换 func3 = "我是女性" def func3(self): print("hahaha,lalala") obj = MyClass() obj.func1() # <=> newfunc1 obj.func2() # obj.func3() error print(obj.func3) print(MyClass.func3)
文件解析:
1. 套上outer 这成函数就是为了保留1 2 3 三个参数,可以在闭包函数中使用
2. 调用outer 结束之后,才是返回正常的装饰器kuozhan
3. 此刻,@符第一次发动技能,把func1当成参数传递给kuozhan,返回newfunc1
4然后,@符第二次发动技能,将返回的newfunc1替换原来func1
if num == 1 返回闭包函数newfunc1
if num == 2 返回闭包函数newfunc2
来替换
obj.func3 在执行时,装饰器已经把func3 变成了属性 func3 = '我是女性'
所以obj.func3 或者 MyClass3 都是"我是女性" 字符串
obj.func3 => return"我是女性'
MyClass.func3 => return '我是女性"
带有参数的类装饰器
如果参数是1 ,就为当前类添加成员属性和方法
如果参数是2 , 就把原方法run变成属性
# 8.带有参数的类装饰器 """ 如果参数是1,就为当前类添加成员属性和方法 如果参数是2,就把原方法run变成属性 """ class Kuozhan(): money = "贵族厕所,每小时1000元,贵族厕所欢迎您来,欢迎您再来" def __init__(self,num): self.num = num def __call__(self,cls): if self.num == 1: return self.newfunc1(cls) elif self.num == 2: return self.newfunc2(cls) def ad(self): print("贵族茅厕,茅厕中的百岁山") def newfunc1(self,cls): def newfunc(): # 为当前cls这个类,添加属性 cls.money = Kuozhan.money # 为当前cls这个类,添加方法 cls.ad = Kuozhan.ad return cls() return newfunc def newfunc2(self,cls): def newfunc(): if "run" in cls.__dict__: # 调用类中的方法,得到对应的返回值 res = cls.run() # 把返回值重新赋值到run属性上 cls.run = res# cls.run = "亢龙有悔" return cls() return newfunc
# 参数1 @Kuozhan(1) class MyClass(): def run(): return "亢龙有悔" obj = MyClass() print(obj.money) obj.ad() # 参数2 @Kuozhan(2) class MyClass(): def run(): return "亢龙有悔" obj = MyClass() print(obj.run)
注意点: 把类当做参数传递到函数中
class Ceshi(): ad = 10 obj = Ceshi() print(obj.ad) # 10 def func(cls): cls.money = 100 return cls() # 把类当成参数传递到函数当中,在局部空间中,形成独立的副本 obj = func(Ceshi) # 把类变量Ceshi 变成字符串 Ceshi = "abcde" # 发现局部空间中类对象中的成员,并没有受到影响 print(obj.money) # 100
面型对象中的方法
普通方法:有参或者无参,如果是无参,只能类来调用(因为对象调用会自动把obj对象当做参数传递进去)
绑定方法
(1) 绑定到对象(自动传递对象参数) 类对象都可以调用
(2) 绑定到类(自动传递参数) 类和对象都可以调用,但是推荐使用类来调用 使用装饰器@classmethod
静态方法:
无论是对象还是类,都可以调用此方法,而不会默认传递任何参数 使用装饰器@staticmethod
class Cat(): name = "tom" # 普通方法 def mai_meng(): print("小猫会卖萌") # 绑定方法(对象) def attack(self): print("小猫会卅(sua)人") # 绑定方法(类) @classmethod def youmi(cls): print(cls) print("可以放大招,伤害最高") # 静态方法 @staticmethod def jump(a,b,c,d,e): print("小猫会上树,抓老鼠") obj = Cat() # 普通方法 (无参方法只能类调用) Cat.mai_meng() # obj.mai_meng() error # 绑定方法(对象) obj.attack() Cat.attack(obj) # 绑定方法(类) """对象和类都可以调用绑定到类的方法 推荐使用类来调用""" Cat.youmi() obj.youmi() # print(obj.__class__) # 静态方法 obj.jump() Cat.jump()
Property
Property 可以把方法变成属性使用
作用; 控制属性的获取,修改,删除等操作
变向的增加成员的安全性,可以通过自定义的逻辑进行控制
自动触发: 要求名字相同,同一个名字
获取:@porperty
设置: @属性名.setter
删除: @属性名: deleter
方式一
# 写法一 class MyClass(): def __init__(self,name): self.name = name @property def username(self): return self.name # pass # 不获取 @username.setter def username(self,val): # 在触发时:val = 朴飘乐 self就是本对象 self.name = val # pass # 不设置 @username.deleter def username(self): # print("删除方法被触发...") del self.name # pass # 不删 obj = MyClass("朴一生") # 获取属性 print(obj.username) # 设置属性 obj.username = "朴飘乐" # 获取属性 print(obj.username) # 删除属性 del obj.username
方式二
# 写法二 class MyClass(): def __init__(self,name): self.name = name # 获取方法 def get_username(self): return self.name # pass # 不获取 # 设置方法 def set_username(self,val): self.name = val # pass # 不获取 # 删除方法 def del_username(self): # del self.name pass # property(获取方法,设置方法,删除方法) username = property(get_username,set_username,del_username) # 这三个顺序不可以调换 obj = MyClass("朴仁猛") # 获取操作 print(obj.username) # 自动触发get_username方法 # 设置操作 obj.username = "pdd" # 自动触发set_username方法 # 删除操作 del obj.username # 自动触发del_username方法
标签:__,obj,Python,self,高级,对象,第二部,print,def 来源: https://www.cnblogs.com/f211/p/13911093.html