【python基础语法十】面向对象

面向对象的程序开发

"""
用几大特征表达一类事物称为一个类,类更像是一张图纸,表达的是一个抽象概念
对象是类的具体实现,更像是由这图纸产出的具体物品,类只有一个,但对象可以通过这个类实例化出多个
对象是类的实例,类是对象的模板
*类中的成员只有方法和属性,不要裸露的把判断和循环直接写在类中,而是用方法包起来

(1)类的定义
(2)类的实例化
(3)类的基本结构
(4)类的命名
"""

1. 类的定义

# 1
class Car:
	pass
	
# 2 推荐
class Car():
	pass
	
# 3.
class Car(object):
	pass

2. 类的实例化

class Car():
	pass
	
obj = Car()
print(obj)

3. 类的基本结构

"""
类中两样东西:
	(1)成员属性
	(2)成员方法
"""
class Car():
	# 成员属性
	color = "白色"
	# 成员方法
	def didi():
		print("小车会滴滴的叫")
		
# 语法上不报错,但是严禁使用,破坏了类中的结构,不要裸露的把判断和循环直接写在类中,而是用方法包起来
class Car():
	if 5 ==5 :
		print(11223344)

4. 类的命名

"""类的命名 : 推荐使用大驼峰命名法,每个单词的首字母都要大写"""
"""
mycar => MyCar
zhangbaozhang => ZhangBaoZhang
"""

面向对象三大特征: 封装 继承 多态

封装

对类中成员属性和方法的保护,控制外界对内部成员的访问,修改,删除等操作

对象的操作

"""
封装:
	1.私有 : 在类内可以互相访问,在类外不能访问
	2.公有 : 在类内或者类外都可以访问

类中成员:
	1.成员属性
	2.成员方法
	
绑定方法:
	1.绑定到对象 : 当对象去调用类中成员方法时,系统会默认把该对象当成参数传递给该方法
	2.绑定到类   : 当对象或者类去调用类中成员方法时,系统会默认把该类当成参数传递给该方法

使用方式:
	对象.成员属性
	对象.成员方法
"""

class MyCar():
	# 公有属性
	logo = "布加迪威龙"
	
	# 私有属性, 前面加两个下划线
	__price = "2000万"
	
	# 公有方法
	def run(self): # 必须要写上一个形参。调用时自动传参(强制操作)
		print("百公里油耗300L,logo={} , price={}".format(self.logo, self.__price))

	# 私有方法
	def __info(self):
		print("车主信息保密,据说是某个房地产大佬的儿子")

# 实例化对象(类的实例化)
obj = MyCar()

# (1)实例化的对象访问成员属性和方法
# 公有
print(obj.logo)
obj.run()

# 私有 (私有成员无法在类外访问,类内可以)
# obj.__price # error
# obj.run()
# obj.__info() # error


#(2)实例化的对象动态添加公有成员属性
obj.color = "黄色"
obj.logo = "五菱宏光" 
print(obj.color)
print(obj.logo)

# __dict__ 获取类对象的内部成员
print(obj.__dict__)
print(MyCar.__dict__)

#(3)实例化的对象动态添加公有成员方法

# 1.无参方法 (类外定义的方法,不会强制传参)
def dahuangfeng():
	print("请加我大黄蜂")

obj.dahuangfeng = dahuangfeng
obj.dahuangfeng()

# 2.有参方法
# 基本版
def qingtianzhu(name):
	print("请叫我一柱擎天么,{}".format(name))
	
obj.qingtianzhu = qingtianzhu
obj.qingtianzhu("擎天柱")

# 升级版
def qingtianzhu(obj,name):
	print("请叫我一柱擎天么,{},我的颜色是{}".format(name,obj.color))

obj.qingtianzhu = qingtianzhu
obj.qingtianzhu(obj,"擎天柱")

# 究极版
"""如果要创建绑定方法,参数的顺序,self对象本身要放到第一位."""
def qingtianzhu(obj,name):
	print("请叫我一柱擎天么,{},我的颜色是{}".format(name,obj.color))

