学习笔记,仅供参考,有错必纠
文章目录
- python 学习高级篇
- 类对象的特殊方法之`__str__()`
- 类对象的特殊方法之`__new__()`
- 对象的引用计数
- 什么是引用计数
- 对象的引用计数加1的情形
- 对象的引用计数减1的情形
python 学习高级篇
# 支持多行输出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all' #默认为'last'
类对象的特殊方法之__str__()
在python的交互式界面中,我们敲入如下代码
"""
>>> class MyClass(object):
... pass
...
>>> mc = MyClass()
>>> mc
<__main__.MyClass object at 0x103f41550>
>>> print(mc)
<__main__.MyClass object at 0x103f41550>
>>> str(mc)
'<__main__.MyClass object at 0x103f41550>'
>>> repr(mc)
'<__main__.MyClass object at 0x103f41550>'
"""
"""
>>> class MyClass(object):
... def __str__(self):
... return "__str__被调用"
...
>>> mc = MyClass()
>>> mc
<__main__.MyClass object at 0x103e5c588>
>>> print(mc)
__str__被调用
>>> str(mc)
'__str__被调用'
>>> repr(mc)
'<__main__.MyClass object at 0x103e5c588>'
"""
"""
>>> class MyClass(object):
... def __repr__(self):
... return "__repr__被调用"
...
>>> mc = MyClass()
>>> mc
__repr__被调用
>>> print(mc)
__repr__被调用
>>> str(mc)
'__repr__被调用'
>>> repr(mc)
'__repr__被调用'
"""
"""
>>> class MyClass(object):
... def __str__(self):
... return "__str__被调用"
... def __repr__(self):
... return "__repr__被调用"
...
>>> mc = MyClass()
>>> mc
__repr__被调用
>>> print(mc)
__str__被调用
>>> str(mc)
'__str__被调用'
>>> repr(mc)
'__repr__被调用'
"""
'\n>>> class MyClass(object):\n... def __str__(self):\n... return "__str__被调用"\n... def __repr__(self):\n... return "__repr__被调用"\n... \n>>> mc = MyClass()\n>>> mc\n__repr__被调用\n>>> print(mc)\n__str__被调用\n>>> str(mc)\n\'__str__被调用\'\n>>> repr(mc)\n\'__repr__被调用\'\n'
类对象的特殊方法之__str__()
和__repr__()
用于自定义并返回实例对象的字符串表示形式
- 当在交互式命令行中直接打印一个实例对象时,如果在实例对象对应的类对象中实现了特殊方法
__repr__()
,会自动调用该方法;否则,会打印实例对象对应的类对象和实例对象在内存中的地址。 - 当调用内置函数print打印一个实例对象时,如果在实例对象对应的类对象中实现了特殊方法
__str__()
,会自动调用该方法;否则,如果在实例对象对应的类对象中实现了特殊方法__repr__()
,会自动调用该方法;否则,会打印实例对象对应的类对象和实例对象在内存中的地址。 - 当调用内置函数str创建字符串并且实参是一个实例对象时,如果在实例对象对应的类对象中实现了特殊方法
__str__()
,会自动调用该方法;否则,如果在实例对象对应的类对象中实现了特殊方法__repr__()
,会自动调用该方法;否则,会打印实例对象对应的类对象和实例对象在内存中的地址。 - 当调用内置函数repr创建字符串并且实参是一个实例对象时,如果在实例对象对应的类对象中实现了特殊方法
__repr__()
,在内置函数repr的内部会自动调用该方法;否则,会打印实例对象对应的类对象和实例对象在内存中的地址。
通常情况下,类对象的特殊方法__str__()
和__repr__()
的实现代码是一样的,因此当实现了其中一个后,可以把其方法名赋值给另一个的方法名。
class MyClass(object):
def __str__(self):
return 'XXX'
__repr__ = __str__
内置函数str()和repr()都返回对象的字符串表示,其区别在于:
- str()的返回值是给用户看的,更加用户友好;
- repr()的返回值是给程序开发者看的,是为调试服务的。
str('A \nB')
repr('A \nB')
'A \nB'
"'A \\nB'"
类对象的特殊方法之__new__()
当使用"类名([实参])"创建实例对象时,Python解释器的主要处理过程包括两大步:
- 调用特殊方法
__new__()
创建实例对象:首先会查找该类对象是否实现了特殊方法__new__()
,如果没有实现,则去其父类中依次查找,直到类对象object;特殊方法__new__()
会返回创建的实例对象. - 调用特殊方法
__init__()
对创建的实例对象进行初始化,__new__()
返回的实例对象会作为实参被自动传递给__init__()
的第一个形参self
.
class Parent(object):
def __new__(cls, *args, **kwargs):
print("父类的__new__()被调用,其形参cls对应实参的id:%s" % id(cls))
obj = super().__new__(cls)
print("创建的实例对象的id:%s" % id(obj))
return obj
class Child(Parent):
def __init__(self, name):
print("子类的__init__()被调用,其形参self对应实参的id:%s" % id(self))
self.name = name
print("父类的id:%s" % id(Parent))
print("子类的id:%s" % id(Child))
child = Child("Mike")
print("创建的实例对象的id:%s" % id(child))
父类的id:1968492033576
子类的id:1968492039240
父类的__new__()被调用,其形参cls对应实参的id:1968492039240
创建的实例对象的id:1968521654224
子类的__init__()被调用,其形参self对应实参的id:1968521654224
创建的实例对象的id:1968521654224
对象的引用计数
什么是引用计数
通常情况下,开发人员无需关心内存的分配和释放。当创建一个对象时,系统会自动分配一块内存以存储该对象的信息。当该对象不再被使用时,系统会进行垃圾回收以自动释放掉其占用的内存。
为了确保使用中的对象不会被销毁,Python使用引用计数来跟踪和计算内存中每个对象被引用的次数。当对象的引用计数为0时,它才可以被销毁。
对象的引用计数加1的情形
- 对象赋值给变量
- 引用对象的变量赋值给另一个变量
- 对象作为容器(例如:列表、元组、集合等)中的元素
- 对象作为函数调用时的实参
class MyClass(object):
pass
def do_sth(param):
pass
# 引用计数加1,变为1
a = MyClass()
# 引用计数加1,变为2
b = a
# 引用计数加1,变为3
L = [1, 2, a]
# 在函数的执行过程中,引用计数加1,变为4
do_sth(a)
# 当函数执行后,对实参的引用会自动销毁,因此,引用计数减1,变为3
import sys
# 在函数的执行过程中,引用计数加1,变为4
print(sys.getrefcount(a))
# 当函数执行后,对实参的引用会自动销毁,因此,引用计数减1,变为3
4
对象的引用计数减1的情形
- 对象离开它的作用域,例如:对象所在的函数执行完毕
- 对象的引用被显式销毁
- 引用对象的变量被赋予新的对象
- 从容器中删除对象,或对象所在的容器被销毁
class MyClass(object):
pass
# 引用计数加1,变为1
x = MyClass()
# 引用计数加1,变为2
y = x
# 引用计数减1,变为1
del x
# 引用计数加1,变为2
z = y
# 引用计数减1,变为1
y = 18
# 引用计数加1,变为2
l = [1, 2, z]
# 引用计数减1,变为1
del l
# 在函数的执行过程中,引用计数加1,变为2
print(sys.getrefcount(z))
# 当函数执行后,对实参的引用会自动销毁,因此,引用计数减1,变为1
2