1:列表复制
# -*- coding=utf
list1=[1,2,3]
list2=[1,2,3,4]
a=list1[:]
b=list2
print(b)
print(a)
输出:[1, 2, 3, 4]
[1, 2, 3]
比较推荐的列表复制方法是list1[:]这种方法,b=list2方法很容易出现各种问题。
2:垃圾回收机制
java和C#都采用了垃圾手机机制,而不再是c和c++里那样用户自己管理维护内存,自己管理内存及其自由,可以任意申请内存,但是可能会发生内存泄漏。
python同java一样采用垃圾回收机制,不过不同的是:python采用的是引用计数 机制为主,标记-清除和分代收集两种机制为辅
3:python中self的含义
python的类中self代表类的实例,而非类本身。
class Test:
def pself(self):
print(self)
print(self.__class__)
t=Test()
t.pself()
输出:
<__main__.Test instance at 0x7fcdf5f6e7e8>
__main__.Test
由上面的例子中可以发现,self代表的是类的实例,而self.class则指向类。
self可以用this代替
class Test:
def pself(this):
print(this)
print(this.__class__)
t=Test()
t.pself()
同样输出:
<__main__.Test instance at 0x7fede2d407e8>
__main__.Test
但是self在定义时不可以省略。
self指的是描述类的实例
- self在定义时需要定义,但是在调用时会自动传入。
- self的名字并不是规定死的,但是最好还是按照约定是用self
- self总是指调用时的类的实例。
4:包装(wrapping)与代理(delegation)
wrapping的思想:
面向对象程序设计中有一个理念就是封装,而实际上面向对象也让程序员在使用一些类(自己定义或则别人定义)对象的时候非常方便。包装就是一个希望将某个对象(或类),进行重新打包,装换成另外一种更适合当前使用场合的对外接口。
class WrapMe(object):
def __init__(self, obj): #这个声明了构造函数,实际上就是模拟要包装对象的构建方法
self.__data = obj #__data就是这个被包装对象的核心,使用__data有一定的隐蔽性
def get(self): #放回封装中的数据,这个是添加的方法。
return self.__data
def __repr__(self): #特殊函数就是Python编译是如何输入这个对象
return 'self.__data'
def __str__(self): #特殊函数,其实就是转换那个__data中的同样的功能
return str(self.__data) #特殊函数__str__就是为内建函数准备的
def __getattr__(self, attr): #这个是关键,就是代理(delegation) 下面详细讲
return getattr(self.__data, attr)
5:python、cpyton、pypy和jython的介绍
Python是一门编程语言,任何一种编程语言都需要用另一种语言来实现它,比如C语言就是用机器语言来实现的。所以,Python根据实现方式不同分为了CPyhton、Pypy、Jython等。
cpython
CPython是用C语言实现Pyhon,是目前应用最广泛的解释器。Python最新的语言特性都是在这个上面先实现,Linux,OS X等自带的也是这个版本,包括Anaconda里面用的也是CPython。CPython是官方版本加上对于C/Python API的全面支持,基本包含了所有第三方库支持,例如Numpy,Scipy等。但是CPython有几个缺陷,一是全局锁使Python在多线程效能上表现不佳,二是CPython无法支持JIT(即时编译),导致其执行速度不及Java和Javascipt等语言。于是出现了Pypy。
---------------------
pypy
Pypy是用Python自身实现的解释器。针对CPython的缺点进行了各方面的改良,性能得到很大的提升。最重要的一点就是Pypy集成了JIT。但是,Pypy无法支持官方的C/Python API,导致无法使用例如Numpy,Scipy等重要的第三方库。这也是现在Pypy没有被广泛使用的原因吧。
---------------------
jython
Jython是将Python code在JVM上面跑和调用java code的解释器。
6:ord()函数和char()函数的用法
ord()函数用于获取字符的整数表示,而char()函数是把编码转换为对应的字符。
print(ord('a'))
# print(ord('李'))
print(chr(66))
输出:
97
B
7:不变的tuple
t=('a','b',['A','G'])
t[2][0]='X'
t[2][1]='Y'
print(t)
输出:('a', 'b', ['X', 'Y'])
ple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a'
,就不能改成指向'b'
,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的。
8:if x:的用法
x=0
# x=110
if x:
print('True')
只要x
是非零数值、非空字符串、非空list等,就判断为True
,否则为False
。
9:python内建函数
https://docs.python.org/2.7/library/functions.html
10:python默认参数必须指向不变对象
def add_end(l=[]):
l.append('END')
return l
print(add_end([1,2,3]))
print(add_end(['x','y','z']))
print(add_end())
print(add_end())
输出:
[1, 2, 3, 'END']
['x', 'y', 'z', 'END']
['END']
['END', 'END']
函数似乎每次都记住了上次添加了‘END’后的list
定义默认参数要牢记一点:默认参数必须指向不变对象
def add_end(l=None):
if l is None:
l=[]
l.append('END')
return l
为什么要设计str
、None
这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。
11:python中isinstance的用法
python中的isinstance函数是一个内建函数,用来判断一个对象是否是一个已知类型。
语法:isinstance(object,classinfo)
如果参数object是classinfo的实例,或者object是classinfo类的子类的一个实例返回True。否则返回False。
12:python中的enumerate函数
python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。
for i,value in enumerate(['A','B','C','D']):
print(i,value)
输出:
(0, 'A')
(1, 'B')
(2, 'C')
(3, 'D')
13:python中的杨辉三角、生成器
14:python中的迭代器(Iterable/Iterator/iter())
iterable对象
for循环的数据类型有以下几种:
一类是集合数据类型:如list、tuple、dict、set和str等。
另一类是generator,包括生成器和带yield的generator function
可以直接作用于for循环的对象我们统称为可迭代对象:Iterable。
可以通过isinstance()判断对象是否是Iterable对象。
iterator对象
可以使用isinstance()判断一个对象是否是iterator对象:
list、dict和str虽然是Iterable(可以直接用for来迭代,但是可以利用iter()转换后用next()方法),却不是Iterator对象(用next()来迭代)
将list、dict和str等Iterable变成Iterator可以使用iter()函数
python的Iterator对象表示是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据。可以把数据流看作一个有序序列,但不能提前知道序列的长度,只能不断的通过next()函数实现按需计算下一个数据;
总结:凡是可作用于for循环的对象都是Iterable类型
凡是可以作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合类型list、dict和str等是iterable,但不是iterator,不过可以通过iter()函数获得一个iterator对象。
for x in [1,2,3,4,5]:
pass
等价与
it=iter([1,2,3,4,5])
while True:
try:
x=next(it)
except StopIteration:
break
15:字符转数字(char2num)和字符串转整型(str2int)
#-*- coding=utf-8
from functools import reduce
def fn(x,y):
return x*10+y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
if __name__=='__main__':
print(reduce(fn,[1,3,4,5]))
print(reduce(fn,map(char2num(),'421')))
16:map和reduce的用法
map()函数接受两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
def f(x):
return x*x
r=map(f,[1,2,3,4,5])
print(list(r))
输出:[1, 4, 9, 16, 25]
def f(x):
return x*x
# r=map(f,[1,2,3,4,5])
# print(list(r))
l=[]
for n in [1,2,3,4,5]:
l.append(f(n))
print(l)
map函数直接利用一个for循环可以代替,但是为什么用map呢?map()
作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:
lsit(map(str,[1,2,3,4]))
输出:['1','2','3','4']
reduce的用法,reduce将一个函数作用在一个序列[x1,x2,x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累计计算:
reduce(f,[x1,x2,x3])=f(f(f(x1,x2),x3))
如下例子:
def add(x,y):
return x+y
print(reduce(add,[1,3,5]))
输出:9
会先算1+3=4,再算4+5=9
def fn(x,y):
return x*10+y
print(fn,[1,3,4,5])
输出1345:计算过程:1×10+3=13,再计算13×10+4=134,最后计算134×10+5=1345。
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return DIGITS[s]
reduce(fn, map(char2num, s))
此函数的作用是将字符串s转化为数字,通过map()实现,然后利用reduce将map得到的数字转化为满足fn的数。
通过lambda可以进一步简化:
lambda只是一个表达式,lambda函数体比def简单很多,将有限的逻辑封装到lambda中,起到函数速写的功能,允许代码内嵌一个函数的定义。
lambda可以传入一个或者多个参数:
p=lambda x,y :x+y
print (p(4,6))
p=lambda x :x*x
print (p (x))
p=lambda x,y,z :(x+8)*y-z
print(p(5,6,8))
17:python中首字母大写其它字母小写
# -*- coding=utf-8
def norm(name):
return name[0].upper()+name[1:].lower()
if __name__=='__main__':
print(norm('i love python'))
18:利用reduce求多个数的和
# -*- coding=utf-8
def norm(name):
return name[0].upper()+name[1:].lower()
def prod(l):
def multi(a,b):
return a*b
return reduce(multi,l)
if __name__=='__main__':
# print(norm('i love python'))
print(prod([1,2,3]))
19:pyton中的回数问题(filter方法)
回数指的是从左向右和从右向左读数一样,例如12321,909等都是回数。
# -*- coding: utf-8 -*-
def is_palindrome(n):
for i in range(int(n / 2)):
return str(n)[i] == str(n)[-i - 1]
# 测试:
output = filter(is_palindrome, range(1, 1000))
print(list(output))
filter()函数的作用是用于过滤序列,过滤掉符合条件的元素,返回由符合条件元素组成的新列表。
fliter函数接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断。
filter(function,iterable)
function为判断函数,iterable为可迭代对象
# !/usr/bin/python
# -*- coding: UTF-8 -*-
def is_odd(n):
return n % 2 == 1
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(newlist)
输出:[1,3,5,7,9]
20:python中sorted、列表、字典、排序和键值
sorted()是一个高阶函数,用sorted()排序的关键在于实现一个映射函数。
# -*- coding: utf-8 -*-
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
L2 = sorted(L, key=by_name)
print(L2)
输出:[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
上面是按照key进行排序
# -*- coding: utf-8 -*-
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_score(t):
return t[1]
L2 = sorted(L, key=by_score, reverse=True)
print(L2)
输出:[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
如上按照value进行排序。
21:返回函数与闭包
注意到返回的函数在其定义内部引用了局部变量args,所以当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以闭包用起来简单,实现起来不容易。
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
def count():
fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
f1, f2, f3 = count()
如上的例子中,每次循环都创建了一个新的函数,然后将新创建的3个函数都返回了,可以认为调用了f1(),f2(),f3()结果应该是返回1,4,9 ,但是实际上返回的结果是9,9,9。3个函数返回时,它们所引用的i已经变为了3,因此结果为9。
返回闭包时牢记:返回函数不要引用任何循环变量,或者后续会发生变化的量。
如果一定要引用循环变量的话,就是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该变量后如何改变,已经绑定到函数参数的值不变。
22:python中的装饰器
python中的装饰器很容易和设计模式里面的装饰器模式发生混淆,使用python的装饰器可以实现装饰器模式,但是绝对是很小的一部分。
在方法的开始或者结束前做一些事情,比如一些类似于权限检查、跟踪、资源枷锁等。
类式装饰器相比函数装饰器有更强大功能。
装饰器返回的对象是像函数一样能够被调用,因此装饰器需要实现__call__。装饰器完成什么工作?它能够完成任何事情,不过通常情况下,你可能会期望原有的被传递来的函数在某个地方能够被执行。
class myDecorator(object):
def __init__(self, f):
print "inside myDecorator.__init__()"
f() # Prove that function definition has completed
def __call__(self):
print "inside myDecorator.__call__()"
@myDecorator
def aFunction():
print "inside aFunction()"
print "Finished decorating aFunction()"
aFunction()
myDecorator的构造器实际上是在装饰函数时执行,可以在__init__()中调用函数f,能够看到,在装饰器被调用之前,函数调用f()就已经在itit中初始化完成,构造器能够接收被装饰的方法,一般来讲我们会捕捉到这个函数对象然后接下来在函数__call__()里面调用。
如上面代码中,aFunction被装饰完成后调用时,我们得到一个完全不同的行为,实际上执行的是myDecorator.__call__()的代码逻辑,装饰将原有的代码逻辑用新的返回的逻辑替换掉,myDecorator对象替换掉函数aFunction。
class entryExit(object):
def __init__(self, f):
self.f = f
def __call__(self):
print "Entering", self.f.__name__
self.f()
print "Exited", self.f.__name__
@entryExit
def func1():
print "inside func1()"
@entryExit
def func2():
print "inside func2()"
func1()
func2()
输出:
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2
现在我们能够看到,那些被装饰的方法有了“进入”和“离开”的跟踪信息。
构造器存储了通过参数传递进来的函数对象,在调用的方法里,我们用函数对象的__name__
属性来展示被调用函数的名称,然后调用被装饰的函数自己。
装饰器参数
前面介绍了不带参数的装饰器,被装饰的方法会传递给构造器,然后在被装饰的函数被调用的时候,装饰器的__call__()方法会执行。
如下是带参数的装饰器:
class decoratorWithArguments(object):
def __init__(self, arg1, arg2, arg3):
"""
If there are decorator arguments, the function
to be decorated is not passed to the constructor!
"""
print "Inside __init__()"
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def __call__(self, f):
"""
If there are decorator arguments, __call__() is only called
once, as part of the decoration process! You can only give
it a single argument, which is the function object.
"""
print "Inside __call__()"
def wrapped_f(*args):
print "Inside wrapped_f()"
print "Decorator arguments:", self.arg1, self.arg2, self.arg3
f(*args)
print "After f(*args)"
return wrapped_f
@decoratorWithArguments("hello", "world", 42)
def sayHello(a1, a2, a3, a4):
print 'sayHello arguments:', a1, a2, a3, a4
print "After decoration"
print "Preparing to call sayHello()"
sayHello("say", "hello", "argument", "list")
print "after first sayHello() call"
sayHello("a", "different", "set of", "arguments")
print "after second sayHello() call"
输出:
Inside __init__()
Inside __call__()
After decoration
Preparing to call sayHello()
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: say hello argument list
After f(*args)
after first sayHello() call
Inside wrapped_f()
Decorator arguments: hello world 42
sayHello arguments: a different set of arguments
After f(*args)
after second sayHello() call
现在,在“装饰”阶段,构造器和__call__()
都会被依次调用,__call__()
也只接受一个函数对象类型的参数,而且必须返回一个装饰方法去替换原有的方法,__call__()
只会在“装饰”阶段被调用一次,接着返回的装饰方法会被实际用在调用过程中。
尽管这个行为很合理,构造器现在被用来捕捉装饰器的参数,而且__call__()
不能再被当做装饰方法,相反要利用它来完成装饰的过程。尽管如此,第一次见到这种与不带参数的装饰器迥然不同的行为还是会让人大吃一惊,而且它们的编程范式也有很大的不同。
23:*args 和**kwargs
当函数的参数不确定时,可以使用*args 和**kwargs,*args 没有key值,**kwargs有key值。
24:python学习资源
https://blog.csdn.net/qq_33528613/article/details/73034003
25:getattr方法
class Student(object):
def __init__(self):
self.name='Liyang'
def __getattr__(self, item):
if item=='score':
return 99
26:多进程的python实现
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
输出结果:
Parent process 928.
Process will start.
Run child process test (929)...
Process end.
如果要启动大量的子进程,可以使用进程池实现批量创建子进程。
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
输出:
Parent process 669.
Waiting for all subprocesses done...
Run task 0 (671)...
Run task 1 (672)...
Run task 2 (673)...
Run task 3 (674)...
Task 2 runs 0.14 seconds.
Run task 4 (673)...
Task 1 runs 0.27 seconds.
Task 3 runs 0.86 seconds.
Task 0 runs 1.41 seconds.
Task 4 runs 1.91 seconds.
All subprocesses done.
进程间通信:
Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
依Queue为例,在父进程中创建两个子进程,一个往Queue里面写数据,一个从Queue里面读数据:
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
Process to write: 50563
Put A to queue...
Process to read: 50564
Get A from queue.
Put B to queue...
Get B from queue.
Put C to queue...
Get C from queue.
27:callable()函数
用于检查一个对象是否是可以调用,如果返回True,object仍然可能调用失败;但如果返回False,调用对象object绝对不会成功。
对于函数、方法、lambda 函式、 类以及实现了 __call__ 方法的类实例, 它都返回 True。
28:实例方法
在类中,如果不传递类的实例,调用这个方法时也不传递类的实例。如果传递了类的实例,则这种方法为类方法,也称为实例方法。
# -*- coding=utf-8
class Student(object):
def aMethod():
print('i am stu')
if __name__=='__main__':
Student.aMethod()
如下为实例方法:
# -*- coding=utf-8
class Student(object):
def aMethod(self):
print('i am stu')
if __name__=='__main__':
# Student.aMethod()
s=Student()
s.aMethod()
29:实例方法、类方法和静态方法
实例方法:在类中定义的方法,这个方法的第一个参数默认是实例对象,一般习惯使用self。
类方法:在类中定义的方法,这个方法的第一个参数默认是类对象,一般习惯使用cls,使用@classmethod装饰器装饰。
静态方法:在类中定义的方法,这个方法对参数没有要求。@staticmethod装饰器装饰。
实例方法只能被实例调用。
类方法和静态方法可以被类或者实例调用。
class Foo(object):
#实例方法,第一个参数必须是实例对象,一般习惯用self
def instance_method(self):
print("是类{}实例方法,只能被实例对象调用".format(Foo))
@classmethod
def class_method(cls):
print("是类方法")
#静态方法,参数没有要求,使用@staticmethod装饰。
@staticmethod
def static_method():
print("是静态方法")
foo=Foo()
#实例方法只能被实例调用
foo.instance_method()
#类方法可以使用类或者实例调用
Foo.class_method()
foo.class_method()
#静态方法可以被类或者实例调用
Foo.static_method()
foo.static_method()
30:python中__init__的用法
当一个类的实例被创建时,__init__方法会自动执行,在类实例创建完毕后执行,类似构造器,__init__并不创建实例,仅仅是创建实例后执行的第一个方法。通过创建自己的__init__方法,可以覆盖默认的__init__方法。
31:浅拷贝和深拷贝
只拷贝了对象的索引,而不是重新建立一个对象;
如果想完全的拷贝一个对象,需要用到深拷贝。
其中copy提供了浅拷贝和深拷贝的能力。