python_learn 5.30 review

"""
与类相关的魔术方法
0. __init__		# 实例化时触发,为对象添加成员,参数self,无返回值
0. __new__		# 实例化时触发,在__init__之前,控制对象的创建过程,参数cls,返回值为对象或None
1. __del__		# 对象被内存回收时触发,用于对象使用完毕后的资源回收,参数self,无返回值
2. __str__		# 使用print(对象)或str(对象)时触发,用于查看对象,参数self,必须返回字符串类型
3. __repr__		# 使用repr(对象)时触发,功能与__str__一致
4. __call__		# 把对象当做函数调用时触发,用于模拟函数化操作,参数self,返回值看需求
5. __bool__		# 使用bool(对象)时触发,用于强转对象,参数self,返回值必须是bool类型
6. __complex__  # 使用complex(对象)时触发,用于强转对象,参数self,返回值必须是complex类型
7. __int__		# 使用int(对象)时触发,用于强转对象,参数self,返回值必须是int类型
8. __float__	# 使用float(对象)时触发,用于强转对象,参数self,返回值必须是float类型
9. __add__		# 使用对象进行运算相加的时候自动触发,用于对象运算,参数是2个对象,返回值是运算后的值
10.__sub__		# 使用对象进行运算相减的时候自动触发,用于对象运算,参数是2个对象,返回值是运算后的值
11.__mul__		# 使用对象进行运算相乘的时候自动触发,用于对象运算,参数是2个对象,返回值是运算后的值
12.__truediv__	# 使用对象进行运算相除的时候自动触发,用于对象运算,参数是2个对象,返回值是运算后的值
13.__len__		# 使用len(对象)时触发,用于检测对象中或者类中成员的个数,参数self,返回值必须是整型
14.__iter__		# 定义迭代容器中的元素的行为
15.__reversed__	# 定义当被reversed()调用时的行为
16.__contains__	# 定义当使用成员测试运算符(in 或 not in)时的行为
"""
# ------------------------------------------------------------
"""
与类相关的魔术属性
1. __dict__		# 获取对象或类的内部成员结构
2. __doc__		# 获取对象或类的内部文档
3. __name__		# 获取类名函数名
4. __class__	# 获取当前对象所属的类
5. __bases__	# 获取一个类直接继承的所有父类,返回元组
"""


# ------------------------------------------------------------
# ============================================================
# shift + cmd + v  访问历史粘贴板
# shift + enter    任意位置换行
# shift + cmd + enter	补全代码


### 此处演示类的析构方法 __del__
class LangDog():
	food = "吃肉"

	def __init__(self, name):  # 1
		self.name = name

	def __del__(self):
		print("析构方法被触发")  # 5


# 1.页面执行完毕回收所有变量
obj = LangDog("刀疤")
print(obj.name)  # 2
# 2.所有对象被del时触发__del__
o_obj = obj
print(o_obj is obj)  # True	3
del obj
print(1)  # 4
del o_obj
# 截止此处,所有的对象都被del.触发__del__
"""当一个值,没有任何变量指向或者引用时,这个值才会真正的被释放.关键字是团灭"""
print(2)

# ------------------------------------------------------------

# 此处演示如何模拟文件操作
import os


class ReadFile():
	def __new__(cls, filename):			# 2
		# 判断文件是否存在
		if os.path.exists(filename):
			return object.__new__(cls)		# 3
		else:
			return print("该文件是不存在的")

	def __init__(self, filename):		# 4
		# 打开文件操作
		self.fp = open(filename, mode="r", encoding="utf-8")	 # 5

	def readcontent(self):			# 6
		# 读取文件操作
		content = self.fp.read()
		return content

	def __del__(self):				# 8
		self.fp.close()


obj = ReadFile("ceshi.txt")			# 1
res = obj.readcontent()				# 6
print(res)							# 7

# ============================================================

