再看python3

1.raw_input() was renamed to input() python3后就已经将raw_input()与input合并了,统一为input
2.关于复杂的编码问题
2.1 原始的原始,ACSII码,用来记录英文与字符,因为语音开始就只会用到这些
2.2 由于中文需要有了GB2312,记录中文
2.3 由于各国有各国的编码,于是诞生了Unicode编码,一般 两个字节来表示一个字符 这样在表示英文的时候就会占用大量空间
2.4 由于Unicode占用空间,所以utf-8出现了,英文只占一个字节,中文是三个字节,这就是他们的相爱相杀

总结内存里面使用Unicode,存储 / 网络传输使用utf-8

3.tuple 只包含一个数据的时候,t = (1,),不要省略最后的','哦
>>> t = (1,)
>>>
>>> t
(1,)
>>> t = (1)
>>> t
1
4.dict 有一个很有意思的地方就是 dict有pop方法 d.pop(key) 对应的value也会删除
>>> d = {'a':1, 'b':2, 'c':'rookia'}
>>> d['a']
1
>>> d.pop('a')
1
>>> d
{'b': 2, 'c': 'rookia'}
5.set可以像数学一样求并集,交集
>>> s1 = set([1,2,3])
>>> s2 = set([2,3,4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
6.关于可变与不可变思考

关于不可变字符串对其改变 a.replace('a','A') 这里的改变会通过返回值来返回改变结果,但是不可变a本身是不变的
而数组就不一样a.sort()就会直接改变a

>>> a = ['a','3','b','5']
>>> s = "abc"
>>> a.sort()
#不难发现a已经直接改变了
>>> a
['3', '5', 'a', 'b']
>>> s.replace('a','A')
'Abc'
#虽然返回结果是'Abc',但是s的值还是'abc'
>>> s
'abc'
7.函数

函数名 其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”

8.可变参数

如果已经有一个list或者tuple,要调用一个可变参数怎么办?Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去。

>>> def calc(*nums):
...     for x in nums:
...             print (x)
...
>>> calc(1,2,3,5)
1
2
3
5
>>> a = [13,4,5,6,7]
#如果已经有一个list或者tuple,要调用一个可变参数怎么办?
#Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去。
>>> calc(a[1], a[2], a[3], a[4])
4
5
6
7
>>> calc(*a)
13
4
5
6
7
>>>
9.关于指定命名关键字参数

指定命名关键字参数与关键字参数区别,指定命名关键字是对关键字的一个限制,允许函数中只能出现指定好的关键字,其他的都为错误的。
思考1:指定命名关键字参数,是否是关键字参数?
回答:答案是肯定的。
所以另外一个问题就来了——> 在调用函数时需要时用 params_func('a','b',c = 'c',d='d')来调用,注意参数c与参数d

>>> def params_func(a, b, *, c, d):
...     print(a+b+c+d)
...
>>> params_func("a",'b',c='c',d='d')
abcd
#这就是不写key的结果
>>> params_func("a",'b','c','d')
Traceback (most recent call last):
  File "", line 1, in 
TypeError: params_func() takes 2 positional arguments but 4 were given

思考2:是否可以向关键字参数那样使用dict传值
回答: 答案是否定的

>>> dic = {'c':'10', 'd':'ddd'}
#事实证明我们无法使用dict来传值
>>> params_func('a','b', *dic)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: params_func() takes 2 positional arguments but 4 were given

思考3:使用指定命名关键字参数时,是否还能使用可变参数
回答:答案是否定的

>>> def params_func(a,b,*nums,*,c,d):
  File "", line 1
    def params_func(a,b,*nums,*,c,d):
                              ^
SyntaxError: invalid syntax

--- 分割线---

>>> def params_func(a,b,*,c,d,*nums):
  File "", line 1
    def params_func(a,b,*,c,d,*nums):
                              ^
SyntaxError: invalid syntax

思考4:指定命名关键字参数跟关键字参数是否能混用
答案:答案是肯定的

>>> def params_func(a,b,*,c,d,**nums):
...     print(a + b + c + d)
...     print(nums)
...
>>> params_func('a','b',c='c',d='d',e='e',f='f')
abcd
{'e': 'e', 'f': 'f'}
10.切片

通过切面复制数组

>>> a = [1,2,3,4,5,6]
>>> b = a[:]
>>> b
[1, 2, 3, 4, 5, 6]

通过切面实现数组倒叙

>>> a = [1,2,3,4,5,6]
>>> b = a[::-1]
>>> b
[6, 5, 4, 3, 2, 1]
11.遍历

思考1:遍历数组,同时获取到index ——> 使用enumerate()

In [2]: a = [1,2,3,4]

In [3]: for i, value in enumerate(a):
   ...:     print('{0}, {1}'.format(i,value))
   ...:
0, 1
1, 2
2, 3
3, 4

思考2:遍历字典,同时有key ,value ——> 使用items()

In [4]: d = {'a': 1, 'b':'bb'}

In [5]: for k,v in d.items():
   ...:     print('{0} , {1}'.format(k, v))
   ...:
a , 1
b , bb

多说一句 ,如果直接使用d ,获取到的就是keys,与d.keys()一样

12.列表生成器(for for if)

for for if——> 意思是生成器内部一般用for 复杂点就用for for 在复杂点就是 for for if
今天看到一个问题 说怎么把 ("a",2)("b",4) 变为 [{"a": 2} , {"b":4}]
发现可以用列表生成器来做,很是方便

In [6]: t1 = ('a','b','c')
In [7]: t2 = ('d','e','f')
In [17]: arr = [{x:y} for x , y in zip(t1, t2)]
In [20]: for x in arr:
    ...:     print(x)
    ...:
{'a': 'd'}
{'b': 'e'}
{'c': 'f'}
13.高阶函数
map

对于map等高阶函数的使用还是有些局限
如看到下面这个

list(map(str, [1,2,3,4,5]))

对于str的使用有些疑惑,但是仔细一想,str也是一个函数,也就合理了。
这样说来,只需要谨记两个参数类型即可,第一个为函数,第二个为Iterable。
其实还是对函数作为参数有些不适应,感觉这是一道坎。

reduce

对于reduce参数,跟map很相似,一个函数一个Iterable,但是不同的是,reduce的函数必须是 两个参数。 其原因就是,他会将Iterable内的数据两个两个的进行操作,然后并将上一次的操作结果作为下一次的第一个数据。

filter

跟map/reduce很相似,都是一个函数一个Iterable,不同的是函数的返回值需要一个Bool类型,来进行筛选那些值需要留下,那些值不需要留下

>>> def fn(nums):
...     return filter(lambda x:x > 0, map(lambda x:x - 10 * 3, nums))
...
>>> list(fn([2,3,5,66,55,44,29]))
[36, 25, 14]
14.匿名函数

匿名函数的限制,只能有一个表达是,不用写return。
匿名函数也是一个函数对象,可以把匿名函数复制给一个变量
思考1 匿名函数作为返回值

In [12]: def haha(x ,y):
    ...:     return lambda: x * x + y * y
    ...:
In [14]: f = haha(10 , 20)
In [15]: f()
Out[15]: 500

思考2 匿名函数作为返回值,同时需要输入参数

In [16]: def haha():
    ...:     return lambda x, y:x * x + y *y
    ...:
In [17]: f = haha()
In [18]: f(10,20)
Out[18]: 500
15.类
15.1 多态

这里只能说是关于多态的一些思考。
何为多态,我的理解是同一行为的不同表现。同一行为也就是某种动作,而在类中,动作就意味着是方法。同一行为说明,大家都有这种行为,而不同表现,则是对这种行为的不同表现。

15.2 关于方法的动态绑定

对于这种方法已经了解,但是对于这种方法的使用场景并没有想到,并不知道怎么使用。
思考1 如果在绑定函数前先创建一个对象,再绑定函数再创建一个对象,是否前一个对象会是绑定前的状态呢。

In [57]: def dynamic_func(self, name):
    ...:     print('just print some {0}'.format(name))
    ...:
#绑定前创建对象
In [58]: b = Car()
In [59]: Car.dynamic_func = dynamic_func
#绑定后创建对象
In [60]: c = Car()
#调用b对象的动态方法
In [63]: b.dynamic_func('haha')
just print some haha
#调用c对象的动态方法
In [64]: c.dynamic_func('haha')
just print some haha

再看一个

In [65]: b = Bike()
In [66]: b.dynamic_func('haha')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 b.dynamic_func('haha')

AttributeError: 'Bike' object has no attribute 'dynamic_func'
In [67]: Bike.dynamic_func = dynamic_func
In [68]: b.dynamic_func('haha')
just print some haha

这果然很动态.

16.关于进程与多线程

进程与多线程一直都是python的一个痛点,现在的我还感受不到痛点,因为技术不够。

16.1关于进程

multiprocessing 下的 Process 使用也很简单
只需要给Process指定一个target方法, 在Process在启动时会去执行指定的那个target方法,同时也会开启新的进程,所以python的进程就这么简单。实现大概是这样。

#这就是那个target方法
In [36]: def process_def(name):
    ...:     print('do some thing with process name:{0}'.format(name))
    ...:     print('current process {0}'.format(os.getpid()))
    ...:     print('sleep 3 second')
    ...:     time.sleep(3)
    ...:
#执行进程的方法
In [38]: def do_process():
             #创建进程
    ...:     p = Process(target=process_def, args=('new_process',))
             #打印当前进程,以做比较
    ...:     print('current process {0}'.format(os.getpid()))
             #开始进程前
    ...:     print('process before start')
             #开启进程
    ...:     p.start()
    ...:     p.join()   #表示*调用join方法的那个进程*执行完成后,才会在继续执行当前线程   **内的内容很关键
             #线程结束
    ...:     print('process end')
    ...:
 
#执行方法
In [39]: dp_process()
#不难发现执行前的线程id是2511
current process 2511
process before start
do some thing with process name:new_process
#启动的进程id是3426
current process 3426
sleep 3 second
process end
16.2关于多个进程操作

多个进程就是用Pool来操作就可以了 也是在multiprocessing中包含的。

In [53]: from multiprocessing import Pool
In [54]: import time, os, random
#按照规定一样有一个target process def
In [55]: def test_task(name):
    ...:     print('Run task {0} ({1})'.format(name, os.getpid()))
    ...:     start = time.time()
    ...:     time.sleep(random.random() * 3)
    ...:     end = time.time()
    ...:     print('Task {0} runs {1} seconds'.format(name, end-start))
    ...:
In [56]: def do_task():
    ...:     print('current process {0}'.format(os.getpid()))
             #这里创建一个Pool
    ...:     p = Pool(4)
    ...:     for i in range(5):
                 #只需要调用apply_async来启动异步进程即可
    ...:         p.apply_async(test_task, args=(i,))
    ...:     print('before start')
    ...:     p.close()
    ...:     p.join()
    ...:     print('end')
    ...:
In [57]: do_task()
current process 2511
before start
Run task 0 (3484)
Run task 1 (3485)
Run task 2 (3486)
Run task 3 (3487)
Task 0 runs 0.260403871536 seconds
Run task 4 (3484)
Task 1 runs 1.60321497917 seconds
Task 4 runs 1.82880997658 seconds
Task 2 runs 2.11483192444 seconds
Task 3 runs 2.80249190331 seconds
end
16.3关于多线程,其实与多进程很像,都需要一个指定的def
#需要制定的thread def
In [10]: def test_thread():
    ...:     print('thread {0} is running...'.format(threading.current_thread().
    ...: name))
    ...:     time.sleep(2)
    ...:     print('end {0}'.format(threading.current_thread().name))
    ...:

In [11]: def do_thread():
    ...:     print('before start {0}'.format(threading.current_thread().name))
             #核心在这里 threading.Thread(target, 这需要制定一个name)  target还是指向到了test_thread
    ...:     t = threading.Thread(target=test_thread, name='LoopThread')
    ...:     t.start()
    ...:     t.join()
    ...:     print('end{0}'.format(threading.current_thread().name))
    ...:

In [12]: do_thread()
before start MainThread
thread LoopThread is running...
end LoopThread
endMainThread
16.4 Pool.close

昨天看文章时,看到有一个close,但是没有看清楚这个close是谁调用的,还以为所有的Process 与 Thread都可以调用,于是今天早上调用了半天的close才发现Process 与 Thread 都没有close,如下:

#Thread中 使用dir查看属性 并没有发现close
>>> import threading
>>> t = threading.Thread()
>>> t.close()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'Thread' object has no attribute 'close'
>>> dir(t)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_args', '_bootstrap', '_bootstrap_inner', '_daemonic', '_delete', '_exc_info', '_ident', '_initialized', '_is_stopped', '_kwargs', '_name', '_reset_internal_locks', '_set_ident', '_set_tstate_lock', '_started', '_stderr', '_stop', '_target', '_tstate_lock', '_wait_for_tstate_lock', 'daemon', 'getName', 'ident', 'isAlive', 'isDaemon', 'is_alive', 'join', 'name', 'run', 'setDaemon', 'setName', 'start']

#Process中 使用dir查看同样没有close
>>> from multiprocessing import Process
>>> def test_close():
...     pass
...
>>> p = Process(target=test_close)
>>> p.close()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'Process' object has no attribute 'close'
>>> dir(p)
['_Popen', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_args', '_bootstrap', '_config', '_identity', '_kwargs', '_name', '_parent_pid', '_popen', '_start_method', '_target', 'authkey', 'daemon', 'exitcode', 'ident', 'is_alive', 'join', 'name', 'pid', 'run', 'sentinel', 'start', 'terminate']

问题来了,这个close是哪里的呢,找了半天才发现,这个close是Pool的,哎,真的是自己不仔细,不过也好,印象深刻了。关于close的使用。
close的作用:使用p.close后,标记着Pool关闭,其他的进程就不会再进入。

16.5 看分布式进程——队列新悟

之前看到队列一次很是抵触,因为大学期间数据结构刚及格,对结构类型都很抵触,不过今天看到分布式进程这里,发现队列的使用其实就是符合队列自身的特性的——先进先出。
这里使用QueueManger来进行管理。

因为是分布式, 要在多台机子上共享,于是有一台机子应该是做任务发布,其他机子都是任务执行者,将执行结果返回给任务发布这台机子。

发布机子的代码:

1.注册方法

QueueManager.register('get_task_queue', callable=lambda: task_queue)
QueueManager.register('get_result_queue', callable=lambda: result_queue)

2.创建 / 启动manager

#这里需要说明一下:因为要共享,于是这里就需要指定一个端口。
manager = QueueManager(address=('', 5000), authkey=b'abc')
manager.start()

3.获取task队列 获取result队列

task = manager.get_task_queue()
result = manager.get_result_queue()

4.模拟任务发布

for i in range(10):
     n = random.randint(0,1000)
     print('put task {0}'.format(n))
     #核心在这 ,将n put到task队列中
     task.put(n)

5.模拟结果获取

for i in range(10):
     #核心在这,通过get在result队列中取出数据
     r = result.get(timeout= 10)
     print('Result: %s' % r)
任务执行

1.一样注册方法

#我们不需要填写回调值,因为我们会直接使用QueueManager中的值
QueueManger.register('get_task_queue')
QueueManger.register('get_result_queue')

2.创建 / 链接manager 创建并链接

m = QueueManger(address=(server_addr, 5000), authkey=b'abc')
m.connect()

3.获取task / result队列

task = m.get_task_queue()
result = m.get_result_queue()
  1. 获取任务值,同时执行任务,同时返回到结果队列中
for i in range(10):
     try:
         #核心, 获取到任务值
         n = task.get(timeout=1)
         print('run task %d * %d...' % (n, n))
         #模拟执行任务
         r = '%d * %d = %d' % (n,n, n *n)
         time.sleep(1)
         #放入队列中,这里放入后,发布任务机子就会获取到任务
         result.put(r)
     except Queue.Empty:
         print('task queue is empty.')
分布式参考文章
17 三目运算符

其他语言的三目运算符一般是

a = 50 > 100 ? 'right' : 'left'

但是看完python的后我惊呆了

a = 'right' if 50 > 100 else 'left'

这种还算好理解,如果为真就是'right',如果为假就为'left'
但是有一个很恐怖写法的就是

a = ('left' ,'right')[50 > 100]

这是啥?谁能给我解释解释,翻译一下是,如果[]内为真就返回'right',否则就返回'left'。
尤其需要注意的是Tuple内,tuple[0]一个代表False要返回的值,tuple[1]代表True返回的值
伪代码就是这样的(if_false_return , if_true_return)[condition_false_or_true]

三目参考文章
18.修饰器

修饰器这个词,很早就已经知道了,一直都不是很理解,到现在也只能说说自己的一点理解,无法说的明白。

18.1 理解与使用

修饰器的核心可以理解为fn = decorator(fn),也就是decorator函数,参数为一个函数,返回值还是一个函数,而且传入的函数接收返回的函数,看个例子。

#创建我们的decorator
In [72]: def my_decorator(fn):
    ...:     def wrapper():
    ...:         print('this is in wrapper')
                 #在这里调用fn,听说这样可以给fn添加功能,同时不会破坏fn自身代码的完整性
    ...:         fn()
    ...:         print('this will leave wrapper')
    ...:     return wrapper
    ...:
#创建我们的function
In [73]: def my_fn():
    ...:     print('this is print in my_fn')
    ...:

这两个创建完成,剩下的就是使用了。不适用decorator的情况下

#my_decorator接受传入的函数my_fn,my_fn同时接受返回的函数
In [74]: my_fn = my_decorator(my_fn)
#使用一下,新返回的my_fn函数
In [75]: my_fn()
this is in wrapper
this is print in my_fn
this will leave wrapper

我们可以看到my_fn已经被扩充了。
修饰器是什么呢,修饰器就是我们来省略 fn = decorator(fn)这句话的一个方式。
使用decorator后(请看清这里代码与上面代码的不同)

#对于decorator,不需要有任何的改变
In [72]: def my_decorator(fn):
    ...:     def wrapper():
    ...:         print('this is in wrapper')
                 #在这里调用fn,听说这样可以给fn添加功能,同时不会破坏fn自身代码的完整性
    ...:         fn()
    ...:         print('this will leave wrapper')
    ...:     return wrapper
    ...:

#而在编写my_decorator的时候,我们需要添加@my_decorator来标记
In [76]: @my_decorator
    ...: def my_fn():
    ...:     print('this is my_fn')
    ...:

#不难发现, 我们不使用 fn= decorator(fn) 也能直接使用my_fn了
In [77]: my_fn()
this is in wrapper
this is my_fn
this will leave wrapper

而这就是修饰器的核心。

18.2 修饰器进化,带参数修饰器

带参数修饰器本质跟修饰器一样,不同的是带参数,这句话好像没说 0-0,直接来看一下吧。
一般修饰器 fn = decorator(fn)
带参修饰器 fn = decorator(*args, **kwds)(fn)
而这里的核心就是,为了确保满足fn = decorator(fn)这一条件,decorator(*args, **kwds)应该返回的是一个decorator。于是有了下面这段代码

"""
首先要知道的是 makeHtmlTag最终返回的是real_decorator 这意味着返回的是一个修饰器
其次这里我们要注意makeHtmlTag的可变参数时args kwds,而里面的wrapper的可变参数时
"""
In [78]: def makeHtmlTag(tag, *args, **kwds):
    ...:     def real_decorator(fn):
    ...:         css_class= "class='{0}'".format(kwds["css_class"]) if "css_clas
    ...: s" in kwds else ""
                 #看这里,参数是 arg 与 kwd
    ...:         def wrapper(*arg, **kwd):
    ...:             return "<"+tag+css_class+">" + fn(*arg, **kwd)+"<"+tag+">"
    ...:         return wrapper
    ...:     return real_decorator
    ...:

这里你可能会有疑问,为什么wrapper与makeHtmlTag的参数会不一样,很简单,因为wrapper是作为fn的返回值,makeHtmlTag的参数则是为real_decorator服务的。
于是我们可以这样用。

#定义hello函数
In [82]: @makeHtmlTag(tag='b', css_class='bold_css')
    ...: def hello(*arg, **kwd):
    ...:     return 'hello world '+kwd['name']
    ...:
#使用hello函数,我们要明确这里的hello函数不再是之前的hello函数了,而是返回来的wrapper了
In [83]: print(hello(name='whale'))
hello world whale

为了证明第二行注释的结论我们来做两个实验。

实验1

我们来修改一下修饰器

In [84]: def makeHtmlTag(tag, *args, **kwds):
    ...:     def real_decorator(fn):
    ...:         css_class= "class='{0}'".format(kwds["css_class"]) if "css_clas
    ...: s" in kwds else ""
                 #注意加注释的这里,这里没有个wrapper
    ...:         def wrapper():
    ...:             return "<"+tag+css_class+">" + fn()+"<"+tag+">"
    ...:         return wrapper
    ...:     return real_decorator
    ...:

再用之前的写法看看是否可以调用的通

In [85]: @makeHtmlTag(tag='b', css_class='bold_css')
    ...: def hello(*arg, **kwd):
    ...:     return 'hello world '+kwd['name']
    ...:

In [86]: print(hello(name='whale'))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in ()
----> 1 print(hello(name='whale'))

TypeError: wrapper() takes no arguments (1 given)

我们来看一下报错TypeError: wrapper() takes no arguments (1 given) wrapper()没有参数但是我们给了一个,我们明明给hello赋值,为什么说wrapper没有参数呢,因为在修饰器里面返回的就是wrapper。

实验2

恢复正常,我们在来看一下hello的__name__

In [97]: @makeHtmlTag(tag='b', css_class='bold_css')
    ...: def hello(*arg, **kwd):
    ...:     return 'hello world '+kwd['name']
    ...:
In [99]: hello.__name__
Out[99]: 'wrapper'

我们不难看出。虽然我们调用的hello但是其实已经变成了wrapper。

18.3 关于wraps

wraps是用来避免返回函数不同而引发的问题,虽然这也不能完全解决所有问题,但是大多数情况下还是够用的。
引入wraps

In [101]: from functools import wraps

使用wraps

In [102]: def makeHtmlTag(tag, *args, **kwds):
     ...:     def real_decorator(fn):
     ...:         css_class= "class='{0}'".format(kwds["css_class"]) if "css_cla
     ...: ss" in kwds else ""
     ...:         @wraps(fn)
     ...:         def wrapper(*arg, **kwd):
     ...:             return "<"+tag+css_class+">" + fn(*arg, **kwd)+"<"+tag+">"
     ...:
     ...:         return wrapper
     ...:     return real_decorator
     ...:

查看结果

In [103]: @makeHtmlTag(tag='b', css_class='bold_css')
     ...: def hello(*arg, **kwd):
     ...:     return 'hello world '+kwd['name']
     ...:

In [104]: hello.__name__
Out[104]: 'hello'
修饰器参考文章

你可能感兴趣的:(再看python3)