重点回顾:
__enter__
返回值使用的是htop
程序查看的CPU占用情况。
单线程死循环:
while True:
pass
双线程死循环:
import threading
def doforever:
while True:
pass
t = threading.Thread(target = doforever)
t.start()
while True:
pass
双进程死循环
import multiprocessing
def doforever:
while True:
pass
t = multiprocessing.Process(target = doforever)
t.start()
while True:
pass
GIL(global interpreter lock)是全局解释器锁,它不是Python语言的特性,而是由于历史原因,使得CPython解释器在实现的时候加上的。以前guido尝试过移除GIL锁,但是移除并不是那么简单的,还要加上很多别的控制代码,所以最终的性能反而不如之前好
Guido的声明:http://www.artima.com/forums/flat.jsp?forum=106&thread=214235
The language doesn’t require the GIL – it’s only the CPython virtual machine that has historically been unable to shed it.
GIL锁的特点:
GIL面试题如下
描述Python GIL的概念, 以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因。
// libdead_loop.c
void DeadLoop(){
while(1){
;
}
}
gcc libdead_loop.c -shared -o libdead_loop.so
因为多进程可以利用多个核心,而 多线程和协程,只是实现了阻塞时期的任务切换:
import copy
copy.copy
copy.deepcopy
(唯一的深拷贝方法)import copy
a = [1,2,3]
b = copy.copy(a)
id(a)
2732216717384
id(b)
2732218239560
# 成功拷贝
import copy
a = [1,2,3]
b = [4,5,6]
c = [a,b]
d = copy.copy(c)
id(c)
2732216577864
id(d)
2732218221320
a.append(9)
c
[[1, 2, 3, 9], [4, 5, 6]]
d
[[1, 2, 3, 9], [4, 5, 6]]
# 一起受影响,所以这是 浅拷贝
import copy
a = [1,2,3]
b = [4,5,6]
c = [a,b]
d = copy.deepcopy(c)
id(c)
2732216577864
id(d)
2732217733576
a.append(8)
c
[[1, 2, 3, 9, 8], [4, 5, 6]]
d
[[1, 2, 3, 9], [4, 5, 6]]
# d不受影响,所以这是 深拷贝
拷贝元祖:
import copy
a = (1,2)
b = copy.copy(a)
id(a)
2732216884680
id(b)
2732216884680
# 对于不可变类型,因为没有拷贝的必要,所以 copy是指向同一个元素
c = copy.deepcopy(c)
id(c)
2732216884680
# 深拷贝在拷贝只有 不可变对象的元祖时,也是使用的 直接指向
import copy
a = [1,2,3]
b = [4,5,6]
c = (a,b)
d = copy.copy(c)
e = copy.deepcopy(c)
id(c)
2732217828552
id(d)
2732217828552
id(e)
2732218154952
# 对于内部含有可变对象的元祖, deepcopy就会拷贝,而copy不拷贝
a.append(9)
c
([1, 2, 3, 9], [4, 5, 6])
d
([1, 2, 3, 9], [4, 5, 6])
e
([1, 2, 3], [4, 5, 6])
几种属性/方法的定义名称:
xxxx
_xxxx
:
from abc import xxxx
导入
__xxx
:
__xxx__
:
__init__
方法子类也会有,而且会默认调用父类的__init__
xx_
:
带有__xxx
形式的属性/方法,只有在类中自己添加的时候,才会名字重整。之后自己添加的不是私有属性.
class A(object):
def __init__(self,name):
self.__name = name
def __hidden(self):
return self.__name
a = A("Miller")
print(a.__dict__)
# 名字重整的结果
# {'_A__name': 'Miller'}
print(A.__dict__)
# {'__module__': '__main__', '__init__': , '_A__hidden': , '__dict__': , '__weakref__': , '__doc__': None}
# 也有名字重整的 __hidden方法
# print(a.__name) 报错
a.__age= 10
print(a.__age)
# 10
# 这个就不是隐藏属性了
自动调用父类构造方法:
class A(object):
def __init__(self):
print("哈哈")
class B(A):
pass
b = B()
# 哈哈
# 自动调用了父亲的构造方法
继承父类构造方法
class A(object):
def __init__(self,name,age):
print("哈哈")
class B(A):
pass
b = B()
# TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
# 报错,所以说子类继承了父类的构造方法
重写父类方法
class A(object):
def __init__(self,name,age):
print("哈哈")
class B(A):
def __init__(self):
print("你好")
b = B()
# 你好
# 子类重写了父类方法
调用多个父类中的哪个方法
class A(object):
def __init__(self):
# self._name = name
print("哈哈")
class B(object):
def __init__(self):
print("嘿嘿")
class C(B,A):
pass
c = C()
# 嘿嘿
# 继承的时候,谁写在前面,就调用哪个父类的方法
from imp import reload
reload(模块名) # 注意,这个模块一定要之前导入过,才能重新导入
应用:可以在运行时修改代码,然后让程序重新带入新代码内容
开发时经常多模块,公用的内容放在一个模块中:
# common
FLAG = True
MYLIST = []
然后另外2个模块,
import common
还是 from common import MYLIST
, 他们指向的都是同一份 MYLIST
import common
,那么common.FLAG
指向的是同一个对象from common import FLAG
,那么每个模块中维护的FLAG对象不是同一份__class__
每个对象都有一个__class__
,能够获取他的类对象,从可以调用类的属性:
class A(object):
count = 10
def __init__(self,name):
self.name = name
a = A("哈哈")
print(a.__class__)
print(a.__class__.count)
print(A.__class__)
#
# 10
#
__dict__
__dict__
属性内部是对象的 属性键值对
print(a.__dict__)
# {'name': '哈哈'}
MRO
在多继承中,如果直接使用Parent.__init__(args)
的方法,会导致交叉的祖先类被多次调用构造方法:
class Parent(object):
def __init__(self, name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
print('Son1的init开始被调用')
self.age = age
Parent.__init__(self, name)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender):
print('Son2的init开始被调用')
self.gender = gender
Parent.__init__(self, name)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
Son1.__init__(self, name, age) # 单独调用父类的初始化方法
Son2.__init__(self, name, gender)
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
# 运行结果:
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
super
调用父类方法super().__init__()
super(类名, self).__init__()
每个类都有一个__mro__
,是Python解释器使用C3算法计算的,显示的就是找方法的顺序。
super()
,实际上是在__mro__
显示的元祖列表中去匹配,如果匹配到了类型,则调用的列表中的下一个类型的方法__mro__
中的顺序去查找的:class Parent(object):
count = 10
class Child(Parent):
pass
print(Child.count)
c = Child()
print(c.count)
# 10
# 10
#因为是根据 __mro__找到了父类Parent
class Parent(object):
def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('Son1的init开始被调用')
self.age = age
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('Son2的init开始被调用')
self.gender = gender
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
# 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
# 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
# super(Grandson, self).__init__(name, age, gender)
super().__init__(name, age, gender)
print('Grandson的init结束被调用')
print(Grandson.__mro__)
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
super(类名, self).方法
, 这个结果是在__mro__
中根据这个传入的类名去查找,然后调用匹配顺序的下一个类的方法。 所以super也能够灵活的调用 继承链中的方法总结:
property能够像属性一样的调用方法,比较像别的语言中的getter与setter。
class Foo:
def func(self):
pass
# 定义property属性
@property
def prop(self): # 这个地方必须只写一个self参数,不能多不能少,多了就报错
pass
# ############### 调用 ###############
foo_obj = Foo()
foo_obj.func() # 调用实例方法
foo_obj.prop # 调用property属性
注意:
self
参数,不多不少@property 这种的,都叫装饰器
另一个例子
class Pager:
def __init__(self, current_page):
# 用户当前请求的页码(第一页、第二页...)
self.current_page = current_page
# 每页默认显示10条数据
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
# ############### 调用 ###############
p = Pager(1)
p.start # 就是起始值,即:m
p.end # 就是结束值,即:n
经典类中只有一种@property
,而新式类有3种:
@property
@属性名.setter
@属性名.deleter
class Goods:
"""python3中默认继承object类
以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter @xxx.deleter
"""
@property
def price(self):
print('@property')
@price.setter
def price(self, value):
print('@price.setter')
@price.deleter
def price(self):
print('@price.deleter')
# ############### 调用 ###############
obj = Goods()
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
新式类和经典类使用这种方法是一样的
步骤:
property
方法调用传参,得到的返回值即为属性class Foo(object):
def get_bar(self):
print("getter...")
return 'laowang'
def set_bar(self, value):
"""必须两个参数"""
print("setter...")
return 'set value' + value
def del_bar(self):
print("deleter...")
return 'laowang'
BAR = property(get_bar, set_bar, del_bar, "description...")
obj = Foo()
obj.BAR # 自动调用第一个参数中定义的方法:get_bar
obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入
desc = Foo.BAR.__doc__ # 自动获取第四个参数中设置的值:description...
print(desc)
del obj.BAR # 自动调用第三个参数中定义的方法:del_bar方法
django中常用property
class Money(object):
def __init__(self):
self.__money = 0
# 使用装饰器对money进行装饰,那么会自动添加一个叫money的属性,当调用获取money的值时,调用装饰的方法
@property
def money(self):
return self.__money
# 使用装饰器对money进行装饰,当对money设置值时,调用装饰的方法
@money.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型数字")
a = Money()
a.money = 100
print(a.money)
__doc__
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print(Foo.__doc__)
#输出:类的描述信息
__module__
和 __class__
__module__
返回的是对象属于哪个模块,是一个字符串__class__
返回的是对象属于哪一个类, 是一个对象# test.py
# -*- coding:utf-8 -*-
class Person(object):
def __init__(self):
self.name = 'laowang'
# main.py
from test import Person
obj = Person()
print(obj.__module__) # 输出 test 即:输出模块
print(obj.__class__) # 输出 test.Person 即:输出类
__init__
初始化方法,而不是构造方法
__del__
class Foo:
def __del__(self):
pass
f = Foo()
del f # __del__被调用
__call__
能够让对象本身被调用:
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
__dict__
类的方法是属于类自己的属性
class Province(object):
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print('func')
# 获取类的属性,即:类属性、方法、
print(Province.__dict__)
# 输出:{'__dict__': , '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': , 'func': , '__init__': }
obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}
obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
__str__
打印对象的时候返回的内容
class Foo:
def __str__(self):
return 'laowang'
obj = Foo()
print(obj)
# 输出:laowang
__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'] = 'laowang' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__
__getslice__、__setslice__、__delslice__
class Foo(object):
def __getslice__(self, i, j):
print('__getslice__', i, j)
def __setslice__(self, i, j, sequence):
print('__setslice__', i, j)
def __delslice__(self, i, j):
print('__delslice__', i, j)
obj = Foo()
obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__
微信开发包:http://wechat-python-sdk.com/
with
上下文管理系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。
context manager 就是一个实现了 __enter__
和 __exit__
的类,可以配合with
关键字
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("entering")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, *args):
print("will exit")
self.f.close()
with File('out.txt', 'w') as f:
print("writing")
f.write('hello, python')
注意:实际返回的对象并不是__init__
返回的对象,而是先调用__init__
之后,如果碰到了with
,再去调用__enter__
方法,将这个方法返回的结果返回。
from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
f = open(path, mode)
yield f
f.close()
with my_open('out.txt', 'w') as f:
f.write("hello , the simplest context manager")
__enter__
的时候调用__exit__
的时候调用闭包就是函数内嵌套函数,返回值为内部函数,并且通常内部函数引用了外部函数的参数——闭包是一块维护了函数+变量的空间
def linecalc(k, b):
def func(x):
return k * x + b
return func
myfunc1 = linecalc(5, 1) # y = 5x+1 的线
print(myfunc1(4)) # 21
myfunc2 = linecalc(6, 1) # y = 6x+1 的线
print(myfunc2(4)) # 25
print(myfunc1(4)) # 21
nonlocal
def outer():
x = 20
def inner():
nonlocal x
print(x) # 20
x = 10
print(x) # 10
inner()
outer()
def outer():
x = 20
def inner():
print(x) # 20
inner()
def outer():
x = 20
def inner():
print(x) # 报错
x = 10
inner()
outer()
不懂装饰器,都不好意思说会python
def origin():
print("哈哈哈1")
print("哈哈哈2")
print("哈哈哈3")
def decoration():
print("===验证模块===")
origin()
print("===资源清理==="
decoration()
但是对于python来说,这样就需要把以前调用origin
的代码全部修改成decoration
, 违反了开放封闭原则。
def decoration(func):
def new():
print("===验证模块===")
func()
print("===资源清理==="
return new
def origin():
print("哈哈哈1")
print("哈哈哈2")
print("哈哈哈3")
origin() # 这是原来的origin
origin = decoration(origin) # 此时origin成了新的new
origin() # 被装饰之后的origin
def decoration(func):
def new():
print("===验证模块===")
func()
print("===资源清理==="
return new
@decoration
def origin():
print("哈哈哈1")
print("哈哈哈2")
print("哈哈哈3")
origin() # 已经是装饰过的origin了
上面代码中,加上@decoration
, 就和10.2
中,将 origin
的引用指向新的new
效果是一样的。
装饰器只能在原函数之前和之后增加功能,无法插入函数内部
def mydec(func):
def inner(paraname):
print("装饰前")
func(paraname)
print("装饰后")
return inner
@mydec
def demo(name):
print(f"我的名字是{name}")
demo("高富帅")
def mydec(func):
def inner(*args, **kwargs):
print("装饰前")
func(*args, **kwargs)
print("装饰后")
return inner
@mydec
def demo(name,*args, **kwargs):
print(f"我的名字是{name}")
print(f"======={args}=======")
print(f"======={kwargs}=======")
demo("高富帅")
def mydec(func):
def inner(*args, **kwargs):
print("装饰前")
result = func(*args, **kwargs)
print("装饰后")
return result
return inner
@mydec
def demo(name,*args, **kwargs):
print(f"我的名字是{name}")
print(f"======={args}=======")
print(f"======={kwargs}=======")
return len(args)
a = demo("高富帅",3,4,5)
print(a)
*args, **kwargs
传递参数@
就已经创建好了,而不是函数调用的时候def mydec(func):
print("装饰器运行了")
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@mydec
def demo1(*args, **kwargs):
return len(args)
@mydec
def demo2(name,age):
print(f"我叫{name},年龄是{age}")
# 调用demo1
a = demo1("高富帅",3,4,5)
print(a)
# 调用demo2
demo2("张三",18)
结果:
装饰器运行了
装饰器运行了
4
我叫张三,年龄是18
顺序: 离函数定义近的先装饰,离函数定义远的后装饰
def mydec1(func):
print("装饰器1运行了")
def inner(*args, **kwargs):
print("装饰器1的功能")
return func(*args, **kwargs)
return inner
def mydec2(func):
print("装饰器2运行了")
def inner(*args, **kwargs):
print("装饰器2的功能")
return func(*args, **kwargs)
return inner
@mydec1
@mydec2
def demo(*args, **kwargs):
return len(args)
demo()
结果:
装饰器2运行了
装饰器1运行了
装饰器1的功能
装饰器2的功能
@类名
的含义是: demo = 类名(demo)
__call__
class Decoration(object):
def __init__(self,func):
print("====装饰中====")
self.func = func
def __call__(self, *args, **kwargs):
print("=====运行装饰的功能====")
return self.func(*args, **kwargs)
@Decoration
def demo(name, *args, **kwargs):
print(f"运行打印==={name}")
return name
print(demo("haha"))
class Decoration(object):
@classmethod
def mydec(cls, func):
print("====装饰中====")
def inner(*args, **kwargs):
print("====运行装饰功能====")
return func(*args, **kwargs)
return inner
@Decoration.mydec
def demo(name, *args, **kwargs):
print(f"运行打印==={name}")
return name
class Decoration(object):
@staticmethod
def mydec(func):
print("====装饰中====")
def inner(*args, **kwargs):
print("====运行装饰功能====")
return func(*args, **kwargs)
return inner
@Decoration.mydec
def demo(name, *args, **kwargs):
print(f"运行打印==={name}")
return name
print(demo("haha"))
嵌套三层:
def outter(arg):
print("=====运行参数传递=====")
def inner(func):
print("=====运行装饰函数=====")
def core(*args, **kwargs):
print("=====运行装饰功能=====")
return func(*args, **kwargs)
return core
return inner
@outter("hello")
def demo(*args, **kwargs):
print("程序运行中")
# 结果为
=====运行参数传递=====
=====运行装饰函数=====
demo("123")
# 结果为
=====运行装饰功能=====
程序运行中
调用步骤:
outer
,将参数传递作为 outer
的参数,然后把这个函数的返回值作为装饰器outer
的返回值,调用它,将被装饰函数作为参数传入,返回值作为被装饰后的函数def set_func(level):
def decoration(func):
def newfunc(*args, **kwargs):
if level == 1:
print("level1级别验证")
elif level == 2:
print("level2级别验证")
return func(*args, **kwargs)
return newfunc
return decoration
@set_level(1)
def test1():
pass
@set_level(2)
def test2():
pass