python提高
GIL(全局解释器锁)
- 首先,Python 和 GIL 没有半毛钱关系,仅仅只是Cpython(解释器)中难以移除GIL。
- GIL 只对线程有影响,每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,所以一个程序是多线程,一定是假的多任务。
- Python使用多进程是可以利用多核的CPU资源的
计算密集型:进程(因为不需要等待,线程的话效率不高)
io密集型:线程、协程(有等待,在等待时可做其它事)
- 解决GIL的问题
①是可以换一个解释器,因为GIL是cpython解释器所存在的问题
②可以换一种语言写多线程,Python作为胶水语言,可调用多门语言来用
拷贝(浅和深)
浅拷贝
- 用
copy
模块中的copy()
方法可完成浅拷贝 - 如果把
a = b
算入拷贝的话,它就是浅拷贝,只是把b
标签指向 指向a
的数据空间,并不是拷贝了a
里面的数据 - 如果数据有多层,就只会复制 最顶层 的那个列表,即指定拷贝哪一层就只拷贝那一层,里面的数据不会拷贝
- 浅拷贝无法拷贝不可变数据类型,仅仅是指向(不可变类型无法修改,拷贝无意义)
深拷贝
- 用
copy
模块中的deepcopy()
方法可完成深拷贝 - 会拷贝所有层次
import导入模块
-
在一存储全局变量的模块,在主程序导入时,要用
import 模块名
不要用
from 模块名 import 变量名
前者导入后,可以用
模块名.变量名
修改全局变量,后者导入后,用变量名=**
修改时,实则是定义的一个新的局部变量,无法修改更新全局变量 -
模块被导入后,重新导入模块不能用
import 模块名
需用reload
重新导入
from imp import reload
reload(模块名)
多继承及MRO顺序
- 在Python中,所有的 函数名 和 方法名 实际都只是 变量名
在多继承中调用父类被重写的方法:
-
①
父类名.方法名(self, name)
- 注:需传递参数
self
问题:
如图:有四个类,其中继承关系如图,四类中都有同一个方法,即各自重写了父类的方法,并在各自里面用 ① 方式调用各自父类的被重写的方法,而最后的 结果 是 Parent 类里的方法被调用了两次,这就多余了,如果该方法是启动线程之类的,这就非常的浪费资源
- 注:需传递参数
-
②
super.方法名(name, *args, **kwargs)
-
注:super 不需要传递
self
-
super
不只是简单的调用父类的方法,它的调用顺序是由 C3算法 来决定的,如若想查看其顺序,可用__mro__
来查看print(Grandson.__mro__) # ####查看结果##### (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
这就是 C3算法 算出来的调用顺序
-
-
③ super(类名, self).方法名(xxx, xxx)
- 这中方式是指定要调用的类名,实则它是拿着这个类名去上面的 MRO 顺序表中去找
小试牛刀:
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
结果
1 1 1
1 2 1
3 2 3
使你困惑或是惊奇的是关于最后一行的输出是 3 2 3 而不是 3 2 1。为什么改变了 Parent.x 的值还会改变 Child2.x 的值,但是同时 Child1.x 值却没有改变?
这个答案的关键是,在 Python 中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到(如果这个被引用的变量名既没有在自己所在的类又没有在祖先类中找到,会引发一个 AttributeError 异常 )。
因此,在父类中设置 x = 1 会使得类变量 x 在引用该类和其任何子类中的值为 1。这就是因为第一个 print 语句的输出是 1 1 1。
随后,如果任何它的子类重写了该值(例如,我们执行语句 Child1.x = 2),然后,该值仅仅在子类中被改变。这就是为什么第二个 print 语句的输出是 1 2 1。
最后,如果该值在父类中被改变(例如,我们执行语句 Parent.x = 3),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是 Child2)。这就是为什么第三个 print 输出是 3 2 3。
不定长参数
-
为避免多继承报错,使用不定长参数,接受参数
*args
=====> 元组-
**kwargs
=====> 字典 - 不定长参数不仅可当作形参,也可以当作当作实参进行传递,当然传递时要加上 * 号,不然,传递时只填
(a, args, kwargs)
的话,args 和 kwargs 会被当作一个元组传递
类里面的方法
-
方法包括:实例方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
-
实例方法:由对象调用,至少一个
self
参数def test1(self): pass
-
类方法:由类调用,至少一个
cls
参数@classmethod def test2(cls): pass
-
静态方法:由类调用,无需参数
@staticmethod def test3(): pass
property属性
-
一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法
# ############### 定义 ############### class Foo: def func(self): pass # 定义property属性 @property def prop(self): pass # ############### 调用 ############### foo_obj = Foo() foo_obj.func() # 调用实例方法 foo_obj.prop # 调用property属性
注:调用不需要用 ()
-
Python的property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回。
-
python2 经典类 只有上面这一种
property
属性,而 python3 新式类 除了上面这种还有其它的两种property
属性# ############### 定义 ############### 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对象的类属性
-
当使用 类属性 的方式创建 property 属性时,经典类 和 新式类 无区别,即 Python2 和 Python3 都可以这样创建
class Foo: def get_bar(self): return 'laowang' BAR = property(get_bar) # 看这里!! obj = Foo() reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值 print(reuslt)
-
property 方法中有个四个参数 (一般第一二个参数用得多)
- 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
- 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
- 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
- 第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息
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方法
property 属性例题
class Goods(object): def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 def get_price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price def set_price(self, value): self.original_price = value def del_price(self): del self.original_price PRICE = property(get_price, set_price, del_price, '价格属性描述...') obj = Goods() obj.PRICE # 获取商品价格 obj.PRICE = 200 # 修改商品原价 del obj.PRICE # 删除商品原价
with 打开文件
def m1():
f = open("output.txt", "w")
f.write("python之禅")
f.close()
这样写有一个潜在的问题,如果在调用 write 的过程中,出现了异常进而导致后续代码无法继续执行,close 方法无法被正常调用,因此资源就会一直被该程序占用者释放
-
用 with 打开文件
def m3(): with open("output.txt", "r") as f: f.write("Python之禅")
这种方式是不是更加的简洁
open
方法的返回值赋值给变量 f,当离开with
代码块的时候,系统会自动调用f.close()
方法,with
的作用和使用try / finally
语句是一样的
END…..