import types
# 创建绑定方法,系统自动把该对象当成参数传递给方法;
# types.MethodType(方法,对象) => 绑定方法   
res = types.MethodType(qingtianzhu,obj)
print(res) # <bound method qingtianzhu of <__main__.MyCar object at 0x77>>

# 自动将obj作为参数传给该方法
obj.qingtianzhu = types.MethodType(qingtianzhu,obj)
obj.qingtianzhu("擎天柱")

# 3.lambda表达式
obj.weizhentian = lambda : print("我是威震天")
obj.weizhentian()

类的操作

"""
使用方式:
	类.成员属性
	类.成员方法
"""
class MyCar():
	
	# 公有成员属性
	platenum = "京A7758BB"
	
	# 私有成员属性
	__earning = "月收入6000"
	
	# 公有成员方法
	def car_info():
		print("牌照信息可以公开")
		print("<======>")
		MyCar.__money_info()
	
	# 私有成员方法
	def __money_info():
		print( "收入信息保密" , MyCar.__earning )
		

# (1)定义的类访问公有成员属性和方法
print(MyCar.platenum)
MyCar.car_info()

# MyCar.__money_info() error
	
# (2)定义的类动态添加公有成员属性
MyCar.oil = "1000L"
print(MyCar.oil)
print(MyCar.__dict__)

# (3)定义的类动态添加公有成员方法
# 1.无参方法
def car_light():
	print("我是造车灯的方法")
MyCar.car_light = car_light
MyCar.car_light()

# 2.有参方法
def car_engine(name):
	print("我是造{}发动机的方法".format(name))
MyCar.car_engine = car_engine
MyCar.car_engine("三缸发动机")

# 3.lambda表达式
MyCar.luntai = lambda : print("我是造轮胎的方法")
MyCar.luntai()


# 对比 对象和类之间的不同
"""
1.类中的无参方法默认只能类来调用,对象无法调取
2.对象可以调用类中的成员,反过来,类不能调用对象中的成员
3.每创建一个对象都会在内存中占用一份空间,对象之间是彼此独立的;
"""
obj = MyCar()
# obj.car_info() error
MyCar.car_info()

obj.price = "10万"
print(MyCar.price)

如何在类外访问私有成员

class Plane():
	# 公有成员
	captian = "赵沈阳"
	
	# 私有成员
	__air_sister = "3名空姐"
	
	# 公有绑定方法
	def fly(self):
		print("飞机要非要平流层,才能减少震动",self.__air_sister)
		
	# 私有绑定方法
	def __age(self):
		print("空姐年龄保密")
		
	# 公有无参方法
	def fly2():
		print("航天飞机飞到天空层,翱翔太空")
	
	# 私有无参方法
	def __earn():
		print("机长的收入保密")
		
	def pub_get1(self):
		print(self.__air_sister)
		self.__age()
		
	def pub_get2():
		print(Plane.__air_sister)
		Plane.__earn()

# 实例化对象
obj = Plane()

# 方法一.访问私有成员 (不推荐)
# python私有化: 采取了改名策略 =>  _类名 + __air_sister
# print(obj.__air_sister) # 报错
print(obj._Plane__air_sister)
print(Plane.__dict__)

# 方法二.访问私有成员 (使用类中的公有方法,间接访问私有成员) (推荐)
obj = Plane()
obj.pub_get1()
Plane.pub_get2()

使用类对象删除相应的成员

"""
1.对象可以访问类中的公有成员,但是无权修改或者删除该类中的成员
2.对象在访问成员时,优先访问该对象自己的成员,如果没有在访问类的,类如果也没有直接报错;
"""
# 删除对象成员属性
obj.captian = "赵世超"
del obj.captian
print(obj.captian)

# 删除对象成员方法
obj.basketball = lambda : print("我的私人飞机可以在天上打篮球")
print(obj.__dict__)
obj.basketball()
del obj.basketball
print(obj.__dict__)
# obj.basketball() # error

