python学习笔记

函数中的参数传递

1
2
3
4
5
6
7
b = 2
def func(b):
print "func_in",id(b)#func_in 39630240
b=1
print "func_in",id(b)#func_in 39630264
func(b)
print id(b),id(2)#39630240 39630240

对于这个函数的参数,虽然经过赋值,但是它本身并没有变化,可以看作是对变量的一个引用.在python中,类型属于对象,对象有两种,可变对象和不可变对象, strings, tuples, 和numbers是不可更改的对象,而 list, dict, set 等则是可以修改的对象 .

下面这个例子就是可变对象

1
2
3
4
5
6
7
8
9
10
a = []
def func(a):
print "func_in",id(a)#func_in 46177544
a.append(1)
print "func_in",id(a)#func_in 46177544

func(a)
print(a.__class__)#<type 'list'>
print id(a),a#46177544 [1]
print id(a[0]),id(1)#44742824 44742824

可以看到,a的类型是list,通过函数对参数进行赋值,变量a的值发生了改变,个人理解是因为,每个变量初始的时候,都会分配一个地址,每次函数调用变量的时候只是引用了变量,并没有实质的改变他的地址,之所以list这些类型会改变,是因为他将值存储到了a[0]中,而a属于一个list的地址,其实也并没有改变。

@classmethod && @staticmethod

在python中有3个方法,类方法,静态方法和实例方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A():
def foo(self,x):
print "executing foo(%s, %s)" % (self, x)
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s, %s)" % (cls, x)
@staticmethod
def static_foo(x):
print "executming static_foo(%s)" % x

a = A()
a.foo(1)#executing foo(<__main__.A instance at 0x0000000002C14DC8>, 1)
a.class_foo(1)#executing class_foo(__main__.A, 1)
a.static_foo(1)#executming static_foo(1)
print(a.static_foo)#<function static_foo at 0x0000000002C18EB8>

这里的self,cls是对实例和类的绑定,默认是这个,不能更改,而且这里的@classmethod,@staticmethoddecorators用于声明类中方法的类型,若是少了这个,那么python默认这个方法就是实例方法 1

https://stackoverflow.com/questions/136097/difference-between-staticmethod-and-classmethod

类变量、实例变量

在python类中同样存在两种变量类型,类变量是类中共有的变量,该类的所有实力都可以访问,实例变量是每个实例单独拥有的变量,不能被其他实例访问,个人理解相当于私有变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
class A(object):
num = 1
def foo(self,name):
self.name = name
A.num +=1

a1 = A()
a2 = A()
a1.foo('a1')
print "instance variable",a1.name#instance variable a1
print "class variable",a1.num#class variable 2
print "class variable",a2.num#class variable 2
print a2.name#AttributeError: 'A' object has no attribute 'name'

可以看到,num是类变量,所以每个实例都可以访问,但是name是实例变量,a1实例创建的变量,a2访问不到

单下划线和双下划线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> class A():
def __init__(self):
self._single = "variable1"
self.__double = "variable2"


>>> a = A()
>>> a._single
'variable1'
>>> a.__double

Traceback (most recent call last):
File "<pyshell#66>", line 1, in <module>
a.__double
AttributeError: A instance has no attribute '__double'
>>> print a.__dict__
{'_single': 'variable1', '_A__double': 'variable2'}

单下划线表明该变量或方法为私有,且 通过from xx import *不可被导入。

双下划线用来区别其他类相同的命名,它不能直接被访问,要通过_类名__xx来访问

__init__这种类型是python内部自定义的名字,用来区别用户定义的

Iterables、Generators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> myiterable=[x*x for x in range(3)]
>>> for i in myiterable:
print i
0
1
4
>>> for i in myiterable:
print i
0
1
4
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
print i
0
1
4
>>> for i in mygenerator:
print i
#null
>>> myiterable
[0, 1, 4]
>>> mygenerator
<generator object <genexpr> at 0x0000000002F60360>

当我们创建一个list时,他就是一个迭代器,我们可以用for.. in..来迭代,这里的myiterable就是可迭代的,他会将所有值存储在内存里面,可以多次迭代

generators也属于迭代的一种,但是它不会将值存储在内存中,只有当我们迭代的时候才会出现值,而且只能迭代一次

yield

yield是一个关键词,和return一样的用法,但是函数使用就会返回是generators

1
2
3
4
5
6
7
8
9
>>> def creategenerators():
mylist = range(3)
for i in mylist:
yield i*i


>>> fun = creategenerators()
>>> print(fun)
<generator object creategenerators at 0x0000000002F60318>

yield时,当我们去请求函数,他只会返回函数类型,内部代码并不会运行,当我们用for迭代时,才会运行代码

yield from

yield from 后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。

yield from 语法出现在python3.3之后

实现生成器嵌套

