面向对象进阶和魔术方法

在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

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值