# 删除类中成员属性
del Plane.captian
print(Plane.__dict__)
# Plane.captian # error
# print(obj.captian) # error

# 删除类中成员方法
del Plane.fly2
# Plane.fly2() # error

# 注意: 对象无法调无参方法!! 反过来,类可以调用对象的绑定方法么? 可以!!
Plane.fly(obj)

__init__ 构造方法

'''
	触发时机:实例化对象,初始化的时候触发
	功能:为对象添加成员
	参数:参数不固定,至少一个self参数
	返回值:无
'''

# (1) 基本语法
class MyClass():
	def __init__(self):
		print("构造方法被触发 ... ")
		self.color = "屎黄色"
		
# 实例化对象
obj = MyClass()
print(obj.__dict__)
print(obj.color)

# (2) 带有多个参数的构造方法
class MyClass():
	def __init__(self,color):
		self.color = color

# 实例化对象
obj1 = MyClass("狗屎绿")
print(obj1.color)
obj2 = MyClass("粉嫩红")
print(obj2.color)

# (3)类可以是一个,对象可以是多个,创造的对象彼此是独立的;
class Children():
	def __init__(self,name,skin):
		self.name = name
		self.skin = skin
	
	def cry(self):
		print("小孩一下生久哇哇哇的哭")
	
	def la(self):
		print("小孩一下生久拉粑粑")
		
	def __eat(self):
		print("小孩一下生就要吃奶奶..")
	
	def info(self):
		print("小孩的名字:{},小孩的肤色{}".format(self.name,self.skin))
		
	def info2(self,name,skin):
		print("小孩的名字:{},小孩的肤色{}".format(name,skin))


# 实例化对象
afanda = Children("阿凡达","深蓝色")
afanda.cry()
afanda.info()

haoke = Children("绿巨人","绿色的")
haoke.la()
haoke.info()

wangbaoqiang = Children("王宝强","亮绿色")
wangbaoqiang.info()
# wangbaoqiang.__eat() error
wangbaoqiang.info2("张保张","黄色")

继承

"""  
一个类除了自身所拥有的属性方法之外,还获取了另外一个类的成员属性和方法 是一种继承关系
被继承的类叫做父类(基类,超类),继承的类叫做子类(衍生类)
在python中所有类都继承object这个父类
继承: (1) 单继承  (2) 多继承
"""

单继承

class Human(object):
	eye = "黑色的"
	
	def jump(self):
		print("古代人类都能上树")
	
	def beat_animal(self):
		print("古代人类都会打猎")

	def __makefire(self): # 只能在本类内部调用
		print("古代人类会生火")
		
# (1) 子父继承之后,子类可以调用父类的公有成员
class Man(Human):
	pass
	
obj = Man()
obj.jump()

# (2) 子父继承之后,子类不能调用父类的私有成员
class Woman(Human):
	def pub_func(self):
		self.__makefire()
	
obj2 = Woman()
# obj2.__makefire()  # 报错 不行
# obj2.pub_func()    # 报错 不行 __makefire 方法调用失败

# (3) 子父继承之后,子类可以重写父类的同名公有方法
class Children(Human):
	def beat_animal(self):
		print("小孩天生只会打泡泡,不会打猎")
		
obj3 = Children()
obj3.beat_animal()

多继承

# (1) 基本语法
class Father():
	property = "风流倜傥,才华横溢,玉树临风,才高八斗,学富五车,英姿洒窗"
	def f_hobby():
		print("抽烟喝酒烫头")
	
class Mother():
	property = "倾国倾城,貌美如花,沉鱼落雁,闭月羞花,婀娜多姿,如花似玉"
	def m_hobby(self):
		print(self.property)
		print("读书看报")
		
class Daughter(Father,Mother):
	pass
	
obj = Daughter()
print(obj.property) # 存在顺序关系
obj.m_hobby()

# (2) 多继承的成员调用
class Father():
	property = "风流倜傥,才华横溢,玉树临风,才高八斗,学富五车,英姿洒窗"
	def f_hobby():
		print("抽烟喝酒烫头")
	
