最近学习《Python参考手册》学到Class部分,遇到了类的构造析构部分的问题:
1、什么时候构造?
2、什么时候析构?
3、成员变量如何处理?
4、Python中的共享成员函数如何访问?
------------------------
探索过程:
1、经过查找,Python中没有专用的构造和析构函数,但是一般可以在__init__和__del__分别完成初始化和删除操作,可用这个替代构造和析构。还有一个__new__用来定制类的创建过程,不过需要一定的配置,此处不做讨论。
2、类的成员函数默认都相当于是public的,但是默认开头为__的为私有变量,虽然是私有,但是我们还可以通过一定的手段访问到,即Python不存在真正的私有变量。如:
__priValue = 0 # 会自动变形为"_类名__priValue"的成员变量
3、由于Python的特殊性,全局成员变量是共享的,所以类的实例不会为它专门分配内容空间,类似于static,具体使用参看下面的例子。
测试1:
# encoding:utf8class NewClass(object): num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配 def __init__(self,name): self.name = name NewClass.num_count += 1 print name,NewClass.num_count def __del__(self): NewClass.num_count -= 1 print "Del",self.name,NewClass.num_count def test(): print "aa"
aa = NewClass("Hello") bb = NewClass("World") cc = NewClass("aaaa")
print "Over"
调试运行:
Hello 1 World 2 aaaa 3 Over DeException l Hello 2 AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF18D0>> ignored Exception AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF1970>> ignored
但是,疑问来了?为什么会这样?按照C/C++等语言的经验,不应该这样啊!经过查找资料,发现:
Python的垃圾回收过程与常用语言的不一样,Python按照字典顺序进行垃圾回收,而不是按照创建顺序进行。所以当系统进行回收资源时,会按照类名A-Za-z的顺序,依次进行,我们无法掌控这里的流程。
明白这些,我们做如下尝试:
# encoding:utf8class NewClass(object): num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配 def __init__(self,name): self.name = name NewClass.num_count += 1 print name,NewClass.num_count def __del__(self): NewClass.num_count -= 1 print "Del",self.name,NewClass.num_count def test(): print "aa"
aa = NewClass("Hello") bb = NewClass("World") cc = NewClass("aaaa")
del aa del bb del cc
print "Over"
调试输出:
Hello 1 World 2 aaaa 3 Del Hello 2 Del World 1 Del aaaa 0 Over
OK,一切按照我们预料的顺序发生。
但是,我们总不能每次都手动回收吧?这么做Python自己的垃圾回收还有什么意义?
SO,继续查找,我们还可以通过self.__class__访问到类本身,然后再访问自身的共享成员变量,即 self.__class__.num_count , 将类中的NewClass.num_count替换为self.__class__.num_count 编译运行,如下:
# encoding:utf8class NewClass(object): num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配 def __init__(self,name): self.name = name self.__class__.num_count += 1 print name,NewClass.num_count def __del__(self): self.__class__.num_count -= 1 print "Del",self.name,self.__class__.num_count def test(): print "aa"
aa = NewClass("Hello") bb = NewClass("World") cc = NewClass("aaaa")
print "Over"
结果:
Hello 1 World 2 aaaa 3 Over Del Hello 2 Del World 1 Del aaaa 0
Perfect!我们完美地处理了这个问题!
PS:
书上又提到了一些问题,在这里作补充(仅作为参考):
__new__()是唯一在实例创建之前执行的方法,一般用在定义元类时使用。
del xxx 不会主动调用__del__方法,只有引用计数==0时,__del__()才会被执行,并且定义了__del_()的实例无法被Python的循环垃圾收集器收集,所以尽量不要自定义__del__()。一般情况下,__del__() 不会破坏垃圾处理器。
实验中发现垃圾回收自动调用了__del__, 这与书上所说又不符,不知是什么原因,需要继续学习。
在创建类时,我们可以手动添加一个 __init__() 方法,该方法是一个特殊的类实例方法,称为 构造方法(或 构造函数)。 构造方法用于创建对象时使用,每当创建一个类的实例对象时, Python 解释器都会自动调用它。 Python 类中,手动添加构造方法的语法格式如下: def __init__(self,...): 代码块 注意,此方法的方法名中,开头和结尾各有 2 个下划线,且中间
问题内容: 为什么构造函数确实称为“构造函数”?它们的目的是什么?它们与类中的方法有何不同? 另外,一个班级中可以有更多人吗?我尝试了以下方法,有人可以解释一下结果吗? 最后,是运算符重载器吗? 问题答案: Python中没有函数重载,这意味着您不能拥有名称相同但参数不同的多个函数。 在您的代码示例中,您没有 过载 。发生的是第二个定义将名称重新 绑定到新方法,导致第一个方法不可访问。 至于关于构
上一个小节我们学习了 Python 的类属性和实例属性的知识点,这个小节我们还是会学习关于类的知识。这节课我们会学习类的构造方法、析构方法和实例方法。 1. 实例方法 1.1 定义 实例方法是用于访问对象实例属性的方法,语法如下: class 类: def 实例方法(self): self.属性 实例方法定义在类中,它的第一个参数 self 指向调用该方法的对象,在实例方
通过之前的学习,我们已经知道定义一个类时,我们经常会通过 __init__(self) 的方法在实例化对象的时候,对属性进行设置。 比如下面的例子: #!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __init__(self, name, age): self.name = na
本页包含内容: 存储型属性的初始赋值 定制化构造过程 默认构造器 值类型的构造器代理 类的继承和构造过程 可失败构造器 必要构造器 通过闭包和函数来设置属性的默认值 构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。 构造过程是通过定义构造器(Initializers)来实现的,这些构造器可以看做是用来创建
本文向大家介绍PHP面向对象程序设计之构造方法和析构方法详解,包括了PHP面向对象程序设计之构造方法和析构方法详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP面向对象程序设计之构造方法和析构方法。分享给大家供大家参考,具体如下: 构造方法和析构方法是对象中的两个特殊方法,它们都与对象的生命周期有关。构造方法是对象创建完成后第一个被对象自动调用的方法,这是我们在对象中使用构造方法的