标签 编程 下的文章

python面向对象之装饰器&类属性

前言

最近看了一下python面向对象,其实还是c++/java那套,继承、多态……但是python中有一些特殊的关于面向对象的。

@staticmethod装饰器

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

class Dog(object):
 
    def __init__(self,name):
        self.name = name
 
    @staticmethod #把eat方法变为静态方法
    def eat(self):
        print("%s is eating" % self.name)


d = Dog("ChenRonghua")
d.eat()

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

Traceback (most recent call last):
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py", line 17, in <module>
    d.eat()
TypeError: eat() missing 1 required positional argument: 'self'

想让上面的代码可以正常工作有两种办法

  1. 调用时主动传递实例本身给eat方法,即d.eat(d)
  2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了(推荐)
class Dog(object):

   def __init__(self,name):
       self.name = name

    @staticmethod
    def eat():
        print(" is eating")

d = Dog("ChenRonghua")
d.eat()

@classmethod装饰器

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

注意跟静态方法的区别,静态方法类变量和实例变量都不能访问

属性方法

属性方法的作用就是通过@property把一个方法变成一个静态属性

class Dog(object):
 
    def __init__(self,name):
        self.name = name
 
    @property
    def eat(self):
        print(" %s is eating" %self.name)
 
 
d = Dog("ChenRonghua")
d.eat()

调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

Traceback (most recent call last):
 ChenRonghua is eating
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 16, in <module>
    d.eat()
TypeError: 'NoneType' object is not callable

正常调用如下

d = Dog("ChenRonghua")
d.eat

把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

  1. 连接航空公司API查询
  2. 对查询结果进行解析
  3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以.

类的特殊成员方法

__doc__  表示类的描述信息

class Foo:

    def func(self):
        pass
 
print Foo.__doc__
#输出:类的描述信息

moduleclass

__module__表示当前操作的对象在那个模块

__class__ 表示当前操作的对象的类是什么

class C:

    def __init__(self):
        self.name = 'wupeiqi'

from lib.aa import C

obj = C()
print obj.__module__  # 输出 lib.aa,即:输出模块
print obj.__class__      # 输出 lib.aa.C,即:输出类

init 构造方法,通过类创建对象时,自动触发执行。

del

 析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

call 对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:
 
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
 
        print '__call__'
 
 
obj = Foo() # 执行 __init__
obj()       # 执行 __call__

dict 查看类或对象中的所有成员   

class Province:
 
    country = 'China'
 
    def __init__(self, name, count):
        self.name = name
        self.count = count
 
    def func(self, *args, **kwargs):
        print 'func'

#获取类的成员,即:静态字段、方法、
print Province.__dict__
# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
 
obj1 = Province('HeBei',10000)
print obj1.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'}
 
obj2 = Province('HeNan', 3888)
print obj2.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}

str 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Foo:
 
    def __str__(self):
        return 'alex li'
 
 
obj = Foo()
print obj

# 输出:alex li

getitem__、__setitem__、__delitem

用于索引操作,如字典。以上分别表示获取、设置、删除数据

class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)
 
 
obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'alex'   # 自动触发执行 __setitem__
del obj['k1']  

转载自:https://www.cnblogs.com/alex3714/articles/5213184.html

python多进程与多线程

前言

主要总结multiprocesssing 这个库的使用,其他多线程库感觉不好用……

进程池(pool)

相对于自己手写,还是这个进程池最好用,完全不用担心调度问题。

Pool 可以提供指定数量的进程供用户使用,默认是 CPU 核数。当有新的请求提交到 Poll 的时候,如果池子没有满,会创建一个进程来执行,否则就会让该请求等待。

  • Pool 对象调用 join 方法会等待所有的子进程执行完毕
  • 调用 join 方法之前,必须调用 close
  • 调用 close 之后就不能继续添加新的 Process 了

pool.apply_async

apply_async 方法用来同步执行线程,语序多个进程同时进入进程池

import multiprocessing
import os
import time

def run_task(name):
    print('Task {0} pid {1} is running'.format(name, os.getpid()))
    time.sleep(1)
    print('Task {0} end.'.format(name))

if __name__ == '__main__':
    print('current process {0}'.format(os.getpid()))
    p = multiprocessing.Pool(processes=3)  #设置进程池并发最大数量
    for i in range(6):
        p.apply_async(run_task, args=(i,))
    # for循环改为这个一样的效果      p.map(run_task,[i for i in range(6)])
    print('Waiting for all subprocesses done...')
    p.close() #关闭进程池,不允许新进程进入
    p.join()  #主进程阻塞,等待其他进程执行完成
    print('All processes done!')  #主进程结束

