在python中,所有以“__"双下划线包起来的方法,称为魔术方法。
所谓魔术方法,就是不知道怎么的就实现了某些功能。
最常见到的” init “就是魔术方法,
构造和初始化
常见面试题:"init"和"new"方法的区别?
"init"构造方法:将参数传入,初始化实例。
"new"方法:在"init"之前执行,用于开辟内存空间,创建类并返回类的实例。
在实际使用中,如果不需要控制类的创建,一般不使用”new“方法。
class foo(object):
def __init__(self,name,age):
self.name=name
self.age=age
def print(self):
return self.name,self,age
__ del__”析构函数“
在对象的生命周期结束后,程序会自动调用__ del__方法销毁对象,
class foo(object):
def __init__(self,name,age):
self.name=name
self.age=age
del __del__(self):
del self.name,self.age
控制访问属性
众所周知,python中类的私有属性其实没有那么私有,只是改变的属性名,如果希望Python能够定义私有属性,然后提供公共可访问的getter和 setter。Python其实可以通过魔术方法来实现封装。
__ getter __方法
该方法定义了用户在访问一个不存在的属性时,可以对拼写错误进行捕获和重定向,对获取一些不建议的属性时提出警告。
只有在访问的属性不存在时,才会调用__ getter __ 方法。
__ setter __方法
__ setter __是实现封装的解决方案,无论属性是否存在,都允许对属性进行赋值,在使用"setter"时要注意避免”无限递归“。
__ getattribute __方法
__ getattribute __方法定义了属性被访问时的行为。
无限递归
def __setattr__(self, name, value):
self.name = value
每一次赋值时,__ setter __都会被调用。
__ getitem __方法
如果要实现自定义不可变的容器类型,只需要__ len 方法和 getitem __方法。
如果要实现自定义可变的容器类型,需要在不可变的基础上增加 __ setitem __和 __ delitem __方法,想让它可迭代,还需定义 __ iter __方法。
__ str __方法
直接返回一个类的实例,是这样的:
并不友好,怎么让它友好的显示呢?
class student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return "student object: name:%s age %d" %(self.name,self.age)
s=student("ss",20)
print(s)
__ call __方法
通过__ call __ 方法,可以让实例表现得像函数一样。
class student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return "student object: name:%s age %d" %(self.name,self.age)
def __call__(self, *args, **kwargs):
print("its a test program")
s=student("ss",20)
s()
上下文管理
在with声明段的代码中,可以对对象进行异常处理和资源回收。
需要两个魔术方法: __enter __和 __ exit __
class myopen(object):
"""为了模拟文件中with语句的实现机制"""
def __init__(self, filename, mode='r'):
self.name = filename
self.mode = mode
def __enter__(self):
"""当with语句开始值性时, 做的操作"""
# 返回的时文件对象
print('文件打开')
self.f = open(self.name, self.mode)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
print("文件关闭")
with myopen('test1.txt', 'r') as f:
print(f.read())
元类
先定义一个类,使用type查看这个类的类型时会发现,所有类的类型也为"type"
这是因为,类是实例的模板,而type就是类的模板。
编辑器在运行到class时,创建class的方法就是type函数
type()函数即可以返回一个对象的类型,也可以创建一个新的类型。
metaclass
要控制类的创建行为,也就是,先创建metaclass,在创建类。
def upper_attr(cls_name, bases, attr):
newAttr = {}
for key, value in attr.items():
newAttr[key.upper()] = value
print(newAttr)
return type(cls_name, bases, newAttr)
class Student(object, metaclass=upper_attr):
country = 'china'
score = 100
s = Student()
# print(s.country)
print(s.COUNTRY)
练习:
import pickle as p
import os
personDictionary= {'name':{'relationship':'','tel':''}}
relationshipList=['家人','朋友','同事']
class Person:
def __init__(self,name,relationship= relationshipList[1],tel='None',Email=None,QQ=None):
personDictionary[name]= {'relationship':relationship,'tel':tel,'Email':Email,'QQ':QQ}
class Operation:
def Addperson():
addname= input('请输入姓名:')
addrelationship= int(input('请选择分组(0:家人,1:朋友,2:同事):'))
addtel= input('请输入电话:')
Person(addname,relationshipList[addrelationship],addtel)
def Delperson():
name= input('请输入要删除的联系人姓名:')
del personDictionary[name]
def Search():
name= input('请输入要查找的联系人的姓名:')
if name in personDictionary:
print('姓名:%s,关系:%s,电话:%s' %(name,personDictionary[name]['relationship'],personDictionary[name]['tel']))
else:
print('联系人不存在。')
def Quit():
running= False
def SaveQuit():
f= open(addressbookFile,'wb')
p.dump(personDictionary,f)
f.close()
running= False
running= True
addressbookFile= 'addressbook.data'
# 如果存在,将文件读取到personDictionary字典中
if os.path.exists(addressbookFile):
f= open(addressbookFile,'rb')
personDictionary= p.load(f)
else:
jCommand= input('未找到通讯录文件,是否创建?yes/no ')
if jCommand== 'yes':
f= open(addressbookFile,'wb')
p.dump(personDictionary,f)
f.close()
elif jCommand== 'no':
running= False
while running:
menu = {'1': '添加联系人',
'2': '删除联系人',
'3': '查找联系人',
'4': '不保存退出',
'5': '保存退出'}
print(menu)
command= input('请输入序号:')
if command== '1':
Operation.Addperson()
continue
elif command== '2':
Operation.Delperson()
continue
elif command== '3':
Operation.Search()
continue
elif command== '4':
Operation.Quit()
break
elif command== '5':
Operation.SaveQuit()
break
else:
print('无效操作!请重新输入!')
continue