1、 调用方:调用委派生成器的客户端(调用方)代码
2、委托生成器:包含yield from表达式的生成器函数
3、子生成器:yield from后面加的生成器函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 子生成器
def average_gen():
total = 0
count = 0
average = 0
while True:
new_num = yield average
count += 1
total += new_num
average = total/count

# 委托生成器,帮我们处理异常
def proxy_gen():
while True:
yield from average_gen()

# 调用方
def main():
calc_average = proxy_gen()# <generator object proxy_gen at 0x0000026B89707E48>
next(calc_average) # 预激下生成器
print(calc_average.send(10)) # 打印:10.0
print(calc_average.send(20)) # 打印:15.0
print(calc_average.send(30)) # 打印:20.0

if __name__ == '__main__':
main()

*args && **kwargs

*args && **kwargs方便函数定义,不强制

*args:当不确定函数里面要传多少参数时,可以用这个,它可以允许传递任意数量参数

1
2
3
4
5
6
7
8
>>> def getthing(*args):
for count,thing in enumerate(args):
print '{0}.{1}'.format(count,thing)


>>> a = ['amdin','guest']
>>> getthing(a)
0.['amdin', 'guest']

**kwargs:允许我们传递多个参未定义的参数名

1
2
3
4
5
6
>>> def puthing(**kwargs):
for count,thing in kwargs.items():
print '{}={}'.format(count,thing)
>>> puthing(friut='apple',name='admin')
friut=apple
name=admin

当混合命名参数使用时,命名参数在最前面,参数值最先传递给命名参数,*args && **kwargs一起用时,args必须在前面。

Decorator

首先,在python中,函数可以当作一个变量赋值给另一个变量:

1
2
3
4
def func():
print "hello"
a = func
a()#hello

其次,我们还可以在函数中定义函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
def func(name="admin"):
def test():
return "now in test function"
def modify():
return "now in modify function"
if name=="admin":
print test()
else:
print modify()
func()# now in test function
modify()# NameError: name 'modify' is not defined
# 可以看到,在func()调用时,里面的test(),modify()都会被调用
# 并且外部不可访问func内部的函数

接着,python中还可以在函数中返回函数:

1
2
3
4
5
6
7
8
9
10
11
def func(name="admin"):
def test():
return "now in test function"
def modify():
return "now in modify function"
if name=="admin":
return test
else:
return modify
print func()#<function test at 0x0000000002AD8DD8>
# 我们还可以输入func()()打印now in test function

装饰器:方便函数与类的重用,避免重复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def decorate_name(func):
def decorated():
print "Before execute func()"
func()
print "After excute func()"
return decorated
def func():
print "func() is excuting"
#下面个两步骤是用@运行时如何使用的
func = decorate_name(func)
func()
#output:
# Before execute func()
# func() is excuting
# After excute func()

装饰器一般用@xxx来表示,上面代码描述了我们使用后@时,代码运行的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from functools import wraps
def decorate_name(func):
@wraps(func)
def decorated(*args,**kwargs):
if not case:
return "func not run"
else:
return func()
return decorated

@decorate_name
def func():
return "func is running"
case = False
print func()

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能

之前讲的是函数装饰器,初次之外还有一个类装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from functools import wraps
class Myclass(object):
def __init__(self,case):
self.case = case

def __call__(self,func):
@wraps(func)
def decorated(*args,**kwargs):
if not self.case:
return "func not run"
return func()
return decorated

@Myclass(False)
def func():
return "func is running"

print func()#func not run

类装饰器和函数装饰器有点不一样,它需要__call__去调用func,这个是类装饰器的必须条件,上面还展示了装饰器带参数的形式

__new__ 与 __init__

__new__是一个类方法用于返回创建的实例,__init__是一个实例方法,用于初始实例,并且在 __new__之后调用。__new__可以用在单例模式下。

单例模式

单例模式目的是给每个类只分配一个实例,避免实例过多造成的资源堵塞

1
2
3
4
5
6
7
8
9
10
11
12
13
#__new__
class Singleton(object):
instance = None
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super(Singleton,cls).__new__(cls,*args,**kwargs)
return cls.instance

a = Singleton()
b = Singleton()
print a,b
#<__main__.Singleton object at 0x0000000002AA9828>
#<__main__.Singleton object at 0x0000000002AA9828>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#装饰器
def singleton(cls):
instance = cls()
instance.__call__ = lambda : instance
return instance

@singleton
class func():
x = 100

a = func()
b = func()
print a,b
#<__main__.func instance at 0x00000000029C5348>
#<__main__.func instance at 0x00000000029C5348>
def singleton(cls):
instances = {}
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance

线程

1
2
3
4
5
6
7
8
9
import threading

def loop(x,y):
for i in range(x,y):
print "thread is >>>{}".format(i)

t = threading.Thread(target=loop,args=(1,10))
t.start()
t.join()