class Mother():
	property = "倾国倾城,貌美如花,沉鱼落雁,闭月羞花,婀娜多姿,如花似玉"
	def m_hobby(self):
		print(self.property)
		print("读书看报")

"""
(1)super本身是一个类 super()是一个对象 用于调用父类的绑定方法
(2)super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self)
(3)super用途: 解决复杂的多继承调用顺序	
"""
class Son(Father,Mother):
	property = "打游戏,吃小零食"
	
	def m_hobby(self):
		print("son中m_hobby方法")
	
	# 用类调用成员
	def skill1(self):
		Father.f_hobby()
		print(Mother.property)
		
	# 用对象调用成员
	"""self按照顺序找: 对象本身 => 类 => 父类 对应的成员 """
	def skill2(self):
		print(self.property)
		self.m_hobby()
		
	# 用super调用成员
	"""super()只调用父类的相关成员,顺带传递对象参数。不调用自己的"""
	def skill3(self):
		print(super()) # <super: <class 'Son'>, <Son object>>
		print(super().property)
		super().m_hobby()
		
obj2 = Son()
# obj2.skill1()

obj2.property = "喜欢看lol,dnf,wow,跑跑卡丁车,ddo,霸王大陆,澄海3"
# obj2.skill2()

obj2.skill3()

菱形继承 (钻石继承)

class Human():
	pty = 1
	def feelT(self):
		print("古代人类,天热了,光腚1")
		print(self.pty) # 4 3 2 1
		print("古代人类,天冷了,穿树衣2")
	
class Man(Human):
	# pty = 2
	def feelT(self):
		print("男人,天热了,光膀子3")
		print(super(),"<==2==>") # <super: <class 'Man'>, <Children object>>
		super().feelT()
		print("男人,天冷了,光腚4")
	
class Woman(Human):
	# pty = 3
	def feelT(self):
		print("女人,天热了,脱毛5")
		print(super(),"<==3==>") # <super: <class 'Woman'>, <Children object>> 
		super().feelT()
		print("女人,天冷了,穿貂6")

class Children(Man,Woman):
	# pty = 4
	def feelT(self):
		print("小孩,天热了,光腚7")
		print(super(),"<==1==>") # <super: <class 'Children'>, <Children object>>  
		super().feelT() # 将super() 对象传给feelT() 方法
		print("小孩,天冷了,多喝热水8")

# ### super的深层理解
obj = Children()
obj.feelT()
# 73512648

"""
# 菱形继承 查找方法解析原则:super() 调用时查找顺序
# mro: 方法解析顺序 (c3算法计算的)
# 语法: 类.mro() => 列表
m :method
r :resolution 
o :order
super 会自动根据mro列表返回出来的顺序关系,依次调用 
super作用:专门用于解决复杂的多继承调用顺序关系;依照mro返回的列表顺序,依次调用;
super调用的顺序:会按照c3算法的广度优先原则进行调用
super传参:会默认在调用方法时,传递该对象参数;
"""
lst = Children.mro()
print(lst)
"""
[
<class '__main__.Children'>, 
<class '__main__.Man'>, 
<class '__main__.Woman'>,
<class '__main__.Human'>, 
<class 'object'>
]
"""

内置函数 issubclassisinstance

issubclass 判断类的子父关系(应用在类与类之间)
class MyClass():
	pass
"""只要在一条继承链上满足关系即可"""
res = issubclass(Children,Man)
res = issubclass(Children,Human)
res = issubclass(Children,MyClass) # False
# 如果元组当中有一个父类满足,即返回真
res = issubclass(Children,  (Man,Human,MyClass)  )
print(res) # True
isinstance 判断对象的类型 (应用在类与对象之间)
"""只要在一条继承链上满足关系即可"""
res = isinstance(obj,Children) # True
res = isinstance(obj,Human) # True
res = isinstance(obj,MyClass) # False
# 如果元组当中有一个类满足,即返回真
res = isinstance(obj,  (Man,Human,MyClass)  )
print(res) # True