"""
__str__ : 使用print(对象)或str(对象)时触发,用来查看对象,参数要有一个self接收当前对象,必须返回字符串类型
# ------------------------------------------------------------
__repr__ : 使用方法与str一致,但平时还是str用的多
"""

# __str__的用法
class Cat():
	gift = "卖萌爬树"

	def __init__(self,name):			# self => tom
		self.name = name		# 2

	# 当执行res = str(tom) 时触发,self=>
	def __str__(self):			# self => tom天生会爬树
		return self.cat_info()		# 4

	def cat_info(self):			# self => tom天生会爬树
		return "{}天生会{}".format(self.name,self.gift)		# 5

tom = Cat("tom")		# 1
# 触发方式1
print(tom)
# 触发方式2
res = str(tom)			# 3
print(res)				# 6		# tom天生会爬树

# ------------------------------------------------------------

# 下面演示 __repr__ 的用法

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)

obj = Mouse("jieri")
res = repr(obj)
print(res)

"""
注意点:
1.不管是str 还是 repr,都是在str或repr强转obj对象时触发,因为强转,所以输出的肯定是字符串
2.在系统底层,如果定义了repr,将会默认赋值给str方法,而反之则不成立
__str__ = __repr__  	将右侧赋值给左侧
3.底层存在赋值调用给str的语法,所以能实现打印或者str强转对象的触发机制.
"""

# ============================================================

"""
__call__ : 把对象当做函数调用的时候触发,用于模拟函数化操作,参数self,返回值看需求
"""

# 此处演示基本用法
class MyClass():
	a = 1

	def __call__(self, *args, **kwargs):		# self 此时是MyClass 对象		2
		print("call方法被触发")

obj = MyClass()
obj()		# 将obj当做函数调用了,此时触发__call__1

# ------------------------------------------------------------

# 此处演示模拟洗衣服过程

class Wash():

	# 此处实现了用call方法统一调用,如果不使用call方法,就是直接调用,那么最后要写n个 obj.stepn(), 非常不便捷
	def __call__(self, *args, **kwargs):
		self.step1(*args)
		self.step2()
		self.step3()

	def step1(self,*args):
		print("洗{}".format(*args))

	def step2(self):
		print("剪")

	def step3(self):
		print("吹")

obj = Wash()
obj("刷刷")

# ------------------------------------------------------------

# 此处模拟内置方法int, 实现 myint 功能
import math
class MyInt():
	
	def mycalc(self,num,sign=1):
		# 去掉左边多余的0
		strvar = num.lstrip("0")
		if strvar == "":
			return 0
		# 计算最终结果
		return eval(strvar) * sign

	def __call__(self, num):
		# 判断是布尔类型
		if isinstance(num,bool):
			if num == True:
				return 1
			else:
				return 0
		# 判断是整型
		elif isinstance(num,int):
			return num
		# 判断是浮点型
		elif isinstance(num,float):
			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.mycalc(num[1:],sign)

			elif num.isdecimal():
				return self.mycalc(num)
			else:
				return "做不到"

myint = MyInt()
print(myint(3.3))
print(  myint(0)  ) #=> 3
print(  myint(3.13)  ) #=> 3
print(  myint("+00000000000000000001003")  ,"<==1=>")
print(  myint("+abcd")  ,"<===>")
print(  myint("-0000000000000000000.1003")  ,"<==2=>")
print(  int("0000000000000000000003")  )
print(  int("+0000000000000000000003")  )
# print(  int("+-+-+-+-+-+-1233444")  )
print(  myint("+-+-+-+-+-+-1233444")  )

# ============================================================

"""
__bool__ : 使用bool(对象)的时候自动触发,用于强转对象,参数必须有一个self,返回值必须是bool类型
"""

class MyClass():
	def __bool__(self):
		return True

obj = MyClass()
res = bool(obj)
print(res)

# ------------------------------------------------------------

"""
__add__ : 使用对象进行运算相加的时候触发,用于对象运算,必须有两个对象作为参数,返回值是运算后的值
"""

