python开发学习笔记(10)————Python高级语法

Python 高级语法

1.GIL锁

GIL:全局解释器锁
面试题:描述python GIL的概念,以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐述多线程抓取程序是否可比单线程性能有提升,并解释原因。
参考答案:
1)python语言和GIL美哟关系,仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL
2)GIL:全局解释器锁,每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程可以执行代码
3)线程释放GIL的情况:在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL。python3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或python2.x,tickets计数达到100
4)python使用多进程是可以利用多核的CPU资源的
5)多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
计算密集型:使用多进程
IO密集型:多线程、多协程

2.深拷贝和浅拷贝
1)浅拷贝

对于一个对象的顶层拷贝
通俗理解:

import copy
copy.copy 是浅拷贝
a=[1, 2]
b=[2, 3]
c=[a, b]
d = copy.copy(c)

此时 id(c)与id(d)不相同,copy.copy重新开辟了一个内存空间进行拷贝,但是id(c[0])与id(d[0])相同,说明d列表中的元素还是指向a和b,浅拷贝只拷贝了c,而不拷贝a和b
注意:使用copy.copy拷贝元组的时候,不会进行浅拷贝,只是增加一个引用,因为元组是不可变类型。

2)深拷贝
import copy
copy.deepcopy 是深拷贝
a=[1, 2]
b=[2, 3]
c=[a, b]
d = copy.deepcopy(c)

此时 id(c)与id(d)不相同,copy.copy重新开辟了一个内存空间进行拷贝,id(c[0])与id(d[0])也不同,说明d列表中的元素也进行了新的拷贝,深拷贝会拷贝所有的元素。

注意:使用copy.deepcopy时,如果拷贝对象中存在可变类型数据,那么深拷贝可以进行。

总结:如果用copy.copy、copy.deepcopy对一个全部都是不可变类型的数据进行拷贝,那么结果相同,都是引用指向;但是如果拷贝的是一个拥有可变类型的数据,即使元组是最顶层,那么deepcopy依然是深拷贝,而copy.copy还是指向。

3)其他拷贝方式

a。分片表
d = c[:] 与 d = copy.copy© 一样,属于浅copy
b。字典dict中的copy方法
d = dict(name=“123123”, age=27)
co = d.copy
属于浅拷贝

3.私有化、import、封装继承多态
1)私有化
xx:公有变量
_x:单前置下划线,私有化属性或方法,from somemodule import * 禁止导入,类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性,例如,__init__
xx_:单后置下划线,用于避免与python关键词的冲突
2)import导入模块

import yyy
from xx import yyy
from xx import *
import xxx,zzz
from xxx import yyy,nnn
import xxx as XXX
a。路径搜索
import sys
sys.path 返回一个列表
导入模块时,从这个列表中搜索模块
b。重新导入模块
已经导入模块之后,如果修改模块内容,已经导入模块的代码执行结果不会发生改变。
from imp import reload
reload(模块名)
重新导入模块
c。多个模块导入注意点
import xxx 时,创建了xxx变量,指向xxx模块,假设yyy是xxx模块中的变量,使用xxx.yyy的方式修改值时,可以修改模块中变量yyy的值。
from xxx import yyy,创建了yyy变量,指向xxx模块中yyy变量,当修改yyy的值时,发生引用指向的改变,无法修改模块中变量yyy的值。
d。封装继承多态
封装:
在使用面向过程编程时,当需要对数据处理时,需要考虑用哪个模板中的哪个函数进行操作,但是当用面向对象编程时,因为已经将数据存储到了这个独立的空间中,这个独立的空间(即对象)中通过一个特殊的变量(class)能够获取到类(模板),而且这个类中的方法是有一定数量的,与此类无关的将不会出现在本类中,因此需要对数据处理时,可以很快速的定位到需要的方法是谁,这样更方便;
全局变量是只能有一份的,当很多个函数需要多个备份时,往往需要利用其它的变量来进行存储,而通过封装会将用来存储数据的这个变量变为对象中的一个全局变量,只要对象不一样那么这个变量就可以再有1份,更方便;
代码划分更清晰。
继承:
能够提升代码的重用率 ,即开发一个类,可以在多个子功能里直接使用
继承能够有效的进行代码的管理,当某个类有问题只要修改这个类就行,而其继承这个类的子类往往不需要修改。
多态:
对象调用方法时,如果类中有,则调用类中的方法,如果没有,则到父类中去寻找。