多态

不同的子类对象,调用相同的父类方法,产生不同的执行结果

"""继承 重写 """

class Soldier():
	def attack(self):
		pass
		
	def back(self):
		pass
		
# 陆军
class Army(Soldier):
	def attack(self):
		print("[陆军]开坦克装甲部队,开大炮轰炸敌方根据地,拼刺刀,手撕鬼子")
		
	def back(self):
		print("[陆军]为了一条性命,夜行八百,日行一千,回家")
	
# 海军
class Navy(Soldier):
	def attack(self):
		print("[海军]开航空母舰,扔鱼叉,撒网捆住敌人,收网")
	
	def back(self):
		print("[海军]直接跳水,下海喂鱼,原地爆炸")

# 空军
class AirForce(Soldier):
	def attack(self):
		print("[空军]空对地投放原子弹,空对空发射巡航导弹")
	
	def back(self):
		print("[空军]直接跳机,落地成盒")
	
# 创建士兵
obj1 = Army()
obj2 = Navy()
obj3 = AirForce()

# 
lst = [obj1,obj2,obj3]
# lst = [Army(),Navy(),AirForce()]

strvar = """
将军请下令:
1.全体出击
2.全体撤退
3.海军出击,其他兵种撤退
"""

num = input(strvar)
for i in lst:
	# print(i)
	if num == "1":
		i.attack() # 方法名相同,但是结果不一样
	elif num == "2":
		i.back()
	elif num == "3":
		if isinstance(i,Navy):
			i.attack()
		else:
			i.back()
	else:
		print("风太大,小弟听不见")
		break

python对成员的保护分为两个等级

  • 私有的: private
    在本类内部可以访问,类的外部不可以访问.(python中 属性或者方法前面加上两个下划线__)
  • 公有的: public
    在本类的内部和外部都可以访问.
# 私有成员的改名策略 [_类名__成员名]
# 对象的相关操作
    (1)实例化的对象访问公有成员属性和方法
    (2)实例化的对象动态添加公有成员属性和方法
    (3)实例化的对象删除公有成员属性和方法
# 类的相关操作
    (1)定义的类访问公有成员属性和方法
    (2)定义的类动态添加公有成员属性和方法
    (3)定义的类删除公有成员属性和方法
    
普通方法:  没有任何参数传递,只能类调用
绑定方法:  把默认传参的方法叫做绑定方法,绑定到对象(默认传对象),绑定到类(默认传类)
非绑定方法:静态方法(无需传任何参数,对象和类都能调用)

私有的:只能载类或者对象的结构中访问
公有的:可以载任何位置访问
受保护:可以载当前类或者对象 和子类或者子类对象中访问

		类内   子类中    类外部
公有的:  √       √        √  
私有的:  √       X        X
受保护:  √       √        X (python语言不支持)

魔术方法(特定时机自动触发)

__init__ 魔术方法(构造方法)

'''
	触发时机:实例化对象,初始化的时候触发
	功能:为对象添加成员
	参数:参数不固定,至少一个self参数
	返回值:无
'''

__new__ 魔术方法

'''
	触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
	功能:控制对象的创建过程
	参数:至少一个cls接受当前的类,其他根据情况决定
	返回值:通常返回对象或None
'''

# (1) 基本使用
class MyClass2():
	a = 100
obj2 = MyClass2()
# print(obj2)

class MyClass1():
	def __new__(cls):
		print(cls) # <class '__mian__.MyClass1'>
		# 1.返回本类对象
		"""类.成员方法(类)"""
		return object.__new__(cls)
		# 2.返回其他类的对象
		# return obj2
		# 3.不返回对象,None
		# return None		
	
obj = MyClass1()
# print(obj.a)
print(obj)

# (2) __new__ 触发时机要快于 __init__
"""
# 先创建对象,然后初始化对象
__new__  创建对象
__init__ 初始化对象
"""
class MyClass():

	def __new__(cls):
		print(1)
		return object.__new__(cls)

	def __init__(self):
		print(2)
	
