类中的内置方法(魔法方法、双下方法)

__len__

class A:
    def __init__(self,name):
        self.name=name
    def __len__(self):
        return len(self.name)
liu=A("liulin")  #实例化
print(len(liu)) #调用类中的__len__() 方法,如果类中没有__len__(),则报错

__eq__

等号比较,定制返回值:==  自动触发

 

class A:
    def __init__(self,name,cls,age,sex):
        self.name = name
        self.cls = cls
        self.age = age
        self.sex = sex
lin = A('','1班',18,'')
lin2 = A('','1班',18,'')
print(lin==lin2)  #返回False,因为比较的是内存地址,值一样,地址不一样
class A:
    def __init__(self,name,cls,age,sex):
        self.name = name
        self.cls = cls
        self.age = age
        self.sex = sex
    def __eq__(self, other):        #在类中定义一个__eq__():方法,只要用==比较,一定执行此函数
        if self.__dict__ == other.__dict__:   #如果值相等
            return True
        else:
            return False
lin = A('小黑','py10期',18,'')
lin2 = A('小黑','py10期',18,'')
print(lin==lin2)    #返回True
让上段代码返回True
class A:
    def __init__(self,name,cls,age,sex):
        self.name = name
        self.cls = cls
        self.age = age
        self.sex = sex
    def __eq__(self, other):        #在类中定义一个__eq__():方法,只要用==比较,一定执行此函数
            return True           #只要比较,一定返回True
lin = A('','1',18,'')
lin2 = A('','2',19,'')
print(lin==lin2)    #返回True
值不一样也可以返回(True) 定制返回值

__format__

定制输出格式

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __format__(self, format_spec):
        return format_spec.format(obj=self)

s1=School('成栋','北京','私立') #实例化  三个属性
print(format(s1,format_dict['tna'])) #把对象和定制的格式传进去
print(format(s1,format_dict['nat']))
print(format(s1,format_dict['tan']))
'''输出:
私立:成栋:北京
成栋-北京-私立
私立/北京/成栋
'''

__str__

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
liulin=Person('刘林',25)
print(liulin)  #直接打印对象 <__main__.Person object at 0x00000194EC747DA0>

----------------------------------------------------------------
#如果想返回属性
class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return str(self.__dict__)  #返回的必须是字符串,否则报错
liulin=Person('刘林',25)
print(liulin)  #直接打印对象就可以打印出结果:{'name': '刘林', 'age': 25}
print(str(liulin))
print("%s"%liulin) 三个结果一样

__repr__

 

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return str(self.__dict__)  #返回的必须是字符串,否则报错
    def __repr__(self):
        return "repr:Person中的repr对象"
liulin=Person('刘林',25)
print(str(liulin))            #  {'name': '刘林', 'age': 25}
print(repr(liulin))           #repr:Person中的repr对象
print("%s"%liulin)            #{'name': '刘林', 'age': 25}
print("%r"%liulin)            #repr:Person中的repr对象
class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __repr__(self):
        return "repr:Person中的repr对象"
liulin=Person('刘林',25)
print(str(liulin))
print(repr(liulin))
print("%s"%liulin)
print("%r"%liulin)            #所有值都是   repr:Person中的repr对象
                               #当类中没有__str__方法时,调用str   会自动执行repr中的代码
当类有repr,没有str时
class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return str(self.__dict__)  #返回的必须是字符串,否则报错
liulin=Person('刘林',25)
print(str(liulin))            #  {'name': '刘林', 'age': 25}
print(repr(liulin))           #<__main__.Person object at 0x0000015D043A7EF0>
print("%s"%liulin)            #{'name': '刘林', 'age': 25}
print("%r"%liulin)            #<__main__.Person object at 0x0000015D043A7EF0>
当类中有str,没有repr时

总结:当类中有__str__没有__repr__ ,则调用str可以执行,调用repr返回内存地址

           当类中有__repr__没有__str__,则调用str和repr,都执行repr方法中的代码

   两个都有,各走各的

__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

# 构造方法 创建一个对象的
# 初始化方法 __init__ 给已经创建出来的对象添加属性
# 析构方法 删除一个对象的时候调用的方法
import time
class A:
    def __init__(self):
        self.f = open('userinfo','a')
    def consume(self):
        pass
    def __del__(self):
        '''在删除一个对象之前做一些收尾工作'''
        self.f.close()
        print('删除一个对象的时候调用我')
