做下读后的核心观点记录。
因为none值和0等,在判断语句中都类似false,可能跟正常情况冲突。python更推崇抛出异常的方式来处理特殊情况。所以异常情况可以直接抛出自定义的异常,让外面处理,没有异常,都是正常值。
代码里某条表达式中使用了变量,python解释器如何寻找?
给变量赋值,有所不同:
python3,nonlocal声明变量表示赋值时在上层作用域中查找该变量,不会延伸到全局作用域
python2,没有nolocal。可以用一个[]中的下标,赋值来替代。例如found[0] = True。这样的赋值会向上层去找作用域。
当调用生成器的next函数时,会执行到下一个yield表达式,并将返回yield的值
这样会节省内存,输入量。
生成器是有状态的,只能迭代1次。造成枯竭。
可以写个容器类,实现__iter__()方法(里面要yield返回每次迭代的东西)。这样for去迭代的时候,每次都会生成一个新的iter对象。
可变数量参数(star args)
def myfunc(*args, **kwargs)
变长参数在传给函数时,先全部转化为元组,这时候生成器会占用大量内存,导致问题。因此适用场景要注意,参数数量不能过多。
在变长参数上增加其它的位置参数,可能产生难以排查的bug。
可以使用*来展开list,**展开字典,传给函数。
增加参数时不影响。
Python3
*号后的参数,只能以关键字参数的形式赋值
python2
使用**kwarg,不定参数,字典形式。pop检查,不符合报错
类内部用字典或列表做底层数据结构,嵌套超过2层就要考虑重构了。使用辅助类来简化逻辑。
拆分后,类和代码可能会变多,但可维护性和逻辑简单了。
类似于静态的new对象的方法。
python2
super(ConcretClass, self).__init__(paras)
python3
super(__class__, self).__init__(paras)
super().__init(paras)
作者不推崇使用多重继承。
mix-in是一种小型类,只定义了一套方法,没有定义实例属性,不要求调用__init__
两个下划线开头为private。
实例不能访问,子类无法访问父类的private属性,类方法可以访问。
内部机制:定义的私有变量编译器会改名,例如:ExampleClass.__p私有属性,编译器会将此私有变量改名为_ExampleClass__p。
所以私有变量在外部也是可以直接访问的,python无法保证private字段的私密性。
为了更便于继承等,不要使用private类型,有隐私要求的可使用protected类型(代码规范,不是强制),一个下划线。并在文档中详细说明。
有个场景可考虑使用private,父类属性名字很常见,子类又不受自己控制,可能引起子类混淆时。
因为可能忘记实现一些方法,例如__len__,__getitem__等,所以通过继承collections.abc模块里的抽象类来防止遗忘。
编写新类时,可以直接操作简单的public属性,而不是实现set和get方法
如果访问对象的某个属性时,需要表现出特殊的行为,那就用@property来定义;
@property遵循最小惊讶原则,而不应该产生奇怪的副作用。
@property执行得迅速一点,缓慢复杂工作放到普通的方法里。
编译器在一个类的实例字典中找不到这个属性时,会调用__getattr__方法。
访问属性时,每次都会访问__getattribute__
__getattr__:当访问某个类的实例变量,不存在时,会回调此函数
__getattribute__:访问某个类的实例变量时,每次都会回调
__setattr__:设置某个类的实例变量前会回调此函数
通过这些函数就可以按需进行动态地对实例属性进行修改了。
如果要在__getattribute__、__setattr__中访问实例属性,不能直接self访问,这样会不断循环。要使用super()
python把子类的整个class加载后,就会调用其元类的__new__方法,可以在这个__new__方法里添加子类的验证逻辑。
Python2:
class Meta(type):
def __new__(meta, name, bases, class_dict):
class MyClasspython2(object):
__meta__ = Meta
python3
class Meta(type):
def __new__(meta, name, bases, class_dict):
Return type.__new__(meta, name, bases, class_dict)
Class MyClass(object, metaClass=Meta):
stuff = 123
meta:元类
name:子类名
bases:父类元组
class_dict:class里面的一些东西
举了个序列化和反序列化的例子
在构建模块化python程序时,类的注册是一种很有用的模式。类的注册可以放在元类中。只要基类的元类里实现了注册,那么子类继承基类时就无需再注册了。
借用元类,我们可以在某个类完全定义好之前,率先修改类的属性。
Orm中定义数据库中某个表的类,里面的Field,实现属性值为Filed的名字。这个在类的父类中的元类中,获取到所有属性值,然后将Filed的值赋好。
由于GIL全局解释器锁存在,每个时刻其实只能一个线程执行。因此计算型任务不适合适用多线程,IO等待型任务适合多线程。
class Test():
def __init__(slef):
self.lock = Lock()
self.count = 0
def increment(self, offet):
with self.lock:
Self.count += offet
如同生成线一样,使用pipeline 的思想,利用生产者消费者模型,将任务分发、传递最终合并。
自己实现由几个问题:某个阶段持续等待;如何停止工作线程、如何防止内存膨胀
可以使用Queue
底层使用multiprocessing来进行多进程,每个进程都有独立的GIL。
pool = ProcessPoolExecutor(max_workers=2)
results = list(pool.map(function, numbers))
ProcessPoolExecutor类会利用multiprocessing模块提供的底层机制:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。