day 24 内置函数(补充)
一。 内置函数
1.__len__ 与 len()
# class A:
# def __init__(self,name,age,sex,cls):
# self.name = name
# self.age = age
# self.sex = sex
# self.cls = cls
# def __len__(self):
# return len(self.__dict__)
#
# # 有一个内置函数 和内置方法len()是唯一对应的关系
# a1 = A('alex',81,'不详',2)
# a1.hobby = '烫头'
# a2 = A('egon',20,'不详',3)
# a3 = A('yuan',21,'不详',4)
# print(len(a1))
# print(len(a2))
# print(len(a3))
2.字典的存储
# hash
class A:
def __init__(self,name,age,sex,cls):
self.name = name
self.age = age
self.sex = sex
self.cls = cls
def __hash__(self):
return 0
a1 = A('alex',81,'不详',2)
print(hash(a1))
每一次的哈希值都不同,为什么可以直接哈希,因为object类里有__hash__方法
二。__str__ 与 __repr__ 与 print()
ps: 总结:
1.print() 想文件中写,print() 替你将数据类型转化成字符串打印出来
2.__str__ : object 类中的__str__ 就是返回一个数据类型的内存地址
l = [1,2,3,4] print(l) # 向文件中写 print替你将数据类型转化成字符串打印出来 class List: def __init__(self,*args): 5 self.l = list(args) def __str__(self): return '[%s]'%(','.join([str(i) for i in self.l])) l = List(1,2,3,4,5) print(l) #--> l.__str__() # object类中的__str__就是返回一个数据的内存地址 print(l) print(str(l)) print('%s'%l) print(obj) 的结果 是 obj.__str__()的结果 str(obj) 的结果 也是 obj.__str__()的结果 '%s'%obj 的结果 也是 obj.__str__()的结果
class Teacher: def __init__(self,name,age): self.name = name self.age = age # def __str__(self): # return "Teacher's object is %s" %self.name def __repr__(self): return "repr %s" %self.name a = Teacher('alex',18) b = Teacher('wusir',18) print(a) print(repr(b))
# repr(obj)的结果和obj.__repr__()是一样的
# '%r'%(obj)的结果和obj.__repr__()是一样的
总结:
1.实际上上述三种结果都是__str__的返回值
2.当然:如果我们不手动改写object中 的上下划线str或者repr,就会默认调用object类中的方法,默认返回的是 内存地址
思考:why? repr(1) 与 repr('1'):的打印结果不同?
因为:在整形中 定义的repr方法,与在str中定义的repr方法定义的函数方法的返回值不同。 即在class int 与 class str 中的 __repr__ 方法的返回值不同
class Teacher: def __init__(self,name,age): self.name = name self.age = age def __str__(self): return "Teacher's object %s"%self.name def __repr__(self): return 'repr function %s'%self.name a = Teacher('alex',80) b = Teacher('egon',80) print(a) print(b)
PS:总结:
1.到需要使用__str__的方法时,找不到__str__方法时,就会找__repr__方法。
2.当需要使用__repr__的方法时,找不到__repr__的方法时,就会找父类的或object的__repr__方法,这是默认返回的时内存地址
3.repr()方法是 str()方法的备胎。嘿嘿嘿(偷笑)
3.实际上:len()和 repr() 方法的返回值都是依赖__len__和__repr__方法来返回值的
三。__len__方法 与 __hash__方法
# class A:
# def __init__(self):pass
# def __len__(self):pass
# def len(obj):
# obj.__len__()
# a = A()
# a.__len__()
# len() # 为什么要归一化设计呢?
# 更接近面向函数编程,简单且节省代码
# len() obj.__len__() 返回值是一致的
# len() 的结果是依赖 obj.__len__()
# hash() 的结果是依赖 obj.__hash__()
# str() 的结果是依赖 obj.__str__()
# print(obj) 的结果是依赖 obj.__str__()
# %s 的结果是依赖 obj.__str__() # 语法糖
#
# repr() 的结果是依赖 obj.__repr__()
# %r 的结果是依赖 obj.__repr__()
# repr是str的备胎
思考:如果str与repr 我只能实现一个,那选哪个?# __str__
# __repr__ 一定是选择repr
什么是语法糖?语法糖的定义?
答:语法糖就是可以让数据结构变得更加简单,就像吃了糖一样甜。这就是语法糖。
四。__format__方法?
class Format: def __init__(self,name,age,hobby): self.name = name self.age = age self.hobby = hobby def __format__(self,format_spec): return format_spec.format(obj = self) person = Format('alex',18,'女') format_spec = '{obj.name}-{obj.age}-{obj.hobby}' print(format(person,format_spec))
五:__call__?
class Teacher: def __init__(self,name,age): self.name = name self.age = age def __call__(self): print(123) t = Teacher('wusir',18) t()
靠?方法加(),什么鬼?
对象名() 相当于调用了类内置的__call__方法
print(callable(类名)):是否可调用的
如果一个对象是否可调用,取决于这个对象对应的类是否有__call__方法
2.__eq__?
class A:pass
a = A()
b = A()
print(a == b)
返回False
因为连个对象的内存地址是不一样的,
# class A: # def __eq__(self, other): # # if self.__dict__ == other.__dict__: # return True # # __eq__() # a = A() # a.name = 'alex' # b = A() # b.name = 'egon' # print(a) # print(b) # print(a == b) # == 是由__eq__的返回值来决定的
# == 是由__eq__的返回值来决定的
3.__del__ 析构方法?
在删除一个对象的时候做一些收尾工作。
class A: def __init__(self): self.f = open('文件','w') a = A() print('aaa')
把a对象删除不用了
这是文件并没有关闭,文件没有关闭会占内存。
应该在删除对象是进行一个析构方法,用操作系统将文件关闭在删除文件
class A: def __init__(self): pass self.f = open('文件','w') def __del__(self): self.f.close() print('执行我了') a = A() del a print(a) print('aaa')
4.__new__?
__new__ 构造方法
实例化对象的时候
创建对象的过程
init 初始化
设计模式 —— 单例模式
单例模式 就是 一个类 只能有一个实例 # class A:pass # a = A() # b = A() # print(a) # print(b) # class B: # __instance = None # def __new__(cls, *args, **kwargs): # if cls.__instance is None: # obj = object.__new__(cls) # cls.__instance = obj # return cls.__instance # def __init__(self,name,age): # self.name = name # self.age = age # def func(self): # print(self.name) # a = B('alex',80) # b = B('egon',20) # print(a) # print(b) # print(a.name) # print(b.name)
5.__item__系列
# item # dic = {'k':'v'} # print(dic['k']) # class Foo: # def __init__(self,name): # self.name=name # # def __getitem__(self,item): # return self.__dict__[item] # # def __setitem__(self, key, value): # self.__dict__[key]=value # # def __delitem__(self, key): # print('del obj[key]时,我执行') # self.__dict__.pop(key) # f = Foo('alex') # # f.name = ... # print(f['name']) # f.__getitem__('name') # f['age'] = 18 # 赋值 # print(f.age) # 自带的语法 # print(f['age']) # 修改 # f['age'] = 80 # print(f['age']) # 通过实现__getitem__得到的 # del f['age'] # print(f.age) # 删除 # class Foo: # def __init__(self,name): # self.name=name # def __delattr__(self, item): # print('del obj.key时,我执行') # self.__dict__.pop(item) # f = Foo('alex') # del f.name #相当于执行了__delattr__ # # delattr(f,'name')
面试题:
# 写一个类 定义100个对象
# 拥有三个属性 name age sex
# 如果两个对象的name 和 sex完全相同
# 我们就认为这是一个对象
# 忽略age属性
# 做这100个对象的去重工作
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __hash__(self):
# hash算法本身就存在了 且直接在python中就能调用
# 姓名相同 性别相同的对象的hash值应该相等才行
# 姓名性别都是字符串
return hash(self.name+self.sex)
def __eq__(self, other):
if self.name == other.name and self.sex == other.sex:
return True
# python2.7
# 去重 set
# hash方法
# set([obj,obj]) unhashable
# hash算法 一个值 进行一系列的计算得出一个数字在一次程序执行中总是不变
#来让每一个不同的值计算出的数字都不相等
obj_lst = []
obj_lst.append(Person('alex',80,'male'))
obj_lst.append(Person('alex',70,'male'))
obj_lst.append(Person('alex',60,'male'))
obj_lst.append(Person('boss_jin',50,'male'))
obj_lst.append(Person('boss_jin',40,'male'))
obj_lst.append(Person('boss_jin',30,'male'))
obj_lst.append(Person('nezha',20,'male'))
obj_lst.append(Person('nezha',10,'male'))
obj_lst = set(obj_lst)
for obj in obj_lst:print(obj.name)
# set对一个对象序列的去重 依赖于这个对象的两个方法 hash eq
# 可hash顺带着写的
# eq来做判断
# key hash 数字 --》 内存地址 --》 value
# set hash 数字 --》 内存地址 --》 set中的元素
# 'aaa' hash
# java
# set去重 一个容器中 有相同值的内容 __eq__
# 当你这个容器中有10000个元素的时候 我判断第10000个元素
# hash算法
# 'abc'
# 'bca'
# set对一个对象序列的去重 如何判断这两个值是否相等
# 值a进行hash --> 存值
# 值b进行hash --> 判断值是否相等 -相等-> 说明是一样的
#-不相等-> 在开辟一个空间 来存放b