版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
文章目录
1、isinstance
class Animal:
pass
if __name__ == '__main__':
animal=Animal()
print(isinstance(animal,Animal))
输出:
True
2、__getitem__
、__setitem__
、__delitem__
- 以字典形式访问的是
__getitem__
系列,如animal["name"]
- 以“.”的形式访问的是
__getattr__
系列,如animal.name
class Animal:
def __init__(self,name):
self.name=name
def __getitem__(self, item):
print("访问的是【%s】%item")
if __name__ == '__main__':
animal=Animal("佩奇")
animal["name"] #属性存在
输出:
访问的是【%s】%item
3、__str__
和__repr__
3.1、__str__
- 类中默认有个
__str__
方法 __str__
方法类似Java中的toString
方法- 必须要有返回值,且必须是字符串
class Animal:
def __init__(self,name):
self.name=name
def __str__(self):
return "name的属性是%s,%self.name"
if __name__ == '__main__':
animal=Animal("佩奇")
print(animal)
输出:
name的属性是%s,%self.name
3.2、__repr__
__repr__
功能和__str__
基本一致- 不同是
__repr__
是在python解释器中调用的
3.2、__str__
和__repr__
共存
__str__
和__repr__
共存,会调用__str__
方法- 类中只有
__repr__
,没有__str__
才会调用__repr__
4、__format__
4.1、__format__
触发的条件
- 当format的参数传入类的实例对象时会调用
__format__
方法
class Animal:
def __init__(self,name):
self.name=name
def __format__(self, format_spec):
print("执行了__format__")
return "__format__的返回值"
if __name__ == '__main__':
animal=Animal("佩奇")
print(format(animal))
输出:
执行了__format__
__format__的返回值
4.2、__format__
实例演示
class Animal:
format_dic = {
"1": "姓名:{0.name}",
"2": "姓名:{0.name},年龄:{0.age}"
}
def __init__(self, name, age):
self.name = name
self.age = age
def __format__(self, format_spec):
if not format_spec or format_spec not in self.format_dic:
format_spec="1" #如果传入的参数是空,则默认为"1"
fm = self.format_dic[format_spec]
return fm.format(self)
if __name__ == '__main__':
animal = Animal("佩奇", 1)
print(format(animal, "1"))
print(format(animal, "2"))
print(format(animal)) # 不传参,用默认
print(format(animal, "aaa")) # 传参不正确,用默认
输出:
姓名:佩奇
姓名:佩奇,年龄:1
姓名:佩奇
姓名:佩奇
5、__slots__
5.1、__slots__
的介绍
__slots__
是一个类变量- 变量值可以是列表、元组,或者可迭代对象
- 也可以是一个字符串(意味着所有实例只有一个数据属性)
- 使用“.”来访问属性,本质是在访问类或者对象的
__dict__
属性字典 - 类的字典是共享的,而每个实例的是独立的
5.2、为什么使用__slots__
- 字典会占用大量内存,如果有一个属性很少的类,但是有很多实例,为了节省内存可以使用
__slots__
取代实例的__dict__
- 当定义
__slots__
后,__slots__
就会为实例使用一种更加紧湊的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个 - 字典,这跟元组或列表很类似。在
__slots__
中列出的属性名在内部被映射到这个数组的指定小标上。 - 使用
__slots__
后,不能再给实例添加新的属性,只能使用__slots__
中定定义的那些属性名 - 注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。
- 另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。
- 大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义
__slots__
比如在程序中需要创建某个类的几百万个实例对象 。 __slots__
的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__
可以达到这样的目的,但是这个并不是它的初衷。- 更多的是用来作为一个内存优化工具。
class Animal:
__slots__=["name","age"]
def __init__(self,name,age):
self.name=name
self.age=age
if __name__ == '__main__':
animal=Animal("佩奇",1)
#print(animal.__dict__) #__dict__这个属性将不再支持
print(animal.__slots__)
6、__doc__
__doc__
属性无法继承给子类
class Animal:
'类的描述信息'
pass
if __name__ == '__main__':
animal=Animal()
print(animal.__doc__)
输出:
类的描述信息
7、__module__
、__classs__
__module__
返回的是该对象是引用的哪个模块- 如果是当前模块,输出
__main__
__classs__
返回的是类名
class Animal:
pass
if __name__ == '__main__':
animal = Animal()
print(animal.__module__)
print(animal.__class__)
8、__del__
- 析构函数,当对象在内存中被释放时,自动触发执行
- 此方法一般无须定义,因为Python是一门高级语言,程序员无需关心内存的分配和释放,所以析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
9、__call__
- 类中定义了
__call__
,可以像这样animal()
,调用实例,并且触发__call__
class Animal:
def __call__(self, *args, **kwargs):
print("执行了__call__")
pass
if __name__ == '__main__':
animal=Animal()
animal #不会触发__call__
animal() #会触发__call__
输出:
执行了__call__
10、__next__和__iter__实现迭代器协议
10.1、什么是迭代器协议
-
迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)
-
可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)
-
协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。
10.2、将类变成可迭代对象
- 需要实现__iter__()方法
- 需要实现 next
- 需要引起一个StopIteration异常,以终止迭代
class A:
def __init__(self,n):
self.n=n
def __iter__(self,n):
return self
def __next__(self):
if self.n==5:
raise StopIteration("迭代终止了")
self.n+=1
return self.n
if __name__ == '__main__':
a=A(1)
print(a.__next__())
print(next(a))
print(next(a))
print(next(a))
输出:
2
3
4
5
10.3、迭代器打印斐波那契数列
- 斐波那契数列:这个数列从第3项开始,每一项都等于前两项之和
class Fib:
def __init__(self):
self._a=1
self._b=1
def __iter__(self):
return self
def __next__(self):
if self._a>50:
raise StopIteration("终止了")
self._a,self._b=self._b,self._a+self._b
return self._a
if __name__ == '__main__':
fib=Fib()
for i in fib:
print(i)
输出:
1
2
3
5
8
13
21
34
55
11、描述符__get__、__set__、__delete__
- 描述符是新式类中至少实现了
__get__、__set__、__delete__
方法中的一个 - 也被称为描述符协议
11.1、触发方式
__get__
调用一个属性时,触发__set__
为一个属性赋值时,触发__delete__
采用del删除属性时,触发
class A:
def __get__(self, instance, value):
print("执行了__set__")
class B:
x=A() #B类中调用了A类
if __name__ == '__main__':
b=B()
b.x #此时触发A中的__get__ 方法
输出:
执行了__set__
11.2、描述符的分类
- 数据描述符:至少实现了
__get__
和__set__
- 非数据描述符:没有实现
__set__
11.3、描述符的注意事项
- 描述符本身应定义成新式类,被代理的类也应是新式类
- 必须把描述符定义成这个类的属性,不能定义到构造函数中
- 严格遵循优先级
- 优先级由高到低分别是:
- 类属性
- 数据描述符
- 实例属性
- 非数据描述符
- 找不到的属性触发
__getattr__
12、上下文管理协议__enter__
、__exit__
12.1、触发条件
with Animal() as a:
触发__enter__
- whith块下面的语句执行完触发
__exit__
- whith中的语句抛出异常时也会触发
__exit__
- whith中的语句抛出异常时:
__exit__
若返回True表示,已处理了异常__exit__
若返回False表示,将此异常抛出
__exit__
运行结束就代表了with语句结束
class Animal:
def __enter__(self):
print("执行了enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("执行了exit")
if __name__ == '__main__':
animal=Animal()
with Animal() as a:
print("第一步")
print("第二步")
print("第三步")
输出:
执行了enter
第一步
第二步
第三步
执行了exit