class MyAdd():
	def __init__(self,num):
		self.num = num

	def __add__(self, other):
		return self.num + other
	def __radd__(self,other):
		return self.num + other*2

# 情况1
a = MyAdd(7)
b = MyAdd(8)
res = a+b
print(res)
"""
a+b 先触发__add__, self接收7,oter接收b,res = 7+b
7+b 再触发__radd__,self接收b,other接收的是7, 故返回 8+7*2 = 22
"""

# ------------------------------------------------------------

"""
__len__ : 使用len(对象)时触发,用于检测对象中或者类中成员的个数,参数self,但必须返回整型
"""

# 此处演示如何计算类中自定义成员的个数
class MyClass():
	pty1 = 1
	pty2 = 2
	pyt3 = 3
	def func1(self):
		pass
	def fucn2(self):
		pass
	def func3(self):
		pass
	def func4(self):
		pass

	def __len__(self):
		lst = [i for i in MyClass.__dict__ if not (i.startswith("_"))]
		return len(lst)

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


# ============================================================

# 与类相关的魔术属性有什么


class Man():
	pass


class Woman():
	pass


class Children(Man, Woman):
	"""
	成员属性: eye
	成员方法: skylight moonread __makebaby
	完成的功能: 描述小孩天生神力.
	"""

	eye = "血轮眼"

	def skylight(self):
		print("一下生,直接使用天照,让世界变得混乱")

	def moonread(self, func):
		print("一下生,使出了武功绝学,月读,世界都黑暗里~")
		print(func.__name__, type(func.__name__))  # earth_boom

	def __makebaby(self):
		print("这一手招数,只能我自己用")


obj = Children()

# __dict__ 获取对象或类的内部成员结构
print(obj.__dict__)
print(Children.__dict__)

# __doc__  获取对象或类的内部文档
print(obj.__doc__)
print(Children.__doc__)


# __name__  获取类名函数名
def earth_boom():
	print("使出一招地爆天星")


obj.moonread(earth_boom)
obj.moonread(Children)

# __class__ 获取当前对象所属的类
print(obj.__class__)

# __bases__ 获取一个类直接继承的所有父类,返回元组
print(Children.__bases__)  # (<class '__main__.Man'>, <class '__main__.Woman'>)


"""
继承,一个类除了自身的属性方法之外,还获得了另一个类的成员属性和方法,就是继承
继承分为单继承\多继承,菱形继承
python所有的类都默认继承父类object
"""
# ------------------------------------------------------------
# 单继承
class Human(object):
	hair = "gold"
	sex = "male"
	def eat(self):
		print("eat")
	def la(self):
		print("la")
	def __makebaby(self):
		print("make")
class Man(Human):
	sex = "female"
	def eat(self):
		print("eateat")

# 此处说明,子父继承之后,子类可以调用父类的公有成员及方法,不能调用父类的私有成员及方法,但是可以改写父类的同名方法,这就是单继承的特点
obj = Man()
print(obj.hair)		# gold
obj.eat()			# eat
# obj.__makebaby()	# AttributeError: 'Man' object has no attribute '__makebaby'
obj.eat()			# eateat

# ------------------------------------------------------------

# 多继承

class Father(object):
	face = "cool"
	def hobby(self):
		print("eat and drink")

class Mather(object):
	face = "beautiful"
	def hobby(self):
		print("shopping")

class Child(Father,Mather):
	pass

obj = Child()
# obj.face()		# TypeError: 'str' object is not callable	字符串对象是不可调用的
print(obj.face)		# cool
obj.hobby()			# eat and drink
# 以上多继承是有继承顺序的,例子中子类都是继承了父类的公有成员属性及方法,这个跟继承的时候父类的填写顺序有关,谁在前面就先继承谁,如果想要定向继承,就要在父类中区分方法名称,然后调用时定向调用,比如Mather类的方法名改为m_hobby,再调用m_hobby,显示的就是"shopping"了

# ------------------------------------------------------------

"""super的用法"""

