字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。
0 , [ ] , " , ( ) , { }
python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等.
python中不可变数据类型有以下三种:Number(数字)String(字符串)Tuple(元组)
可变类型:List(列表)Set(集合)Dictionary(字典)。
Python中的列表是由对其它对象的引用组成的连续数组。指向这个数组的指针及其长度被保存在一个列表头结构中。这意味着,每次添加或删除一个元素时,由引用组成的数组需要改变大小(重新分配)。幸运的是,Python在创建这些数组时采用了指数过分配,所以并不是每次操作都需要改变数组的大小。但是,也因为这个原因添加或取出元素的平摊复杂度较低。不幸的是,在普通链表上“代价很小”的其它一些操作在Python中计算复杂度相对过高。利用 list.insert方法在任意位置插入一个元素——复杂度O(N);利用 list.delete或del删除一个元素——复杂度O(N)。
参考网址
二者使用时相同,但返回类型不同,xreadlines返回的是一个生成器,readlines返回的是list。
g = lambda x ,y: x * y
g ( 2,3 )
https://www.cnblogs.com/JIM-FAN/p/13358488.html
在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对象中的某个变量,但是由于种种原因我们无法确定这个方法或变量是否存在,这是我们需要用一个特殊的方法或机制要访问和操作这个未知的方法或变量,这中机制就称之为反射。
接下记录下反射几个重要方法:getattr、hasattr、delattr和setattr较为全面的实现了基于字符串的反射机制。他们都是对内存内的模块进行操作,并不会对源文件进行修改。动态导入模块
https://www.cnblogs.com/kongk/p/8645202.html
程序调试;了解软件程序运行情况,是否正常;软件程序运行故障分析与问题定位;用户行为分析
https://blog.csdn.net/gaifuxi9518/article/details/81038818
函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储。
在函数的内部,通过global声明,使在函数内部中设置一个全局变量,这个全局变量可以在任意的函数中进行调用!
x = 0b1010 print(x) int(‘1010’,base=2) int(‘0b1010’,2) x = eval(‘0b1010’)
ret = bin(18) print(ret)
ret = oct(18) print(ret) ret = int(‘0o12’,16)
ret = hex(87) print(ret) ret = int(‘0x12’,16)
a. 整型 int、 长整型 long、浮点型 float、 复数 complex b. 字符串 str、 列表list、 元祖tuple c. 字典 dict 、 集合 set
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
with表达式其实是try-finally的简写形式。但是又不是全相同。
with 语句实质是上下文管理。
1、上下文管理协议。包含方法__enter__() 和 exit(),支持该协议对象要实现这两个方法。
2、上下文管理器,定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。
3、进入上下文的时候执行__enter__方法,如果设置as var语句,var变量接受__enter__()方法返回值。
4、如果运行时发生了异常,就退出上下文管理器。调用管理器__exit__方法。
链接:https://www.jianshu.com/p/5b01fb36fd4c
https://www.cnblogs.com/wcwnina/p/8644892.html
自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().
参考网址
python里也同java一样采用了垃圾收集机制,不过不一样的是:python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。python里每一个东西都是对象,它们的核心就是一个结构体:PyObject。PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。使用sys.getrefcount(a)
可以查看一个对象的引用计数。
c=[5,6]#假设此时c的引用为1
d=[7,8]#假设此时d的引用为1
c.append(d)#c的引用+1=2
d.append(c)#d的引用+1=2
假如现在需要同时删除c、d,应该如何回收呢?
python标记删除时通过两个容器来完成的:死亡容器、存活容器。
a=[1,2]#假设此时a的引用为1
b=[3,4]#假设此时b的引用为1
#循环引用
a.append(b)#b的引用+1=2
b.append(a)//a的引用+1=2
假如现在需要删除a,应该如何回收呢?(注意删除a可以使用del a,这样a这个引用就不存在了,但是它指向的对象,在标记删除后还存在,因为还被b使用者)
为了更合理的进行【标记-删除】,就需要对对象进行分代处理
迭代器是遵循迭代协议的对象。用户可以使用 iter() 以从任何序列得到迭代器(如 list, tuple, dictionary, set 等)。另一个方法则是创建一个另一种形式的迭代器 —— generator 。要获取下一个元素,则使用成员函数 next()(Python 2)或函数 next() function (Python 3) 。当没有元素时,则引发 StopIteration 此例外。若要实现自己的迭代器,则只要实现 next()(Python 2)或 next()( Python 3)
生成器(Generator),只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
区别: 生成器能做到迭代器能做的所有事,而且因为自动创建iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常。
把一个类作为一个迭代器使用需要在类中实现两个方法 、__iter__() 与 __next__() 。__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了\ __next__() 方法并通过 StopIteration 异常标识迭代的完成。__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def next(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
def timeit(func):
@wraps(func)
def wrapper(args, **kwargs):
start = time.time()
ret = func(args, **kwargs)
end = time.time()
print(‘used:’,end-start)
return ret
return wrapper
@timeit
def foo():
print(‘in foo()’)
## 执行foo(),输出结果
in foo()
used: 0.0
参考链接
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
参考链接
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class Foo(object):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
class Singleton(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__new__(cls,*args,**kwargs)
return cls._instance
class Foo(Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
或者
class Singleton(object): def __init__(self): pass
def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): # 反射 Singleton._instance = object.__new__(cls) return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)
class Singleton(type):
def __call__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__call__(*args,**kwargs)
return cls._instance
class Foo(object):
__metaclass__ = Singleton
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
单例模式应用的场景一般发现在以下条件下: 资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件,应用配置。 控制资源的情况下,方便资源之间的互相通信。如线程池等,1,网站的计数器 2,应用配置 3.多线程池 4数据库配置 数据库连接池 5.应用程序的日志应用
参考https://www.cnblogs.com/fengf233/p/11468541.html
每当一个线程a要访问共享数据时,必须先获得锁定;如果已经有别的线程b获得锁定了,那么就让线程a暂停,也就是同步阻塞;等到线程b访问完毕,释放锁以后,再让线程a继续
锁有两种状态:被锁(locked)和没有被锁(unlocked)。拥有acquire()和release()两种方法,并且遵循一下的规则:
条件同步机制是指:一个线程等待特定条件,而另一个线程发出特定条件满足的信号。
基于事件的同步是指:一个线程发送/传递事件,另外的线程等待事件的触发。与条件同步类似,只是少了我们自己添加锁的步骤。
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。 线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。 协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
异步的使用场景: 1、 不涉及共享资源,获对共享资源只读,即非互斥操作 2、 没有时序上的严格关系 3、 不需要原子操作,或可以通过其他方式控制原子性 4、 常用于IO操作等耗时操作,因为比较影响客户体验和使用性能 5、 不影响主线程逻辑
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全 那么怎么解决多线程竞争问题?—锁 锁的好处: 确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。 锁的坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了 锁的致命问题: 死锁
孤儿进程: 父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init 进程(进程号为1)所收养,并由init 进程对他们完成状态收集工作。 僵尸进程: 进程使用fork 创建子进程,如果子进程退出,而父进程并没有调用wait 获waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。 避免僵尸进程的方法: 1.fork 两次用孙子进程去完成子进程的任务 2.用wait()函数使父进程阻塞 3.使用信号量,在signal handler 中调用waitpid,这样父进程不用阻塞
同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。 异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调! 阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。 非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的。 同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
每个对象都对应于一个可称为’互斥锁‘的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。 同一进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一线程已经对其进行操作,导致最终结果出现错误,此时需要对被操作对象添加互斥锁,保证每个线程对该对象的操作都得到正确的结果。
怎么避免重读? 创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,在多线程访问数据的时候先查看数据是否在已访问的列表中,若已存在就直接跳过。
https://www.cnblogs.com/JimmyFanHome/p/9914562.html
若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
产生死锁的四个必要条件
1.互斥性:线程对资源的占有是排他性的,一个资源只能被一个线程占有,直到释放。
2.请求和保持条件:一个线程对请求被占有资源发生阻塞时,对已经获得的资源不释放。
3.不剥夺:一个线程在释放资源之前,其他的线程无法剥夺占用。
4.循环等待:发生死锁时,线程进入死循环,永久阻塞。
避免死锁的方法
1.破坏“请求和保持”条件
想办法,让进程不要那么贪心,自己已经有了资源就不要去竞争那些不可抢占的资源。比如,让进程在申请资源时,一次性申请所有需要用到的资源,不要一次一次来申请,当申请的资源有一些没空,那就让线程等待。不过这个方法比较浪费资源,进程可能经常处于饥饿状态。还有一种方法是,要求进程在申请资源前,要释放自己拥有的资源。
2.破坏“不可抢占”条件
允许进程进行抢占,方法一:如果去抢资源,被拒绝,就释放自己的资源。方法二:操作系统允许抢,只要你优先级大,可以抢到。
3.破坏“循环等待”条件
将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出
死锁的解除
1.抢占资源,从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态。
2.终止(或撤销)进程,终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态解脱出来.
死锁的检测
1.每个进程、每个资源制定唯一编号
2.设定一张资源分配表,记录各进程与占用资源之间的关系
3.设置一张进程等待表,记录各进程与要申请资源之间的关系
GIL锁 全局解释器锁(只在cython里才有) 作用: 限制多线程同时执行,保证同一时间只有一个线程执行,所以cython里的多线程其实是伪多线程! 所以python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程。 进程和线程的切换时由系统决定,而协程由我们程序员自己决定,而模块gevent下切换是遇到了耗时操作时才会切换 三者的关系:进程里有线程,线程里有协程。
python GIL锁 也称为:全局解释器所(global interpreter lock),当有多个线程同时执行时,每个线程在执行时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU,也就是说多线程并不是真正意义上的同时执行!
任何Python 线程threading 执行前,必须先获得GIL锁才能执行,当线程获取到GIL锁之后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。
在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获取资源
同进程的一样,semaphore管理一个内置的计数器,每当调用acquire()时内置函数-1,每当调用release()时内置函数+1。
计数器不能为0,当计数器为0时acquire()将阻塞线程,直到其他线程调用release()。
如果使用RLock代替Lock,则不会发生死锁,二者的区别是:递归锁可以连续acquire多次,而互斥锁只能acquire一次
sorted (key_value)
sorted(key_value.items(), key = lambda kv:(kv[1], kv[0]))
参考https://www.runoob.com/python3/python3-func-sorted.html
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
example_list = [5, 0, 6, 1, 2, 7, 3, 4]
result_list = sorted(example_list, key=lambda x: x*-1)
print(result_list)
[7, 6, 5, 4, 3, 2, 1, 0]
注意参数key,该参数传入一个lambda表达式,实现对可迭代对象中的每个元素的加工。其中x表示可迭代对象中的每个元素。
def get_lines():
with open('file.txt','rb') as f:
for i in f:
yield i
import random
alist = [1,2,3,4,5]
random.shuffle(alist)
print(alist)