九.python面向对象(双下方法内置方法)
一. 内置方法
1.__call__
class Da(object): def __init__(self,a1,a2): self.a1=a1 self.a2=a2 def cc(self): print("我是啊哈哈哈")
def __call__(self, *args, **kwargs): print(self.a1) print(self.a2) print(args) print(kwargs) print("对象自动执行!!!!!!!!!!!!!!!!!!!1") obj=Da(11,22) print(obj.a1) print(obj.a2) print("**********************************************8") # 这是使用__call__ 方法 对象传参数自动执行 obj(1,2,3,name="张三",age=555)
# 11
# 22
# **********************************************8
# 11
# 22
# (1, 2, 3)
# {'name': '张三', 'age': 555}
# 对象自动执行!!!!!!!!!!!!!!!!!!!1
2. __getitme__
class Da(object):
def __init__(self, a1, a2):
self.a1 = a1
self.a2 = a2
@property
def cc(self):
print("我是啊哈哈哈")
def __getitem__(self, item):
# print(item)
print(self.a1)
self.cc
return item
# return self.__dict__[itme]
obj = Da(11, 22)
aa = obj["k1"]
print(aa) # k1
print("*********************************")
bb = obj["name", "哈哈哈", "66666"]
print(bb) # ('name', '哈哈哈', '66666')
# 11
# 我是啊哈哈哈
# k1
# *********************************
# 11
# 我是啊哈哈哈
# ('name', '哈哈哈', '66666')
3.__setitem__
# __setitem__ class Da(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __setitem__(self, key, value): print(key,value) print(self.a1) self.cc() # self.__dict__[key]=value obj = Da(11, 22) obj.cc() print("***********************") aa=obj["k1"]=588888 # 我是啊哈哈哈 # *********************** # k1 588888 # 11 # 我是啊哈哈哈
4.__delitme__
# __delitme__ class Da(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __delitem__(self, key): print(key) # del self.__dict__[key] obj = Da(11, 22) obj.cc() print("*****************************************") del obj["lover"] print(obj.__dict__) # 我是啊哈哈哈 # ***************************************** # lover # {'a1': 11, 'a2': 22}
5.__iter__
# __iter__ class Da(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __iter__(self): # return iter([11,22,333]) yield 1 yield 22 a=Da(1,2) for i in a: print(i) # 如果 要把不可迭代对象 -》可迭代对象 # 在类中定义 __iter__方法 # iter 内部返回一个迭代器 生成器也是迭代器的一种 所以生成器也可以 # 1 # 22
6 . __getattr__
class Da(object): num=666 def __init__(self,name): self.name=name def aa(self): print(f'我的名字叫---{self.name}') def __getattr__(self, item): # print("我是") print(item) cc=Da("张无忌") cc.age #调用了一个不存的属性 才会触发 __getattr___ cc.bb # age # bb
class Test(object):
def __init__(self, name):
self.name = name
def __getattr__(self, value):
if value == 'address':
return 'China'
test = Test('美国')
print(test.name)
print(test.address)
test.address = '北京'
print(test.address)
# 美国
# China
# 北京
# __getattribute__ 查找属性无论是否存在,都会执行
class Da(object):
def __init__(self,age):
self.age=age
def __getattribute__(self, item):
print(item,"嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡嗡")
print("********************")
# print(self.age)
aa=Da(55)
aa.bbbbbbbb
print(aa.age)
class Test(object):
def __init__(self, name):
self.name = name
def __getattribute__(self, value):
if value == 'address':
return 'China'
test = Test('上海')
print(test.name)
print(test.address)
test.address = '北京'
print(test.address)
# None
# China
# China
7. __setattr__
class Da(object): num=666 def __init__(self,name): self.name=name def aa(self): print(f'我的名字叫---{self.name}') def __setattr__(self, key, value): self.__dict__[key] = value print(key,value) cc=Da("张无忌") # __setattr__ 设置属性时会促发 __setattr__ cc.age=18 cc.hod="篮球" print(cc.__dict__) # name 张无忌 # age 18 # hod 篮球 # {'name': '张无忌', 'age': 18, 'hod': '篮球'}
8.__delattr__
# __delattr__ 删除一个会促发这个方法 class Fa(object): def __init__(self, name): self.name = name def __setattr__(self, key, value): if type(value) is str: print("执行__setattr__方法", key, value) self.__dict__[key] = value else: print("必须是字符串") def __delattr__(self, item): print("执行 __delattr__ 方法", item) a4 = Fa("张三") a4.age = "25岁" a4.sex = "男" a4.shenggao = 188 # type 是数字就添加不进去 print(a4.__dict__) del a4.name # __delattr__ 删除一个会促发这个方法 """执行__setattr__方法 name 张三 执行__setattr__方法 age 25岁 执行__setattr__方法 sex 男 必须是字符串 {'name': '张三', 'age': '25岁', 'sex': '男'} 执行 __delattr__ 方法 name """
9. __new__ __init__
class Da(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __new__(cls, *args, **kwargs): print(1) obj = Da(11, 22) # print(obj.a1) 执行不到 # 1 print("************************************************************************************88") # 注意 在类中 使用__init__初始化函数前 是自动默认会执行__new__构造方法 # 虽然我们不用添加__new__ 但是我们要知道 在使用 __init__初始化 前 python 内部就自动调用了 __new__构造方法 class Da(object): def __init__(self, a1, a2): print("这里是初始化") self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __new__(cls, *args, **kwargs): print("这里是构造方法") print(cls) return object.__new__(cls) # 构造方法必须返回 object.__new__(cls) 才能执行__init__初始化对象 obj = Da(11, 22) print(obj.a1) # 这里是构造方法 # <class '__main__.Da'> # 这里是初始化 # 11
# __new__ 的作用
# # 1、__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。
# # 假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。
#
#
# # 3、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))
# # __new__出来的实例,或者直接是object的__new__出来的实例
#
# # 4、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
10 . __add__
# __add__ # 对象可以相加 加减 乘 除 class Da(object): def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def cc(self): print("我是啊哈哈哈") def __add__(self, other): return self.a1+other.a1 a=Da(1,2) b=Da(100,20) print(a+b) # 101
11. __del__
# 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做"清理善后" 的工作 # (例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。 # 析构函数 :__del__()释放对象自动调用 class person(object): def run(self): print("run") def __init__(self, name, age, height, weight): self.name = name self.age = age self.height = height self.weight = weight def __del__(self): print("这里是析构函数")
per = person("张三", 25, 300, 100) # 释放对象 就相当于删除了 就不能访问了 这是手动释放 del per # 在函数里定义的对象会在函数结束时自动释放(删除) 可以减少内存浪费空间 def fun(): per2 = person("李四", 1000, 2000, 30000) print(per2.name) fun()
#这里是析构函数
# 李四
# 这里是析构函数
# __del__也称之为析构方法
#
# __del__会在对象被删除之前自动触发
class People:
def __init__(self, name, age):
self.name = name
self.age = age
self.f = open('test.txt', 'w', encoding='utf-8')
def __del__(self):
print('run======>')
# 做回收系统资源相关的事情
self.f.close()
obj = People('egon', 18)
del obj # del obj会间接删除f的内存占用,但是还需要自定制__del__删除文件的系统占用
print('主')
# run======>
# 主
13. __len__
# __len__ 和 len配合使用 class Students(object): def __init__(self, *args): self.names = args def __len__(self): return len(self.names) aa=Students("111",222) print(aa) print(len(aa)) # 2
14. __str__
# __str__()函数的作用: # 不知道大家再写程序是,打印一个实例化对象时,打印的其实时一个对象的地址。而通过__str__()函数就可以帮助我们打印对象中具体的属性值,或者你想得到的东西。 # # 因为再python中调用print()打印实例化对象时会调用__str__()如果__str__()中有返回 class ss: def __init__(self,age,name): self.age = age self.name = name def __str__(self): return str(self.age)+",,wozenmezhemeshuai,,"+self.name s = ss(21,'aitebao') print(s) # 21,,wozenmezhemeshuai,,aitebao
15. __hash__
# __hash__ hash() 用于获取取一个对象(字符串或者数值等)的哈希值。 class F(object): def __init__(self,name,sex): self.name=name self.sex=sex def __hash__(self): return hash(self.name+ self.sex) a=F("张三","男") b=F("张三","1111") print(hash(a)) print(hash(b))
16.__eq__
# 如果不实现__eq__方法,那么自定义类型会调用默认的__eq__方法, 通过默认方法进行比较的相等条件相当严格,只有自己和自己比才会返回True,表现如下 # __eq__ # class B(object): # def __int__(self,name): # self.name=name # def __eq__(self,other): # if self.name==other.name: # return True # c1=B("张三") # c2=B("李四") class Item: def __init__(self, name): self. name= name def __eq__(self, other): if self. name== other. name: return True else: return False first = Item('hello') second = Item('hello') print(first == second) # True
17.__slots__
__slots__是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性) 使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
-
字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
-
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
class Foo: __slots__='x' f1=Foo() f1.x=1 f1.y=2#报错 print(f1.__slots__) #f1不再有__dict__ class Bar: __slots__=['x','y'] n=Bar() n.x,n.y=1,2 n.z=3#报错
# __slots__ 省内存 class Person(object): # 意思__slots__ 里面定义的属性 在实例化对象赋值时 只能使用里面定义好了的字段 不然会报错 这样会省内存 __slots__ = ("name", "age", "speak") per = Person() per.name="哈哈哈哈" per.age=666 per.speak=4444444 # 意思就是只能添加__slots__里面定义的属性 #per.aa=6666 #会报错因为__slotl__里面没有定义 # 使用__slots__时 __dict__ 也不能用 print(per.__slots__) print(Person.__slots__) print("*************************************************************************8") class Foo: __slots__=['name','age'] f1=Foo() f1.name='alex' f1.age=18 print(f1.__slots__) # ['name', 'age'] f2=Foo() f2.name='egon' f2.age=19 print(f2.__slots__) # ['name', 'age'] # f1与f2都没有属性字典__dict__了,统一归__slots__管,节省内存 print(Foo.__dict__) # {'__module__': '__main__', '__slots__': ['name', 'age'], 'age': <member 'age' of 'Foo' objects>, 'name': <member 'name' of 'Foo' objects>, '__doc__': None}
from types import MethodType # 创建一空类 class Person(object): # 想添加什么属性就写在里面 __slots__ = ("name", "age", "speak") per = Person() per.name = "张师傅" print(per.name) # 动态的添加方法 必须引入一个模块 def say(self): print("动态的添加方法" + self.name) print("啊哈哈哈哈哈哈哈") per.speak = MethodType(say, per) per.speak() """ 思考: 如果我们想要 限制实例的属性怎么办 比如 只允许给对象添加name age height 特定的属性 解解方法: 定义类的时候 定义一个特殊的属性 (__slots__)可以限制动态属性的添加 """ per.age = 222222 print(per.age) # 张师傅 # 动态的添加方法张师傅 # 啊哈哈哈哈哈哈哈 # 222222
from types import MethodType # 创建一空类 class Person(object): pass per = Person() per.name = "张师傅" print(per.name) # 动态的添加方法 必须引入一个模块 def say(self): print("动态的添加方法" + self.name) per.speak = MethodType(say, per) per.speak() # 张师傅 # 动态的添加方法张师傅 print(per.__dict__) # 张师傅 # 动态的添加方法张师傅 # {'name': '张师傅', 'speak': <bound method say of <__main__.Person object at 0x0000025D818888D0>>}
18 __doc__返回类的注释信息
class Foo: '我是描述信息' pass print(Foo.__doc__) # 我是描述信息 print("**********************************************") # 该属性无法继承给子类 class Foo: '我是描述信息' pass class Bar(Foo): pass print(Bar.__doc__) #该属性无法继承给子类 # None
19 .__class__ __module__