class Father():
	face = "cool"
	def f_hobby():
		print("eat and drink")

class Mather():
	face = "beautiful"
	def m_hobby(self):
		print("shopping")

class Child(Father,Mather):
	face = "black"
	def skill(self):
		# 利用类来调用父类成员
		print(Mather.face)	# beautiful
		Father.f_hobby()	# eat and drink
		print(Father.face)	# cool

	def skill1(self):
		# 利用对象来调用父类的属性和方法
		self.m_hobby()		# shopping
		print(self.face)	# black

	"""
	super()调用父类的属性和方法
	看下面的例子,super()调用了face这个成员属性,其实这个属性他本来也有,但是并没有调用,而是直接调用了父类的face属性,这说明,super()是不会调用本类成员的,这一点,就是和self最大的不同
	self,调用成员属性及方法,优先调用自己,其次调用父类,都没有就报错
	"""
	def skill2(self):
		print(super)	# <class 'super'>	super是一个类
		print(super())	# <super: <class 'Child'>, <Child object>>
		print(super().face)		# cool 		调用了父类的公有成员属性
		super().m_hobby()		# shopping	调用了父类的公有成员方法


obj = Child()
obj.skill()
obj.skill1()
obj.skill2()

# ------------------------------------------------------------


# 菱形继承
"""
		      (4 Human 1)
	(2 Father 3)		(3 Mother 2)
		     (1 Child 4)

当从C类使用super()时,逐层调用,调用顺序是:去的时候1234,如果后面还有打印的话,回的时候4321

类.mro() 返回的是方法调用顺序的列表,针对于多继承下的同名方法,按照列表顺序依次进行调用

经典类:深度优先
新式类:广度优先

"""

# 以下演示菱形继承的实现原理

class Human():
	num = 4
	def feel(self):
		# self 此时接收的是Child 的对象
		print("i am human 1")
		# obj.pty		obj <Child>	,so num = 1 ,而不是4
		print(self.num)		# <__main__.Child object at 0x103f53390>
		print(obj)
		# print("i am human 2")

class Man(Human):
	num = 3
	def feel(self):
		# self 此时接收的事Child类的对象
		print("i am man 3")
		# super()会接着往父类调用,前往H类
		super().feel()
		# print("i am man 4")

class Woman(Human):
	num = 2
	def feel(self):
		# self 此时接收的事Child类的对象
		print("i am woman 5")
		# super()刚从M类过来,然后通过W类,前往H类调用
		super().feel()
		# print("i am woman 6")

class Child(Man,Woman):
	num = 1
	def feel(self):
		print("i am child 7")
		# super()调用方法时,会携带当前类的对象进行传递,即Child的对象,往上级调用,去了F类
		super().feel()
		# print("i am child 8")

obj = Child()
obj.feel()
lst = Child.mro()
print(lst)	# [<class '__main__.Child'>, <class '__main__.Man'>, <class '__main__.Woman'>, <class '__main__.Human'>, <class 'object'>]

"""
1.issubclass(Child,Man)	判断是否存在子父关系,只要在一个继承链上即可,应用范围:类
2.isinstance(obj,Child) 判断类型,只要在一个继承链上即可,应用范围:对象与类之间
3.in 判断在或者不在, 在True, 不在False
res = "feel" in Child.__dict__
print(res)
"""
"""面向对象oop"""
"""
面向对象的三大特性:封装\继承\多态

封装等级: 1.公有 	2.私有
公有成员在类内类外都能调用,私有成员只能在类内调用
所有的调用都是通过:  obj.属性     or    obj.方法 的语法来实现
 
 类中的绑定方法:
 1.绑定到对象	(obj调用方法,系统自动把obj当成self进行传递),绑定方法就是在定义方法的时候加上形参self
 2.绑定到类	(obj 或 class调用方法时,系统自动把class当成self进行传递)
"""

# ------------------------------------------------------------

