1、GIL(全局解释器锁)
多线程:GIL只对多线程有影响,适合IO密集型,因为CPU发生等待
多进程:GIL对多进程无影响,适合计算密集型
2、深浅copy
变量赋值就是指向,变量copy也是指向
import copy
a=[1,2]
b=[3,4]
c=[a,b]
d=copy.copy(c)
e=copy.deepcopy(c)
id(a)
id(b)
id(c)
id(d)
id(e)
1)情况:生成不同的指向地址号
id(d)
id(e)
两个不同的指向地址(不同的id号),他们都生成一个自身的id,与id(c)也不同
2)情况2:深浅copy区别
id(c[0])
id(d0])
id(e[0])
c[0]与d[0] id结果相同都是指向 a ,这就是浅copy
e[0] 不是指向 a ,而是把a 完全复制一份,得到一个新的 id,这就是深copy
3)情况三:源头发生改变,后续变量指向不变,浅copy随着源头变化而变化、深copy则不变
a.append(100)
id(c[0])
id(d[0])
id(e[0])
c[0]与d[0]指向不变,但内容随着a.append的改变而改变,都变成[[1,2,100],[3,4]]
e[0]还是原先复制a 后的指向,但是内容不变,还是[[1,2],[3,4]]
4)情况四:中间变量发生改变,后续变量指向不变,因此内容也不会改变
c.append([50,60])
id(c)
id(d)
id(e)
三者指向都不变,但是c的内容变成[[1,2,100],[3,4],[50,60]] ,多了append的[50,60]
d为 [[1,2,100],[3,4]]
e为[[1,2],[3,4]]
3、python私有化
xx:公有变量
_xx:单前置下划线,私有化属性或方法,from somemodule import * 禁止导入,类对象与子类可以访问
- 私有属性和方法,原则上只能类内部调用,但是要人为约束,实际上类对象和子类都可以访问
- 禁止通过
from modules import *导入,但是允许import moules导入
__xx:双前置下划线,避免与子类中的属性名冲突,无法在外部直接访问;类实例化后,也无法访问
- Python 解释器会修改变量名,起到保护的作用,包括属性和方法
- 类对象和子类都不能访问,子类更不可重写
- 实现只读属性的场景(在封装上使用)
- 在类的上下文都起作用,而不仅仅是属性和方法
__xx__:前后双下划线,python内部方法,开发时一般不会用到这种变量名,构造方法使用,子类可以继承
xx_:单后置下划线,在变量名与关键字冲突时可以使用
_:下划线(_):临时或无关紧要的变量
4、import使用
1)import 用法
import xxx
from xxx import yyy
from xxx import *
import xxx,zzz
from xxx import yyy,ppp
import xxx as XXX #注意,如果当前模块中有 XXX 的变量,则 as 别名不可叫 XXX
2)import路径加载
sys.path #查看python 模块的路径,结果为列表
sys.path.append('/home/test/xxx')
sys.path.insert(0,'/home/test/xxx') #可以确保先搜索这个路径
3) import 重新导入问题 reload
from xxx import yyy
在同一会话中:当yyy内容发生改变后,在使用from xxx import yyy,还是原来的yyy,不是改变后的yyy
如果想在同一会话中加载改变后的yyy,则需要reload
from imp import reload
reload(aa)
aa.test()
5、类、封装、继承、多态、类对象、实例对象
1)类
坦克大战为例:类即模板,需要创建新坦克,只要调用模板(代码写起来更简洁)
class T(object):
num = 1
def __init__(self,age): #self 可以改为其他字符串,后续模块中代码也要一起修改
self.age = age
t1 = T(10)
获取
t1.__dict__
{'age':10} #获取类的属性,独有的变量/属性
获取t1实例化的类
t1.__class__
<class '__main__.T'>
1)封装
何为装饰器?
官方定义:装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
Python中总共包括三个内置装饰器:
① staticmethod
② classmethod
③ property
我们要知道 @property 装饰器的本质是 property() 函数,所以被装饰的方法就相当于 property() 函数创建的托管属性。托管属性对象是具有相应的属性 fget,fset 和 fdel(访问、设置、删除),而被 @property 装饰器装饰的对象同样也具有对应的 getter,setter 以及 deleter 方法。所以要想被 @property 装饰器装饰的函数转换为属性后也可以实现设置、删除操作,可以做如下设置:
class C:
def __init__(self):
self.score = 85
@property # @property 装饰器本身就相当于 getter 方法
def score_x(self):
if self.score < 60:
return "你妹的,不及格!"
else:
return self.score
@score_x.setter # 给 score_x 属性装饰 setter 方法
def score_x(self, value): # 附加方法与原始的特征属性相同的名称
if 0 <= value <= 100:
self.score = value
else:
print(f"输入的值 {value} 超出范围 0~100 !")
@score_x.deleter # 给 score_x 属性装饰 deleter 方法
def score_x(self): # 附加方法与原始的特征属性相同的名称
del self.score
c = C()
print(c.score_x)
c.score_x = 45
print(c.score_x)
del c.score_x
运行结果:
85
你妹的,不及格!
2)继承
重复利用代码
3)多态
4)类对象、实例对象、类属性、实例属性、类方法、实例方法、静态方法
类对象:
实例对象:
类属性:在内存中只有一份
实例属性:在每个对象中保存一份;
实例方法:不用任何修改的方法为实例方法;由对象调用;至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self;构造方法也属于实例方法
类方法:采用 @classmethod 修饰的方法为类方法;由类调用;至少一个cls参数;执行类方法时,自动将该方法的类赋值给cls
静态方法:采用 @staticmethod 修饰的方法为静态方法;静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法
在实际编程中,几乎不会用到类方法和静态方法,因为我们完全可以使用函数代替它们实现想要的功能,但在一些特殊的场景中(例如工厂模式中),使用类方法和静态方法也是很不错的选择。
比如,下面的类中就用到了实例方法:
class CLanguage:
#类构造方法,也属于实例方法
def __init__(self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
# 下面定义了一个say实例方法
def say(self):
print("正在调用 say() 实例方法")
实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。实例方法通常会用类对象直接调用,例如:
clang = CLanguage() clang.say()
运行结果:
正在调用 say() 实例方法
当然,Python 也支持使用类名调用实例方法,但此方式需要手动给 self 参数传值。例如:
#类名调用实例方法,需手动给 self 参数传值 clang = CLanguage() CLanguage.say(clang)
运行结果为:
正在调用 say() 实例方法
和实例方法最大的不同在于,类方法需要使用@classmethod修饰符进行修饰,例如:
class CLanguage:
#类构造方法,也属于实例方法
def __init__(self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"
#下面定义了一个类方法
@classmethod
def info(cls):
print("正在调用类方法",cls)
注意,如果没有 @classmethod,则 Python 解释器会将 fly() 方法认定为实例方法,而不是类方法。
类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。例如,在上面 CLanguage 类的基础上,在该类外部添加如下代码:
#使用类名直接调用类方法 CLanguage.info() #使用类对象调用类方法 clang = CLanguage() clang.info()
运行结果为:
正在调用类方法 <class '__main__.CLanguage'>
正在调用类方法 <class '__main__.CLanguage'>
静态方法需要使用@staticmethod修饰,例如:
class CLanguage:
@staticmethod
def info(name,add):
print(name,add)
静态方法的调用,既可以使用类名,也可以使用类对象,例如:
#使用类名直接调用静态方法
CLanguage.info("C语言中文网","http://c.biancheng.net")
#使用类对象调用静态方法
clang = CLanguage()
clang.info("Python教程","http://c.biancheng.net/python")
运行结果为:
C语言中文网 http://c.biancheng.net
Python教程 http://c.biancheng.net/python
6、多继承以及MRO顺序
1)一个类继承多个父类
子类中的方法名与父类相同,则子类的方法会覆盖父类的方法
子类调用父类被覆盖的方法
调用父类__init__方法有三种:
parent.__init__(self,name)
super().__init__(name) #self不用再写,调用父类、爷爷类直接用super
super(子类,self).__init__(self,name)
查看类的调用顺序:print(类名.__mro__)
2)继承不是复制
class P(object):
x=1
class S1(object):
pass
class S2(object):
pass
print(P.x,S1.x,S2.x)
S1.x=2
print(P.x,S1.x,S2.x)
print(P.x,S1.x,S2.x)
7、*args 与**kwargs
def test1(a,b,*args,**kwargs)
print('test1-----------------')
print(a)
print(b)
print(args)
print(kwargs)
def test2(a,b,*args,**kwargs)
print(a)
print(b)
print(args)
print(kwargs)
test1(a,b,args,kwargs) #这种调用,args与kwargs的值合到一个元组中,赋值给args
test1(a,b,*args,**kwargs) #这种调用才是正确的调用
test2(1,2,3,80,name='xxx')
输出如下
1
2
(3,80)
{''name:'xxx'}
test1-----------------
1
2
((3,80),{''name:'xxx'})
{}
test1-----------------
1
2
(3,80)
{''name:'xxx'}
posted on
浙公网安备 33010602011771号