运行结果:

C:\Users\Archerx\AppData\Local\Programs\Python\Python36\python.exe F:/code/multi/test1.py
current process 13632
Waiting for all subprocesses done...
Task 0 pid 6788 is running
Task 1 pid 14172 is running
Task 2 pid 6872 is running
Task 0 end.
Task 1 end.
Task 4 pid 14172 is running
Task 2 end.
Task 3 pid 6788 is running
Task 5 pid 6872 is running
Task 3 end.
Task 4 end.
Task 5 end.
All processes done!

Process finished with exit code 0

pool.apply

跟单进程执行到底多了进程调度时间

import multiprocessing
import os
import time

def run_task(name):
    print('Task {0} pid {1} is running'.format(name, os.getpid()))
    time.sleep(1)
    print('Task {0} end.'.format(name))

if __name__ == '__main__':
    print('current process {0}'.format(os.getpid()))
    p = multiprocessing.Pool(processes=3)  #设置进程池并发最大数量
    for i in range(6):
        p.apply(run_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close() #关闭进程池,不允许新进程进入
    p.join()  #主进程阻塞,等待其他进程执行完成
    print('All processes done!')  #主进程结束

执行结果:

current process 12800
Task 0 pid 12172 is running
Task 0 end.
Task 1 pid 10060 is running
Task 1 end.
Task 2 pid 14540 is running
Task 2 end.
Task 3 pid 12172 is running
Task 3 end.
Task 4 pid 10060 is running
Task 4 end.
Task 5 pid 14540 is running
Task 5 end.
Waiting for all subprocesses done...
All processes done!

process类

除了pool那个很常用,但是你对自定义要求程度很高,那pool可能就满足不了你,只有用这个了

Process 类用来描述一个进程对象。创建子进程的时候,只需要传入一个执行函数和函数的参数即可完成 Process 示例的创建。

  • star() 方法启动进程,
  • join() 方法实现进程间的同步,等待所有进程退出。
  • close() 用来阻止多余的进程涌入进程池 Pool 造成进程阻塞。
multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
  • target 是函数名字,需要调用的函数
  • args 函数需要的参数,以 tuple 的形式传入
    示例:
import multiprocessing
import os

def run_proc(name):
    print('Child process {0} {1} Running '.format(name, os.getpid()))

if __name__ == '__main__':
    print('Parent process {0} is Running'.format(os.getpid()))
    for i in range(5):
        p = multiprocessing.Process(target=run_proc, args=(str(i),))
        print('process start')
        p.start()
    p.join()
    print('Process close')
    
运行结果:
Parent process 809 is Running
process start
process start
process start
process start
process start
Child process 0 810 Running 
Child process 1 811 Running 
Child process 2 812 Running 
Child process 3 813 Running 
Child process 4 814 Running 
Process close

多线程

在一个进程下开启多个线程与在一个进程下开启多个子进程的区别

别人博客,看到一个很有意思的比较

开启速度,主进程下开启线程速度较快。

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello')

if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()
    print('主进程-->线程')
    #在主进程下开启子进程
    t=Process(target=work)
    t.start()
    print('主进程-->子进程')

运行结果:
hello
主进程-->线程
主进程-->子进程
hello

进程与线程PID问题

在主进程下开启多个线程,每个线程都跟主进程的pid一样,开多个进程,每个进程都有不同的pid

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello',os.getpid())

if __name__ == '__main__':
    #part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样
    t1=Thread(target=work)
    t2=Thread(target=work)
    t1.start()
    t2.start()
    print('主进程-->线程pid',os.getpid())

    #part2:开多个进程,每个进程都有不同的pid
    p1=Process(target=work)
    p2=Process(target=work)
    p1.start()
    p2.start()
    print('主进程-->子进程pid',os.getpid())

运行结果:
hello 13002
hello 13002
主进程-->线程pid 13002
主进程-->子进程pid 13002
hello 13003
hello 13004

线程的阻塞

与进程的方法都是类似的,其实是multiprocessing模仿threading的接口

from threading import Thread
import time
def sayhi(name):
    time.sleep(2)
    print('%s say hello' %name)

if __name__ == '__main__':
    t=Thread(target=sayhi,args=('h',))
    t.start()
    t.join()
    print('主线程')
    print(t.is_alive())

线程其他相关方法

Thread实例对象的方法

  • isAlive(): 返回线程是否活动的。

    • getName(): 返回线程名。
    • setName(): 设置线程名。

threading模块提供的一些方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

线程死锁、线程同步、线程通信暂时用不到就不整理了

preView