__init__
,在类实例化时会自动调用的方法class MyClass:
def __init__(self):
self.i = 12345
def f(self): # 注意成员函数要加self
return self.i
# 实例化类
x = MyClass()
# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())
try/except
:检测try语句块中的错误,从而让except语句捕获异常信息并处理raise
语句自己触发异常# 一般这么写
try:
fh = open("testfile", "w")
fh.write("这是一个测试文件,用于测试异常!!")
except IOError: # 这是一个标准异常
print("Error: 没有找到文件或读取文件失败")
else:
print("内容写入文件成功")
fh.close()
# python3中没有了message属性,可直接str()或者借用sys的exc_info
try:
a = 1/0
except Exception as e: # 这个e就是异常提示信息
exc_type, exc_value, exc_traceback = sys.exc_info()
print(str(e)) # division by zero
print(exc_value) # division by zero
finally: # 无论是否发生异常都将执行最后的代码
print('over!')
# 触发异常
def func(level):
if level < 1:
raise Exception("Invalid level!", level) # 都可以输出,你写就行
# 触发异常后,后面的代码就不会再执行
func() # Exception: ('Invalid level!', 0)
# 自定义异常
class Networkerror(RuntimeError): # 继承RuntimeError
def __init__(self, arg):
self.args = arg
# self.message = arg
try:
raise Networkerror("Bad hostname")
except Networkerror as e: # 这个e就是异常提示信息
print(e.args) # 也可以输出 format(e) str(e)
大型的程序需要自定义很多的包(模块),既增强代码的可读性,也便于维护
使用import
导入内置或者自定义模块,相当于include
import my # 导入my.py 方式一
from my import test # 导入里面的一个函数test() 方式二
''
表示当前路径当前程序对导入的模块会防止重复导入,即导入后修改了模块,无法直接重新导入
# 需要使用reload模块重导
from importlib import reload # imp已弃用
reload(module_name)
# 查看帮助
help(reload) # The module must have been successfully imported before.
多模块开发注意点
需要注意:
__name__
属性# 如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性
# 使该程序块仅在该模块自身运行时执行
# Filename: using_name.py
if __name__ == '__main__':
print('程序自身在运行%s'%__name__)
else:
print('我来自另一模块%s'%__name__)
$ python using_name.py
程序自身在运行__main__ # 显示主模块
$ python
>>> import using_name
我来自另一模块using_name # 显示文件名
类比C++
virtual void func(int a){}
,特点是先不编译,不确定是哪个类调用的在Python中类似,看个例子
# python中继承就写在括号里
class MiniOS(object): # 所有类的基类
"""MiniOS 操作系统类 """
def __init__(self, name): # 构造函数
self.name = name
self.apps = [] # 安装的应用程序名称列表 list()
def __str__(self): # __xxx__(self) 叫魔法方法
"""返回一个对象的描述信息,print对象时使用"""
return "%s 安装的软件列表为 %s" % (self.name, str(self.apps))
def install_app(self, app): # 传入父类指针
# 判断是否已经安装了软件
if app.name in self.apps:
print("已经安装了 %s,无需再次安装" % app.name)
else:
app.install()
self.apps.append(app.name)
class App(object):
def __init__(self, name, version, desc):
self.name = name
self.version = version
self.desc = desc
def __str__(self):
return "%s 的当前版本是 %s - %s" % (self.name, self.version, self.desc)
def install(self): # 相当于虚函数
print("将 %s [%s] 的执行程序复制到程序目录..." % (self.name, self.version))
class PyCharm(App): # 子类继承App
pass
# 同一作用域叫重载
class Chrome(App):
def install(self): # 相当于虚函数重写; 类中的普通函数叫重定义
print("正在解压缩安装程序...")
super().install() # 要通过super调用,而不是直接用
linux = MiniOS("Linux")
print(linux)
pycharm = PyCharm("PyCharm", "1.0", "python 开发的 IDE 环境")
chrome = Chrome("Chrome", "2.0", "谷歌浏览器") # 传入子类对象
linux.install_app(pycharm) # 相当于全局函数,传入哪个子类执行哪个子类的虚方法
linux.install_app(chrome)
linux.install_app(chrome)
print(linux) # Linux 安装的软件列表为 ['PyCharm', 'Chrome']
仔细体会!
threading
创建子线程import threading
import time
def func1(num1):
for i in range(18):
print(num1)
time.sleep(0.1)
def func3(str):
for i in range(18):
print(str)
time.sleep(0.1)
def func2():
for i in range(20):
print('主线程',i)
time.sleep(0.1)
if __name__ == '__main__':
thread = threading.Thread(target=func1, args=(555,)) # 列表参数
thread2 = threading.Thread(target=func3, kwargs={
'str':'roy'}) # 关键字参数
thread.start()
thread2.start()
func2() # 主线程一般放在后面,不然会先执行完主进程
if __name__ == '__main__':
thread = threading.Thread(target=func1, args=(555,)) # 元祖形式传参
thread2 = threading.Thread(target=func3, kwargs={
'str':'roy'})# 字典形式
# 守护进程
thread.setDaemon(True)
thread.start()
# 必须都设置守护线程才会在主线程结束时退出
thread2.setDaemon(True)
thread2.start()
func2()
# 多个线程之间同时操作全局变量就会出问题,需要上锁
lock = threading.Lock() # 互斥锁
arr = 0
def lockfunc1():
lock.acquire() # 锁住
global arr # 需要拿到全局变量arr
for i in range(500):
arr += 1
print('进程1:',arr)
lock.release() # 释放锁
def lockfunc2():
lock.acquire()
global arr
for i in range(400):
arr += 1
print('进程2:',arr)
lock.release()
import multiprocessing
def func1(num1):
for i in range(18):
print(num1)
time.sleep(0.1)
def func2(str):
for i in range(18):
print(str)
time.sleep(0.1)
if __name__ == '__main__':
multi1 = multiprocessing.Process(target=func1)
multi2 = multiprocessing.Process(target=func2)# 每个进程自带一个线程
multi1.start()
multi2.start()
Precess.terminate()
终止queue = multiprocessing.Queue(3) # 默认可以存任意多数据
Python三君子:迭代器、生成器、装饰器
迭代器一般用在可迭代对象,包括:列表、字典、元祖、集合,一般用在for循环中
# 判断是否可迭代
from collections import Iterable
# 使用函数:只要可以迭代,就一定能溯源到Iterable
isinstance([], Iterable) # isinstance:是不是一个示例,即前面的属不属于后面的
isinstance(a,A) # 对象a是不是类A的实例
__iter__
方法iter()
函数:自动调用上述魔法方法,返回迭代器(对象)next()
函数,不断调用可迭代对象的__next__
方法,获取对象的下一个迭代值__iter__
和__next__
方法__iter__
方法,让它是一个可迭代对象,同时返回ClassIterator迭代器__iter__
方法next
方法即可获得ret值__next__
方法)下面这个例子也说明了迭代器原理:
class MyIterator:
def __iter__(self): # 返回迭代器对象(初始化)
self.a = 1 # 标记迭代位置
return self
def __next__(self): # 返回下一个对象
x = self.a
self.a += 1 # 可以发现,这里是得到下一个值的方法
return x
myclass = MyIterator()
myiter = iter(myclass) # 得到迭代器
print(next(myiter)) # 1
print(next(myiter)) # 2
print(next(myiter)) # 3
print(next(myiter)) # 4
print(next(myiter)) # 5
iter()
方法,这和定义相关,因为要初始化self.a,所以这不是必须的例如:range()和==xrange()==的区别
# 在python2中
range(100) # 返回0到99的列表,占用较多内存
xrange(100) # 返回生成数据的方式
# 在py3中range()相当于xrange()
range()
当然,不止for循环可以接收迭代对象,类型转换本质也是迭代器
li = list(FibIterator(15))
print(li)
tp = tuple(FibIterator(6))
print(tp)
迭代器是什么?
在实现一个迭代器时,需要我们手动返回,并实现next方法,进而生成下一个数据
可以采用更简便的生成器语法,即生成器(generator)是一类特殊的迭代器
方式一:
L = [ x*2 for x in range(5)] # [0, 2, 4, 6, 8]
G = ( x*2 for x in range(5)) # at ...
# 区别仅在于外层的(),可以按照迭代器的使用方法来使用
next(G) # 0 G此时就是一个迭代器
next(G) # 1
next(G) # 2
方式二:
yield
关键字创建生成器,特点是执行到yield即返回后面的值def create_num(all_num):
print('------1------')
a, b = 0, 1
cur = 0
while(cur<all_num):
print('------2------')
yield a # 返回a
print('返回接着执行')
a, b = b, a+b
cur += 1
if __name__ == '__main__':
obj = create_num(5)
for num in obj:
print(num)
return
和__next__
方法什么是生成器?
注:迭代器和生成器的迭代只能往后不能往前
实现简单协程代码
import time
def work1():
while True:
print("----work1---")
yield
time.sleep(0.5)
def work2():
while True:
print("----work2---")
yield
time.sleep(0.5)
def main():
w1 = work1()
w2 = work2()
while True:
next(w1)
next(w2)
if __name__ == "__main__":
main()
什么是协程:协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元
它自带CPU上下文,这样只要在合适的时机, 我们可以把一个协程切换到另一个协程;
与线程的区别:
为了更好使用协程来完成多任务,python中的greenlet
模块对其封装
# sudo pip3 install greenlet # pip 就安装到Python2上去了
from greenlet import greenlet
import time
def test1():
while True:
print "---A--"
gr2.switch()
time.sleep(0.5)
def test2():
while True:
print "---B--"
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
#切换到gr1中运行
gr1.switch() # 这个函数对yield封装
# 实际上这是假的多任务,完全交替执行
更常用的是gevent
pip3 --default-timeout=100 install gevent http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
http://mirrors.aliyun.com/pypi/simple/
sudo pip3 install gevent
,慢一点pip3 list
查看已安装库# 拿着greenlet进一步封装
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(), i)
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
# 运行发现是依次运行
多任务:在单核中各任务并发交替执行
import gevent
def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
#用来模拟一个耗时操作,注意不是time模块中的sleep
gevent.sleep(1) # 都要使用gevent里面的模块
def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(1) # 碰到耗时操作就切换
def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(1)
g1 = gevent.spawn(f1, 5) # 创建一个协程
g2 = gevent.spawn(f2, 5) # 目标函数,参数
g3 = gevent.spawn(f3, 5)
g1.join() # join会阻塞耗时
g2.join() # 加入并执行
g3.join() # 会等待所有函数执行完毕
# 相当于在函数之间切换,即所谓的自带CPU上下文,节省资源
线程依赖于进程,协程依赖于线程;协程最小
from gevent import monkey # 补丁,自动转换time等为gevent
import gevent
import random
import time
def coroutine_work(coroutine_name):
for i in range(10):
print(coroutine_name, i)
time.sleep(random.random())
gevent.joinall([
gevent.spawn(coroutine_work, "work1"),
gevent.spawn(coroutine_work, "work2")
])
协程是什么?
from gevent import monkey # 即运行时替换,python动态性的体现!
import gevent
import urllib.request
import random
# 有耗时操作时需要
monkey.patch_all()
def my_downLoad(url):
print('GET: %s' % url)
resp = urllib.request.urlopen(url)
# file_name = random.randint(0,100)
data = resp.read()
with open(file_name, "wb") as f:
f.write(data)
def main():
gevent.joinall([
gevent.spawn(my_downLoad, "1.jpg", 'https://rpic.douyucdn.cn/live-cover/appCovers/2021/01/10/9315811_20210110043221_small.jpg'),
gevent.spawn(my_downLoad, "2.jpg", 'https://rpic.douyucdn.cn/live-cover/appCovers/2021/01/04/9361042_20210104170409_small.jpg'),
gevent.spawn(my_downLoad, "3.jpg", 'https://rpic.douyucdn.cn/live-cover/roomCover/2020/12/01/5437366001ecb82edfe1e098d28ebc36_big.png'),
])
if __name__ == "__main__":
main()