4.方法解析顺序表MRO
1)多继承以及MRO顺序

多继承:继承自多个父类

super()进行调用父类方法,通过mro顺序调用
print(类名.__mro__) 可以打印出__init__调用的顺序
2)*args、**kwargs的另外用处拆包

*args 保存元组
**kwargs 保存关键字参数,以字典的方式
代码:

def test2(a, b, *args, **kwargs):
	pass
	
def test1(a, b, *args, **kwargs):
	test2(a, b, args, kwargs) # 相当于test2(11, 22, (33, 44, 55, 66), {“name”:”laowag”, “age”:18})
	test2(a, b, *args, kwargs) # 相当于test2(11,22,33,44,55,66,{“name”=”laowang”,”age”=18})
	test2(a, b, *args, **kwargs) # 相当于test2(11,22,33,44,55,66,name=”laowang”,”age”=18)
	
test1(11, 22, 33, 44, 55, 66, name=”laowang”, age=18)
5.类对象和实例对象访问属性的区别和property属性
1)静态方法、类方法

1>类属性、实例 属性
实例属性属于对象,类属性属于类。
实例属性通过对象来访问,类属性通过类访问
创建对象时:
a。调用__new__方法,新建一个内存空间
b。调用__init__方法,对刚刚申请的空间进行初始化
类属性在内存中只保存一份;实例属性在每个对象中都要保存一份
应用场景:通过类创建实例对象时,如果每个对象需要具有相同名字的属性,那么就使用类属性。
2>实例方法、静态方法和类方法
实例方法:由对象调用;至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self。
类方法:由类调用;至少一个cls参数;执行类方法时,自动将调用该方法的类赋值给cls。
静态方法:由类调用;无默认参数;

2)property属性
class Foo:
	def func(self):
		pass
	@property
	def prop(self):
		pass    #定义property属性
调用时
foo_obj = Foo()
foo_obj.func()
foo_obj.prop

注意:
1> 定义时,在实例方法的基础上添加@property装饰器;并且仅有一个self参数
2>调用时,无需括号

3)创建property属性的两种方式

装饰器,即在方法上应用装饰器
类属性,即在类中定义值为property对象的类属性
1>装饰器方式
在实例方法上应用@property
新式类中,三种方法

@property       #得到property属性
def price(self):
	print(“”)
@price.setter         #给property属性赋值
def price(self, value):
	print(“”)
@price.deleter        #删除property属性
def price(self):
	print(“”)

2>类属性方式

class Foo:
	def get_bar(self):
	return “laowang”
	BAR = property(get_bar)
obj = Foo()
result = obj.BAR
print(result)

property方法中有四个参数:
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.doc,此参数是该属性的描述性信息
property属性可以简化调用者在获取数据的流程。

6.私有属性和名字重整、魔法属性和方法、上下文管理
1)修改、查看私有属性、名字重整
class Test(object):
	def __init__(self, name):
self.__name = name
	a = Test(“laowang”)

python将私有属性进行名字重整,造成无法读取私有属性的假象。
上面示例中,使用a.__name 无法查看a的私有属性
使用 a._Test__name 可以查看,因为进行了名字重整。

2)魔法属性

1> __doc__
查看类的描述信息
2> __module____class__
__module__ 表示当前操作的对象在哪个模块
__class__ 表示当前操作的对象的类是什么
3> __init__
初始化方法,通过类创建对象时,自动触发执行
4> __del__
当对象在内存中被释放时,自动触发执行
5> __call__
对象后面加括号,触发执行。
obj(), 实例对象后直接加括号,直接调用call
6> __dict__
类或对象中的所有属性
7>__str__
如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
8>__getitem____setitem____delitem__
用于索引操作,如字典,以上分别表示获取,设置,删除数据
9> __getslice____setslice____delslice__
用于分片操作

3)with、上下文管理器

1>with 关键字

with open(“文件地址“,”r“) as f:

可以保证文件肯定能关闭。
2>上下文管理器
任何实现了__enter__()__exit__()方法的对象都可称之为上下文管理器。
上下文管理器对象可以使用with关键字。可以保证使用完毕或出现异常后,一定关闭资源。
文件对象实现了上下文管理器,所以可以使用with来操作文件。
实现上下文管理器的另外方式
装饰器 @contextmanager 简化了上下文管理器的实现方式。
函数前加上上面的装饰器语句,使用with关键字调用该函数即可。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值