obj = MyClass()	# 1 2

# (3) __new__的参数要和__init__参数一一对应

class Boat():
	def __new__(cls,name): # 不加name参数会报错
		return object.__new__(cls)
	
	def __init__(self,name):
		self.name  = name

obj = Boat("万里阳光号")
print(obj.name)

# 使用收集参数进行改造 ***
class Boat():
	# *args,**kwargs 可以收集多余的所有参数
	def __new__(cls,*args,**kwargs):
		return object.__new__(cls)
	
	def __init__(self,name,type):
		self.name  = name
		self.type = type

obj = Boat("万里阳光号","破木头做的")
print(obj.name , obj.type)


# (4) __new__和__init__之间的注意点
"""
如果 __new__ 没有返回对象或者返回的是其他类的对象,不会调用构造方法.
只有在返回自己本类对象的时候,才会调用 __iniy__ 构造方法.
"""
class Children():
	def __new__(cls,*args,**kwargs):
		return obj2
		# pass # 需要return cls
		
	def __init__(self,name,skin):
		print("构造方法被触发 ... ")
		# self.name = name
		# self.skin = skin
		
obj = Children("灭霸","紫薯")
# 没有返回对象,默认是None,无法在None关键字上加name属性
# print(obj.name) error
# print(obj.skin) error

单例模式

同一个类,无论实例化多少次,都有且只有一个对象

"""
每创建一个对象,就会在内存中多占用一份空间
为了节省空间,提升执行效率,使用单态(单例)模式
场景:只是单纯调用类中的成员,而不会额外为当前对象添加成员;
"""

class Singleton():
	__obj = None
	def __new__(cls):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj

"""
第一次,在实例化对象时触发__new__魔术方法 
if cls.__obj is None 条件成立  cls.__obj = object.__new__(cls) 创建一个对象给私有成员属性__obj
return cls.__obj  用obj1接收到了对象

第二次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象
return cls.__obj

第三次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象
return cls.__obj
"""
obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
print(obj1,obj2,obj3)

# 完整版
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("康玉康")
obj2 = Singleton("张保张")
print(obj1,obj2) # 同一个对象,指向同一个内存地址
print(obj1.name) # 张保张
print(obj2.name) # 张保张

__del__ 魔术方法(析构方法)

'''
	触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
    功能:对象使用完毕后资源回收
	参数:一个self接受对象
	返回值:无
'''

# (1) 基本语法

class Lion():
	def __init__(self,name):
		self.name = name
		
	def __del__(self):
		print("析构方法被触发 ... ")

# 触发方式一: 页面执行完毕回收所有变量
obj1 = Lion("辛巴")

# 触发方式二: 所有对象被del的时候
obj2 = obj1
obj3 = obj1
print(obj2 , obj1 ,obj3)
print("<====start===>")
del obj1
del obj2 # 对象没有引用的时候才会触发
del obj3
print("<====end===>")

# (2) 模拟文件操作
import os
class ReadFile():
	# 根据文件是否存在,创建对象
	def __new__(cls,filename):
		if os.path.exists(filename):
			return object.__new__(cls)
		else:
			print("抱歉,没有这个文件")
	
	# 打开文件
	def __init__(self,filename):
		self.fp = open(filename,mode="r",encoding="utf-8")
		
	# 关闭文件
	def __del__(self):
		self.fp.close()
		
	# 读取文件
	def readcontent(self):
		return self.fp.read()
		

obj = ReadFile("0.py")
print(obj.readcontent())

__str__ 魔术方法

'''
	触发时机: 使用print(对象)或者str(对象)的时候触发
	功能:     查看对象
	参数:     一个self接受当前对象
	返回值:   必须返回字符串类型
'''

class Cat():
	gift = "抓老鼠"
	def __init__(self,name):
		self.name = name
		
	def cat_gift(self):
		return "小猫叫{},小猫会{}".format(self.name,self.gift)
	
	def __str__(self):
		return self.cat_gift()	

	__repr__ = __str__
	
