A.
类的初始化函数__init__, 其传递的参数一般采用"具体参数, 可变长元组参数args,可变长字典类型参数 kwargs "相互配合的方式,比如threading.Thread 的初始化函数:
代码语言:javascript复制def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
#其中 kwargs=None, 也可以写作 kwargs={}, 注意args, kwargs 需要以关键字参数的形式进行传递.
采用上述写法的好处是: 明确指定了有名称的参数(比如上例的group, target,name, daemon),同时可以接受传入的额外参数(args,kwargs 来接受). 这样,就保证了可以接受所有的参数. 如果是自己定义的class, 也可以采用这种方式进行参数传递,确保class 在实例化的时候,可以接受所有的参数.在上述的例子中,所有参数都是可选参数,而如果要传递位置参数,那么明确指出就可以了.
B.
在没有指定父类的情况下,所有类的父类默认就是object, 通常是忽略不写的. 但是如果明确指定了当前类的父类,那么关于当前类的初始化函数的参数传递规则如下: 1). 如果当前类在父类的基础上需要增加新的参数,那么直接在初始化函数__init__的参数列表中新增对应的参数就可以了,比如在上述threading.Thread 类的基础上,创建自定义的class,那么这个自定义的类可以这么写:
代码语言:javascript复制class mythread(threading.Thread): #指定父类
def __init__(self,group=None, target=None, name=None, args=(), kwargs=None, daemon=None, mypara=None)
#在父类的基础上,初始化的时候增加了新的参数: mypara,所以简单在后面的参数列表追加就可以了
super(mythread,self).__init__(*args,**kwargs)
self.newpara=mypara
2). 如果当前类不需要新增传递的参数,那么在当前类的初始化的时候,直接采用(*args,**kwargs)来接受所有参数,就更简单省事. 而有新增加的参数的时候,才使用上面描述的方式. 3). 为了确保能够继承父类的方法和属性,那么一般在当前类的初始化函数中,会首先通过super方法来调用父类的初始化函数. 比如上例的super 方法的使用,然后再执行当前类初始化时候要做的特定的action, 当然如果不调用父类的初始化函数也是可以的,这样就无法使用父类的方法以及属性了. 这其实是类的继承的一个特点.
C.
关于在class的方法里面调用 class外的函数,这时候向class传递的参数是一个函数,那么直接写函数的名称,不要把函数的名称写成字符串,这样在 class的方法中就可以使用如下的方式调用这个函数,这也是在class的方法中调用 class 之外的方法的典型用法:
代码语言:javascript复制class Thread:
... #省略源代码中的一部分...
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None): #初始化函数...
... #省略源代码中的一部分...
self._target = target #target其实就是线程所执行的函数的名称
self._args = args #线程执行的函数的元组参数
self._kwargs = kwargs #线程执行的函数的字典参数
... #省略源代码中的一部分...
def run(self):
...
self._target(*self._args, **self._kwargs) #函数调用以及参数传递
...
D.
threading.Thread 这个类没有包括线程结束的方法,这个原因是:贸然结束线程可能导致多种预测不到的问题,比如线程结束了,但是其 加锁的资源并没有释放,或者其处理的数据还没有更新到磁盘等... 而如果要结束线程,网络上主要有两种方式: 1). 用 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,SystemExit)进行强制结束. 可能带来上述的不良后果.而为了解决强制结束带来的问题,可以在强制结束之前调用 对应的 线程清理函数,首先执行相应的清理操作,然后再强制结束线程的运行. 还有一个弊端就是,如果不是通过Python解释器进行的调用,那么因为上述命令是通过触发异常来结束线程的运行,所以就无法捕获到异常,也就无法终止线程的运行了,如果是纯python编程,那么应该没有这个问题. 该方法的好处是:可以随时结束线程的运行,无论线程本身是否循环执行都可以结束. 2). 在threading这个模块中,还有一个class 叫做Event,该Event 类拥有is_Set 以及set, clear 等方法,可以用于设置标志位,所以可以在线程中通过不停检测这个标志位从而实现线程的自杀,从而结束线程的运行;该方法有一个弊端: 如果线程函数并不是循环执行,那么如何来检测这个标志位呢? 而如果线程本身就是不断循环,那么采用这种方式相对更好. 属于线程自杀结束执行.