python-面向对象-双下方法
__str__和__repr__
class Course(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return "func is __str__ ,课程:{},价格:{}".format(self.name, self.price)
#
python = Course("python", 25000)
print(python) # func is __str__ ,课程:python,价格:25000
print("%s" % (python)) # func is __str__ ,课程:python,价格:25000
print([python]) # [<__main__.Course object at 0x000001CAEB38F438>]
class Course(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return "func is __repr__ ,课程:{},价格:{}".format(self.name, self.price)
python = Course("python", 25000)
print(python) # func is __repr__ ,课程:python,价格:25000
print("%r" % (python)) # func is __repr__ ,课程:python,价格:25000
print([python]) # [func is __repr__ ,课程:python,价格:25000]
python = Course("python", 25000)
class Course(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return "func is __str__ ,课程:{},价格:{}".format(self.name, self.price)
def __repr__(self):
return "func is __repr__,课程:{},价格:{}".format(self.name, self.price)
python = Course("python", 25000)
print(python) # func is __str__ ,课程:python,价格:25000
print("%s" % (python)) # func is __str__ ,课程:python,价格:25000
print([python]) # [func is __repr__,课程:python,价格:25000]
print(repr(python)) # func is __repr__,课程:python,价格:25000
print("%r" % (python)) # func is __repr__,课程:python,价格:25000
总结:
# 如果str存在,repr也存在
# 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
# 而repr(obj)和%r格式化字符串,都会调用__repr__
# 如果str不存在,repr存在
# 那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__
# 如果str存在,repr不存在
# 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
# repr(obj)和%r格式化字符串 都会打印出内存地址
class Course(object):
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
def __repr__(self): # 备胎
return '%s,%s,%s'%(self.name,self.price,self.period)
# def __str__(self):
# return self.name
class Python(Course):
pass
# def __repr__(self): # 备胎
# return '%s--%s--%s'%(self.name,self.price,self.period)
# def __str__(self):
# return '全栈开发 :'+self.name
py20 = Python('python',25000,'6 months')
print(py20)
打印对象 先走自己的str,如果没有,走父类的,如果除了object之外的所有父类都没有str
再回来,找自己的repr,如果自己没有,再找父类的
repr是str的备胎
和所有的字符串格式化以及直接打印这个对象相关
有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了
增强了用户的体验 在程序开发的过程中
如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,实际上是一种麻烦
如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示
__new__ 和__del__
__new__ 构造方法 生产对象的时候用的 - 单例模式.
__del__ 析构方法 在删除一个对象之前用的 - 归还操作系统资源.
__new__
class Foo(object):
def __new__(cls, *args, **kwargs): # 这里不能将cls换成self.原因在这里,self还没有被创建出来
print("创建对象呀!") # 先执行
obj = object.__new__(cls) # self被创建出来
print(obj) # <__main__.Foo object at 0x00000158F978C9E8>
return obj
def __init__(self):
print("初始化!!") # 后执行
print(self) # <__main__.Foo object at 0x00000158F978C9E8>
f = Foo()
'''
创建对象呀!
<__main__.Foo object at 0x00000158F978C9E8>
初始化!!
<__main__.Foo object at 0x00000158F978C9E8>
'''
实例化一个Foo对象,先开辟一块空间,使用的是Foo这个内部的__new__,如果内部没有这个__new__方法,则会调用object类中的__new__方法
在使用self之前,都还有一个生产self的过程,就是在内存空间开辟属于这个对象的空间,并且在这个内存空间存放一个类指针,也上就是__new__所做的事情。
单例模式
一个类 有且只能有一个实例
class Foo(object):
__flag = None
def __new__(cls, *args, **kwargs):
if cls.__flag is None:
obj = object.__new__(cls)
cls.__flag = obj
return cls.__flag
保证一个类无论 被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址
__del__
class Foo(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __del__(self):
print("执行我了")
print("ddabhjdab")
f = Foo("Tom", 45)
print(f.__dict__) # {'name': 'Tom', 'age': 45}
del f.name # 只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容
print(f.__dict__)
'''
{'age': 45}
执行我了
'''
文件的操作
class File(object):
def __init__(self, path):
self.f = open(path, 'w',encoding='utf-8')
def __del__(self):
self.f.close()
f = File("XXXX")
在所有的代码都执行完毕之后,所有的值都会被python解释器回收
python解释器清理内存
- 我们主动的去删除 del obj
- python解释器周期性删除
- 在程序结束之前,所有的内容都需要进行清空
__call__
对象()自动触发__call__中的内容
class Foo(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print("name " + self.name)
# f = Foo("Tom")
# f() # name Tom
Foo("Mack")() # name Mack # 对象+()就会调用__call__()方法
with处理上下文
class Foo(object):
def __enter__(self):
print("开始")
def __exit__(self, exc_type, exc_val, exc_tb):
print("结束!")
with Foo():
print('aaaa')
'''
开始
aaaa
结束!
'''
文件操作
class FileDeal(object):
def __init__(self, path,mode='w'):
self.f = open(path, mode, encoding="utf8")
def __enter__(self):
print("start")
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with FileDeal("config.ini","r") as f:
print(f.read())
pickle文件操作
dump
import pickle
class PickleDump(object):
def __init__(self, path, mode):
self.path = path
self.mode = mode
def __enter__(self):
self.f = open(self.path, self.mode)
return self
def dump(self, obj):
pickle.dump(obj, self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with PickleDump("pickle_file", 'ab') as file:
file.dump("abcde")
file.dump("abcde")
file.dump("abcde")
file.dump("abcdea")
load
import pickle
class PickleLoad(object):
def __init__(self, path, mode):
self.mode = mode
self.path = path
def __enter__(self):
self.f = open(self.path, self.mode)
return self
def load(self):
while True:
try:
f = pickle.load(self.f)
yield f
except EOFError as f:
break
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with PickleLoad('pickle_file', 'rb') as file:
for read_line in file.load():
print(read_line)
实现一个装饰器
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __enter__(self):
print("开始了")
def __exit__(self, exc_type, exc_val, exc_tb):
print("结束了")
with Foo("Tom", 45):
print("func")
'''
开始了
func
结束了
'''
__get__、__set__、__delete__
class Foo(object):
def __get__(self, instance, owner):
print("__get__")
print(instance, owner)
def __set__(self, instance, value):
print("__set__")
print(instance, value)
def __delete__(self, instance):
print("__delete__")
print(instance)
class Foo1(object):
foo = Foo() # foo 属性被代理,将这个类作用于另外一个类的属性来使用
def __init__(self, foo1):
self.foo = foo1
f1 = Foo1("xx")
f1.age = 15
f1.foo
del f1.foo
"""
__set__
<__main__.Foo1 object at 0x00000212573D5FD0> xx
__get__
<__main__.Foo1 object at 0x00000212573D5FD0> <class '__main__.Foo1'>
__delete__
<__main__.Foo1 object at 0x00000212573D5FD0>
"""
__setitem__、__getitem__和__delitem__
class Foo(object):
def __setitem__(self, key, value):
print("执行我__setitem__了")
self.__dict__[key]=value
def __getitem__(self, item):
print("执行我__getitem__了")
def __delitem__(self, key):
print("我__delitem__工作了")
del self.__dict__[key]
f = Foo()
f["name"]='devil' # 将会执行__setitem__
f["name"] # 将会执行__getitem__
del f["name"] # 将会执行__delitem__
# 当使用[]进行操作的时候,都会调用双下方法的item系列的方法
"""
执行我__setitem__了
执行我__getitem__了
我__delitem__工作了
"""
__setattr__、__getattr__、__delattr__和__getattribute__
class Foo(object):
def __setattr__(self, key, value):
print("执行了__setattr__方法")
print(key, value)
def __getattr__(self, item):
print("执行了__getattr__方法")
def __delattr__(self, item):
print("执行了__delattr__方法")
def __getattribute__(self, item):
print("执行了__getattribute__方法")
f = Foo()
f.name = 'devil' # 将会执行__setattr__
f.name # 将会执行__getattribute__或者__getattr__ 当两者都存在的时候 先执行__getattribute__ 如果两者都没有 报错
del f.name # 将会执行__delattr__
"""
执行了__setattr__方法
name devil
执行了__getattribute__方法
None
执行了__getattribute__方法
执行了__delattr__方法
"""
__getitem__ 、__delitem__、__setitem__
在__getitem__ 、__delitem__、__setitem__中使用[]
才能给触发。
class Item_(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __setitem__(self, key, value):
print("__setitem__")
self.__dict__[key] = value
def __getitem__(self, item):
print("__getitem__")
return self.__dict__[item]
def __delitem__(self, key):
print("__delitem__")
del self.__dict__[key]
obj = Item_("Yang","10")
obj["sex"] = 'man' # 会调用__setitem__
obj["name"] # 会调用__getitem__
del obj["name"] # __delitem__
print(obj.__dict__)
"""
__setitem__
__getitem__
__delitem__
{'age': '10', 'sex': 'man'}
"""
__setattr__、__getattr__
#使用创建属性
class Set_(object):
def __init__(self,name):
self.name = name
def __setattr__(self, key, value):
print("__setattr__")
self.__dict__[key] = value
sobj = Set_("Yang")
sobj.age = 18
print(sobj.__dict__)
"""
__setattr__ self.name = name
__setattr__
{'name': 'Yang', 'age': 18}
"""
class Set_(object):
def __init__(self,name):
self.name = name
def __setattr__(self, key, value):
print("__setattr__")
self.__dict__[key] = value
def __getattr__(self, key):
print("__getattr__")
return key #当key不存在上海 才触发它
sobj = Set_("Yang")
sobj.age = 18
sobj.xx
"""
__setattr__
__setattr__
__getattr__
'xx'
"""
__eq__
class Equal(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __eq__(self,other):
print("__eq__")
if self.age == other.age:
return True
else:
return False
obj = Equal("Yang",18)
obj1 = Equal("Wang",18)
print(obj == obj1) # 判断相等
__hash__
class Hash_(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __hash__(self):
return hash(self.age + self.name) # 返回必须是一个integer
obj = Hash_("Yang","18")
print(hash(obj))
"""
-987895104248511319
"""
魔法方法 | 含义 |
---|---|
基本的魔法方法 | |
__new__(cls[, ...]) | 1. __new__ 是在一个对象实例化的时候所调用的第一个方法 2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法 3. __new__ 决定是否要使用该 __init__ 方法,因为__new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则__init__ 不会被调用 4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string |
__init__(self[, ...]) | 构造器,当一个实例被创建的时候调用的初始化方法 |
__del__(self) | 析构器,当一个实例被销毁的时候调用的方法 |
__call__(self[, args...]) | 允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b) |
__len__(self) | 定义当被 len() 调用时的行为 |
__repr__(self) | 定义当被 repr() 调用时的行为 |
__str__(self) | 定义当被 str() 调用时的行为 |
__bytes__(self) | 定义当被 bytes() 调用时的行为 |
__hash__(self) | 定义当被 hash() 调用时的行为 |
__bool__(self) | 定义当被 bool() 调用时的行为,应该返回 True 或 False |
__format__(self, format_spec) | 定义当被 format() 调用时的行为 |
有关属性 | |
__getattr__(self, name) | 定义当用户试图获取一个不存在的属性时的行为 |
__getattribute__(self, name) | 定义当该类的属性被访问时的行为 |
__setattr__(self, name, value) | 定义当一个属性被设置时的行为 |
__delattr__(self, name) | 定义当一个属性被删除时的行为 |
__dir__(self) | 定义当 dir() 被调用时的行为 |
__get__(self, instance, owner) | 定义当描述符的值被取得时的行为 |
__set__(self, instance, value) | 定义当描述符的值被改变时的行为 |
__delete__(self, instance) | 定义当描述符的值被删除时的行为 |
比较操作符 | |
__lt__(self, other) | 定义小于号的行为:x < y 调用 x.__lt__(y) |
__le__(self, other) | 定义小于等于号的行为:x <= y 调用 x.__le__(y) |
__eq__(self, other) | 定义等于号的行为:x == y 调用 x.__eq__(y) |
__ne__(self, other) | 定义不等号的行为:x != y 调用 x.__ne__(y) |
__gt__(self, other) | 定义大于号的行为:x > y 调用 x.__gt__(y) |
__ge__(self, other) | 定义大于等于号的行为:x >= y 调用 x.__ge__(y) |
算数运算符 | |
__add__(self, other) | 定义加法的行为:+ |
__sub__(self, other) | 定义减法的行为:- |
__mul__(self, other) | 定义乘法的行为:* |
__truediv__(self, other) | 定义真除法的行为:/ |
__floordiv__(self, other) | 定义整数除法的行为:// |
__mod__(self, other) | 定义取模算法的行为:% |
__divmod__(self, other) | 定义当被 divmod() 调用时的行为 |
__pow__(self, other[, modulo]) | 定义当被 power() 调用或 ** 运算时的行为 |
__lshift__(self, other) | 定义按位左移位的行为:<< |
__rshift__(self, other) | 定义按位右移位的行为:>> |
__and__(self, other) | 定义按位与操作的行为:& |
__xor__(self, other) | 定义按位异或操作的行为:^ |
__or__(self, other) | 定义按位或操作的行为:| |
反运算 | |
__radd__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rsub__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rmul__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rtruediv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rfloordiv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rdivmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rpow__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rlshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rrshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rand__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__rxor__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
__ror__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) |
增量赋值运算 | |
__iadd__(self, other) | 定义赋值加法的行为:+= |
__isub__(self, other) | 定义赋值减法的行为:-= |
__imul__(self, other) | 定义赋值乘法的行为:*= |
__itruediv__(self, other) | 定义赋值真除法的行为:/= |
__ifloordiv__(self, other) | 定义赋值整数除法的行为://= |
__imod__(self, other) | 定义赋值取模算法的行为:%= |
__ipow__(self, other[, modulo]) | 定义赋值幂运算的行为:**= |
__ilshift__(self, other) | 定义赋值按位左移位的行为:<<= |
__irshift__(self, other) | 定义赋值按位右移位的行为:>>= |
__iand__(self, other) | 定义赋值按位与操作的行为:&= |
__ixor__(self, other) | 定义赋值按位异或操作的行为:^= |
__ior__(self, other) | 定义赋值按位或操作的行为:|= |
一元操作符 | |
__pos__(self) | 定义正号的行为:+x |
__neg__(self) | 定义负号的行为:-x |
__abs__(self) | 定义当被 abs() 调用时的行为 |
__invert__(self) | 定义按位求反的行为:~x |
类型转换 | |
__complex__(self) | 定义当被 complex() 调用时的行为(需要返回恰当的值) |
__int__(self) | 定义当被 int() 调用时的行为(需要返回恰当的值) |
__float__(self) | 定义当被 float() 调用时的行为(需要返回恰当的值) |
__round__(self[, n]) | 定义当被 round() 调用时的行为(需要返回恰当的值) |
__index__(self) | 1. 当对象是被应用在切片表达式中时,实现整形强制转换 2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__ 3. 如果 __index__ 被定义,则 __init__ 也需要被定义,且返回相同的值 |
上下文管理(with 语句) | |
__enter__(self) | 1. 定义当使用 with 语句时的初始化行为 2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定 |
__exit__(self, exc_type, exc_value, traceback) | 1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么 2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作 |
容器类型 | |
__len__(self) | 定义当被 len() 调用时的行为(返回容器中元素的个数) |
__getitem__(self, key) | 定义获取容器中指定元素的行为,相当于 self[key] |
__setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于 self[key] = value |
__delitem__(self, key) | 定义删除容器中指定元素的行为,相当于 del self[key] |
__iter__(self) | 定义当迭代容器中的元素的行为 |
__reversed__(self) | 定义当被 reversed() 调用时的行为 |
__contains__(self, item) | 定义当使用成员测试运算符(in 或 not in)时的行为 |