# 以下演示类的公有成员属性\私有成员属性\公有成员方法\私有成员方法的格式
class MyCar():
	# 公有成员属性
	color = "yellow"
	# 私有成员属性
	__logo = "auto"
	# 公有成员方法
	def dirve(self):
		print("{} car can drive.".format(self.color))
	# 私有成员方法
	def __info():
		print("price are mimi")

# 对象的实例化
obj = MyCar()
# 通过对象调用公有成员属性
print(obj.color)
"""对象调用方法"""
obj.dirve()
print(MyCar.color)
# 调用私有成员
# obj.__info()	# AttributeError: 'MyCar' object has no attribute '__info'
# obj.__logo		# AttributeError: 'MyCar' object has no attribute '__logo'

"""实例化对象不能调用私有成员属性及方法"""

# ------------------------------------------------------------

"""添加成员的方法"""

# 1.动态添加无参方法
def mod1():
	print("mod1")
# 对象.自定义属性 = 方法
obj.mod1 = mod1
obj.mod1()

# 2.动态添加有参方法
# 基础版
def mod2(name):
	print("{} is ironman".format(name))
obj.mod2 = mod2
obj.mod2("stack")		# 实参与形参对应,经过format格式化并打印

# 升级版
def mod3(obj,name):
	print("{} is superman, {}".format(name,obj.color))

obj.mod3 = mod3
obj.mod3(obj,"laowang")

# 高级版
import types

def mod4(self,name):
	print("hi ,guy {},you are foolish {}".format(name,self.color))

# types.MethodType(函数,对象)
obj.mod4 = types.MethodType(mod4,obj)
obj.mod4("haha")
print(obj)		# <__main__.MyCar object at 0x1032df320>

# 动态添加lambda 匿名函数
obj.mod5 = lambda : print(" i am ironman ,too")
obj.mod5()

print(obj.__dict__)
# {'mod1': <function mod1 at 0x107d38e18>, 'mod2': <function mod2 at 0x10832fe18>, 'mod3': <function mod3 at 0x10832fea0>, 'mod4': <bound method mod4 of <__main__.MyCar object at 0x107db1320>>, 'mod5': <function <lambda> at 0x108343048>}

"""此处我们可以看出,obj折腾的这一段,动态添加无参方法\有参方法\lambda,都是基于他自己这个对象建立的,而不是类,类跟对象是占用不同内存空间的,你玩你的,我玩我的,对象可以去调用类的成员属性和方法,但本质上并不能进行修改,对象像是在根据需求"自娱自乐",而类始终没变,私有化有效保证了数据的安全性,而这就是类的三大特性之一--封装"""


# ============================================================

# 类的相关操作
"""
1.定义类访问公有成员属性和方法
2.定义类动态添加公有成员属性和方法
类的操作和对象的操作基本一致,需要注意的点是,类中的成员只归属于当前这个类本身,类无法调用对象中的相关成员,对象可以调用类中的相关成员

"""

# ============================================================

# 类中的私有成员,怎么调用?
class Plane():
	# 公有成员属性
	captain = "魏富强"
	# 私有成员属性
	__airsistem = 3

	# 公有绑定方法
	def fly(self):
		print("飞机会飞,百公里油耗2万升1")

	# 公有无参方法
	def fly2():
		print("飞机会飞,百公里油耗2万升2")

	# 私有绑定方法
	def __plane_info(self):
		print("飞机上的空姐数量是保密的,个数%d" % (self.__airsistem))

	# 私有无参方法
	def __plane_info2():
		print("飞机上的空姐数量是保密的,个数%d" % (Plane.__airsistem))

	# 用pub_info调用私有成员属性和方法
	def pub_info(self):
		print(self.__airsistem)  # 3
		self.__plane_info()

	def pub_info2():
		print(Plane.__airsistem)
		Plane.__plane_info2()


obj = Plane()
obj.fly()
Plane.fly2()
print(Plane.__dict__)

# (1) 私有成员的改名策略 [_类名__成员名] (不推荐)
print(obj._Plane__airsistem)
print(Plane._Plane__airsistem)