tom = Cat("汤姆")
# 触发时机1 :  print(对象)
# print(tom)
# 触发时机2 :  str(对象)
res = str(tom)
print(res)

print("<==================>")
res = repr(tom)
print(res , type(res))
print("<==================>")

__repr__ 魔术方法

'''
	触发时机: 使用repr(对象)的时候触发
	功能:     查看对象,与魔术方法__str__相似
	参数:     一个self接受当前对象
	返回值:   必须返回字符串类型
'''
class Mouse():
	gift = "偷油吃"
	def __init__(self,name):
		self.name = name
	
	def mouse_gift(self):
		return "老鼠叫{},老鼠会{}".format(self.name,self.gift)
	
	def __repr__(self):
		return self.mouse_gift()
	
	# 系统底层默认把__repr__方法赋值给__str__方法,所以通过print或者str强转可以触发;
	# __str__ = __repr__
	
jerry = Mouse("杰瑞")
# res = repr(jerry)
# print(res)

# 可以触发
# print(jerry)
res = str(jerry)
print(res)

__call__ 魔术方法

'''
	触发时机:把对象当作函数调用的时候自动触发
	功能: 模拟函数化操作
	参数: 参数不固定,至少一个self参数
	返回值: 看需求
'''

# (1) 基本语法
class MyClass():
	def __call__(self):
		print("__call__魔术方法被触发 ... ")

obj = MyClass()
obj() # 如果没写 __call__魔术方法 则报错

# (2) 利用__call__魔术方法做统一调用
class Wash():
	def __call__(self,something):
		print("我要洗{}".format(something))
		self.step1(something)
		self.step2()
		self.step3()
		return "洗完了"
		
	def step1(self,something):
		print("放水,把{}扔进去".format(something))
		
	def step2(self):
		print("倒洗衣粉,洗衣液,蓝月亮,金纺,立白 ... ")
		
	def step3(self):
		print("洗一洗,晾干,穿上")

obj = Wash()
# obj.step1()
# obj.step2()
# obj.step3()
res = obj("袜子")
print(res)