a = A()
time.sleep(1)
del a
# 删除一个对象的时候,如果内部存在__del__方法,
# 那么在删除一个对象之前先执行__del__方法中的代码

__new__  构造方法

类创建对象之初进行的函数,常与单例模式一起使用

# new一个对象
class A:
    def __init__(self):
        print(111)
    def __new__(cls):
        print(222)
        return object.__new__(cls)  #创造对象,将对象返回给__init__   如果不返回,讲不会执行__init__
a = A()
#输出:222
#      111
# 先执行__new__方法 创造出一个对象,
# 然后把创造出来的对象传递给__init__方法(先执行new,再执行init)
# 会把self自动的返回,被a接收
补充:元类——创建类的类

type()  所有直接用class创建出来的类的元类都是type
class 类名(B,classMeta = 元类名)
class 类名(B,classMeta = type)  默认  
元类 创造 类     所以所有的类的type都是它的元类,默认是type
类   创造 对象   具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
设计模式——单例模式—:  一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例

 单例模式:

一个普通的类,在实例化的时候,可以同时实例化多个对象(多个对象一起执行,都存在内存地址里),单例模式就是只能存在一个

class A:
    _instance = None                  #设置一个空
    def __init__(self,name):
        '''给娃穿衣服'''
        self.name = name
    def __new__(cls, *args, **kwargs):
        '''生娃的过程'''
        if not A._instance:        #当_instance为空时,进入此条件
            A._instance = object.__new__(cls)  #创造对象,赋给_instance,返回
        return A._instance         #当_instance不为空时,说明已经实例化一次,则直接返回之前那得对象
a1 = A('liu')  # 第一次实例化的时候创造一个实例
print(a1.name)    #打印liu
a2 = A('lin')   
print(a1.name,a2.name)   #打印 lin  lin    因为只允许实例化一次,两次实例化是内存地址一样,所以两个值一样
class A:
    def __init__(self,name):
        '''给娃穿衣服'''
        self.name = name
    def __new__(cls, *args, **kwargs):
        '''生娃的过程'''
        if not hasattr(A,'_instance'):#判断如果没有此对象
            A._instance = object.__new__(cls)
        return A._instance
a1 = A('alex')  # 第一次实例化的时候创造一个实例
print(a1.name) #alex
a2 = A('egon')
print(a1.name,a2.name)  #egon egon
单例另一种写法(hasattr)

 

3、item系列

__getitem__  找   __setitem__  新建   __delitem__  删除   __delattr__  删除

通过上述方法  实现类似字典一样的操作

class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)
    def __delattr__(self, key):
        print('del obj.key时,我执行')
        del self.__dict__[key]

f1=Foo('sb')
f1['age']=18
f1['age1']=19del f1['age']
f1['name']='liulin'
print(f1.__dict__)

 

 

__call__

对象名加括号,调用类中内置__call__ 方法

class A:
    def __call__(self):
        print('执行我了')
A()() #实例化 ()
#执行我了

 

__hash__

# hash
# 不可变的数据类型都可以被hash
# dict的key   set的元素
# dic key --> value
# dic[key] = value
 
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
View Code

 


依据hash和set(集合)完成的金融面试题

# 金融公司面试题
# 有一个类,对应这个类产生了100个对象
# 每个对象有三个属性 : 姓名 年龄 性别
# 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象
# 问最简便的方法?
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def __hash__(self):
        return hash('%s%s'%(self.name,self.sex))
    def __eq__(self, other):
        if self.name == other.name and  \
            self.sex == other.sex:
            return True
p_lst = []
for i in range(100):
    p_lst.append(Person('egon',i,'male'))
p_lst.append(Person('alex',i,'male'))
p_lst.append(Person('yuan',i,'male'))
print(p_lst)
print(set(p_lst))

 

收获1
对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法
都有可能依赖于类中的内置方法
收获2
set方法依赖集合中元素对象的__hash__ __eq__


posted on 2018-03-13 17:30  刘。林  阅读(114)  评论(0编辑  收藏  举报

导航