obj._Plane__plane_info()
Plane._Plane__plane_info2()

# (2) 利用类内的公有方法间接调用私有成员 (推荐)
obj.pub_info()
Plane.pub_info2()

# ------------------------------------------------------------

# 2. 删除相关成员		del 对象.属性\方法		del 类.属性\方法
"""
实例化对象删除公有成员和属性\方法
定义的类删除公有成员和属性\方法

都删完,再调用就报错,如果没删干净,那还能调一调
"""


# ### 1.类中的私有成员
class Plane():
	# 公有成员属性
	captain = "魏富强"
	# 私有成员属性
	__airsistem = 3

	# 公有绑定方法
	def fly(self):
		print("飞机会飞,百公里油耗2万升1")

	# 公有无参方法
	def fly2():
		print("飞机会飞,百公里油耗2万升2")

	# 私有绑定方法
	def __plane_info(self):
		print("飞机上的空姐数量是保密的,个数%d" % (self.__airsistem))

	# 私有无参方法
	def __plane_info2():
		print("飞机上的空姐数量是保密的,个数%d" % (Plane.__airsistem))

	# 用pub_info调用私有成员属性和方法
	def pub_info(self):
		print(self.__airsistem)  # 3
		self.__plane_info()

	def pub_info2():
		print(Plane.__airsistem)
		Plane.__plane_info2()


obj = Plane()
obj.fly()
Plane.fly2()
print(Plane.__dict__)

# (1) 私有成员的改名策略 [_类名__成员名] (不推荐)
print(obj._Plane__airsistem)
print(Plane._Plane__airsistem)

obj._Plane__plane_info()
Plane._Plane__plane_info2()

# (2) 利用类内的公有方法间接调用私有成员 (推荐)
obj.pub_info()
Plane.pub_info2()

# ### 2.删除相关成员

# (1)实例化的对象删除公有成员属性和方法
obj.captain = "王思聪"
print(obj.__dict__)
# 删除属性
del obj.captain
print(obj.__dict__)
# 如果对象有该成员,先调用自己的,没有的话,调用类的.如果都没有,报错
print(obj.captain)

# 删除方法
obj.func = lambda: print("开飞机是为了泡妞")
obj.func()
# Plane.func() error
del obj.func
# obj.func() error


# (2)定义的类删除公有成员属性和方法
# 删除属性
del Plane.captain
# print(Plane.captain)
# obj.captain  error # 对象和类当中,没有 captain 成员

# 删除方法
# del Plane.fly
# obj.fly() error

# 注意点
obj.fly = lambda: print("112233")
del Plane.fly
del obj.fly
# obj.fly()		# Error


# ============================================================

"""
构造方法  __init__(self,...)
用于为对象添加成员,在实例化对象时触发,参数至少有一个self,无返回值
"""

# 构造多参数
class MyClass():
	def __init__(self,name):
		# 对象.成员属性(自定义) = 参数值
		self.name = name

# 实例化对象,注意传参数
obj = MyClass("xboy")
print(obj.name)

# 下面演示如何通过一个类实例化出不同的多个对象
class Children():
	def __init__(self,name,skin):
		self.name = name
		self.skin = skin

	def cry(self):
		print("cry")

	def drink(self):
		print("drink")

	def __eat(self):
		print("eat")

	def pub_func(self):
		print("名字{},肤色{}".format(self.name,self.skin))

	def pub_func2(self,name,skin):
		print("名字{},肤色{}".format(name,skin))

# 实例化对象p1
p1 = Children("xboy","green")
p1.cry()
p1.pub_func()
print("<--------->")

# 实例化对象p2
p2 = Children("alex","red")
p2.drink()
p2.pub_func()

p2.pub_func2("egon","yellow")
print(p2)					# <__main__.Children object at 0x10bacf438>

print(p2.__dict__)			# {'name': 'alex', 'skin': 'red'}
print(p1.__dict__)			# {'name': 'xboy', 'skin': 'green'}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值