# (3) 模拟整型强转操作
import math
class MyInt():
	def __call__(self,num):
		if isinstance(num,bool):
			if num == False:
				return 0 
			else:
				return 1
				
		elif isinstance(num,int):
			return num
			
		elif isinstance(num,float):
			# 方法一
			# a,b = str(num).split(".")
			# return eval(a)
			
			# 方法二
			"""
			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
				elif num[0] == "-":
					sign = -1	
				# 截取符号后面的字符串传递
				return self.calc(num[1:],sign)
				
			elif num.isdecimal():
				return self.calc(num)
			else:
				return "这个算不了兄弟~"

		
	# 计算最后的数值
	def calc(self,num,sign=1):
		# 去掉前面的"0"字符串
		num	= num.lstrip("0")
		# print(num , type(num) , "<==============>")
		if num == "":
			return 0 
		
		return eval(num) * sign			
			
	
myint = MyInt()
res = myint(-5.67) 
print(res , type(res))
res = myint("-000000000000055555")
print(res , type(res))
res = myint("asdfasdfasdfasdf")
print(res , type(res))
# print(myint("+0000000000000"))
# bool int  float 纯数字字符串

"""
print(    int("00000000000001223")   )  # 1223
print(    int("-00000000000001223")   ) # -1223
print(    int("+00000000000001223")   ) # 1223
print(    int("+0000000000000")   ) # 0
"""
# print(    int("asdfasdfasdfasdf")   ) # 报错
# print(  eval("00000000000001223")   ) # 报错

__bool__ 魔术方法

'''
	触发时机:使用bool(对象)的时候自动触发
	功能:强转对象
	参数:一个self接受当前对象
	返回值:必须是布尔类型
'''
'''
类似的还有如下等等(了解):
	__complex__(self)      被complex强转对象时调用
	__int__(self)          被int强转对象时调用
	__float__(self)        被float强转对象时调用
	...
	...
'''

class MyClass():
	def __bool__(self):
		return True # 返回的不是bool 类型会报错
obj = MyClass()
print(bool(obj))

__add__ 魔术方法 (与之相关的__radd__ 反向加法)

'''
	触发时机:使用对象进行运算相加的时候自动触发
	功能:对象运算
	参数:二个对象参数
	返回值:运算后的值
'''

'''
类似的还有如下等等(了解):
	__sub__(self, other)           定义减法的行为:-
	__mul__(self, other)           定义乘法的行为:
	__truediv__(self, other)       定义真除法的行为:/
	...
	...
'''

class MyClass():
	def __init__(self,num):
		self.num = num
		
	# 当对象在 + 号的左侧时,自动触发
	def __add__(self,other):
		# print(self) # 对象
		# print(other) # + 号右边的数据
		return self.num * 3 + other
		
	# 当对象在 + 号的右侧时,自动触发
	def __radd__(self,other):
		# print(self)  # 对象
		# print(other) # 7 + 号左边的数据
		return self.num * 5 + other
		
# add的触发方式
a = MyClass(3)
res = a + 1
print(res) # 10

# radd的触发方式
b = MyClass(5)
res = 7 + b
print(res) # 32

# 对象 + 对象
res = a + b
print(res) # 34

"""
a+b 触发的是add魔术方法  self 接受的是a   other 接受的是b
return a.num + b  => return 9 + b
res =  9 + b   触发的是radd魔术方法  self 接受的是b   other 接受的是9
return b.num * 5 + 9  => 5 * 5 + 9 => 34
"""

__len__ 魔术方法

'''
	触发时机:使用len(对象)的时候自动触发 
	功能:用于检测对象中或者类中某个内容的个数
	参数:一个self接受当前对象
	返回值:必须返回整型
'''
'''
类似的还有如下等等(了解):
	__iter__(self)                 定义迭代容器中的元素的行为
	__reversed__(self)             定义当被 reversed() 调用时的行为
	__contains__(self, item)       定义当使用成员测试运算符(in 或 not in)时的行为
	...
	...
''' 

# len(对象) => 类中的所有自定义成员
class MyClass():
	pty1 = 1
	pty2 = 2 
	__pty3 = 3
	
	def func1():
		pass
	def func2():
		pass
	def __func3():
		pass
		
	def __len__(self):
		# 以__开头并且以__结尾的成员过滤掉;
		return len( [  i for i in MyClass.__dict__ if not (  i.startswith("__") and i.endswith("__")  )  ] ) 

obj = MyClass()
print(len(obj))

魔术属性

class Man():
	pass

class Woman():
	pass

class Sasuke(Man,Woman):
	"""
描述: 佐助这个的天生属性,技能
成员属性:  __eye skin
成员方法: skylight __moonread
	"""
	__eye = "血轮眼->万花筒->轮回眼"
	
	skin = "白色"
	
	def skylight(self , myfunc):
		print("使用天照,一团黑色的火焰 ... 恐怖如斯")
		res = myfunc.__name__
		print(res , type(res) )
		
	def __moonread(self):
		print("使用月读,让敌人拉入到幻术空间,被施法者掌握")

obj = Sasuke()

__dict__ 获取对象或类的内部成员结构

dic = Sasuke.__dict__ # <class 'mappingproxy'> 类型
dic = obj.__dict__ # <class 'dict'>
print(dic)

__doc__ 获取对象或类的内部文档

print(Sasuke.__doc__)
print(obj.__doc__)

__name__ 获取类名函数名

def func343434():
	print("佩恩出场时,使用一手地爆天星,技惊四座,点燃所有观众")

obj.skylight(func343434) # func343434

__class__ 获取当前对象所属的类

print(obj.__class__) # <class '__main__.Sasuke'>

__bases__ 获取一个类直接继承的所有父类,返回元组

print(Sasuke.__bases__) # (<class Man>, <Woman>)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值