改善python程序的建议-code[转]

《编写高质量代码 改善Python程序的91个建议》

《编写高质量代码 改善Python程序的91个建议》读后程序学习小结 - BigDeng_2014的专栏 - CSDN博客

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
# coding=utf-8
# Language Reference
'''
参考书:《编写高质量代码 改善Python程序的91个建议》张颖,赖勇浩 著 2014.6
'''
 
from __future__ import with_statement
 
# assert
x, y = 1, 1
assert x == y, "not equals"
 
# time计时的两种方式
import timeit
t = timeit.Timer('x,y=y,x','x=1;y=2')
print(t.timeit()) # 0.110494892863
import time
t = time.time()
sum = 0
while True:
    sum += 1
    if sum > 100000:
        break
time.sleep(1)
print(time.time()-t) # 1.02999997139
 
# itertools 结合 yield
from itertools import islice
def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b
print(list(islice(fib(),10))) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
 
# class 定义变量 和 nametuple 定义变量
class Seasons:
    Sprint, Summer, Autumn, Winter = range(4)
print(Seasons.Winter) # 3
from collections import namedtuple
Seasons0 = namedtuple('Seasons0','Spring Summer Autumn Winter')._make(range(4))
print(Seasons0.Winter) # 3
 
# isintance 可以设置多种类型的判断
print(isinstance((2,3),(str, list, tuple))) # True
 
# eval的漏洞,能够处理的范围太大,导致系统文件被读取,谨慎使用
str0 = '__import__("os").system("dir")'
eval(str0) # 2017/09/28  09:31    <DIR> 。。。
 
# 生成器 yield 与 迭代器 iteritems
def myenumerate(seq):
    n = -1
    for elem in reversed(seq):
        yield len(seq) + n, elem
        n = n -1
e = myenumerate([1,2,3,4,5])
print(e.next()) # (4, 5)
dict0 = {'1':1, '2':2}
d = dict0.iteritems()
print(d.next()) # ('1', 1)
 
# 字符串驻留机制:对于较小的字符串,为了提高系统性能保留其值的一个副本,当创建新的字符串时直接指向该副本。
a = 'hello'
b = 'hello' # b 是 a 的引用
print(id(a), id(b), a is b, a == b) # (53383488, 53383488, True, True)
 
# 可变对象list 与 不可变对象str
list1 = [1,2,3]
list2 = list1
list3 = list1[:] # 浅拷贝
list1.append(4)
print(list1, list2, list3) # ([1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3]) - list2可变
str1 = '123'
str2 = str1
str3 = str1[:]
str1 += '4'
print(str1, str2, str3) # ('1234', '123', '123') - str2不可变
 
# 浅拷贝, 深拷贝
# 浅拷贝和深拷贝的不同仅仅是对组合对象来说,
# 所谓的组合对象就是包含了其它对象的对象,如列表,类实例。
# 而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
# 浅拷贝: 创建一个新的对象,其内容是原对象中元素的引用。(拷贝组合对象,不拷贝子对象)
# 浅拷贝有:切片操作、工厂函数、对象的copy()方法、copy模块中的copy函数。
# 深拷贝: 创建一个新的对象,然后递归的拷贝原对象所包含的子对象。深拷贝出来的对象与原对象没有任何关联。
# 深拷贝: 虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。
# 深拷贝只有一种方式:copy模块中的deepcopy函数。
a = [[1,2]] # 组合对象
import copy
b = copy.copy(a)
print(id(a), id(b), a is b, a == b) # (58740048, 59050864, False, True)
for i, j in zip(a, b):
    print(id(i), id(j)) # (61090752, 61090752)子对象相同
b = copy.deepcopy(a)
print(id(a), id(b), a is b, a == b) # (58740048, 58737848, False, True)
for i, j in zip(a, b):
    print(id(i), id(j)) # (61090752, 61071568)子对象不同
 
# 再举一例
class TestCopy():
    def get_list(self, list0):
        self.list0 = list0
    def change_list(self, str):
        self.list0 += str
    def print_list(self):
        print(self.list0)
list0 = [1, 2, 3]
a = TestCopy()
a.get_list(list0)
a.print_list()  # [1, 2, 3]
b = copy.copy(a) # 浅拷贝,子对象共享
b.change_list('4')
b.print_list()  # [1, 2, 3, '4']
a.print_list()  # [1, 2, 3, '4']
c = copy.deepcopy(a) # 深拷贝,子对象独立
c.change_list('5')
c.print_list()  # [1, 2, 3, '4', '5']
b.print_list()  # [1, 2, 3, '4']
a.print_list()  # [1, 2, 3, '4']
# 赋值操作
a = [1, 2, 3]
b = copy.copy(a) # 其实是赋值操作,不属于浅拷贝,赋值对象相互独立
b.append(4)
print(a, b)  # ([1, 2, 3], [1, 2, 3, 4])
 
# encode, decode, gbk, utf-8
with open("test.txt", 'w') as f:
    f.write('python' + '中文测试')
with open("test.txt", 'r') as f:
        # print(f.read()) # python中文测试
        print((f.read().decode('utf-8')).encode('gbk')) # python���IJ���
 
# --1 = 1 = ++1 = (1)
print(+++1, ---1) # (1, -1)
print (1), (1,) # 1 (1,)
print(''.split(), ''.split(' ')) # ([], [''])
 
# with 调用 class, 初始化调用__enter__,退出调用__exit__
class MyContextManager():
    def __enter__(self):
        print('entering...')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('leaving...')
        if exc_type is None:
            print('no exceptions')
            return False
        elif exc_type is ValueError:
            print('value error')
            return True
        else:
            print('other error')
            return True
with MyContextManager():
    print('Testing...')
    raise(ValueError)  # entering... Testing... leaving... value error
 
# else 结合 for 和 try
for i in range(5):
    print(i),
else:
    print('for_else') # 0 1 2 3 4 for_else
try:
    print('try'),
except:
    pass
else:
    print('try_else') # try try_else
 
# None
a = None
b = None
print(id(a), id(b), a is b, a==b) # (505354444, 505354444, True, True)
a = 'a'
b = u'b'
print(isinstance(a,str), isinstance(b,unicode), isinstance(a, basestring), isinstance(b, basestring))
# (True, True, True, True)
 
# 对 class 操作,先调用 __init__()
class A:
    def __nonzero__(self):
        print('A.__nonzero__()')
        return True
    def __len__(self):
        print('A.__len__()')
        return  False
    def __init__(self):
        print('A.__init__()')
        self.name = 'I am A'
    def __str__(self):
        print('A.__str__()')
        return 'A.__str__{self.name}'.format(self=self)
if A():
    print('not empty') # A.__init__() A.__nonzero__() not empty
else:
    print('empty')
print(str(A())) # A.__init__() A.__str__() A.__str__I am A
 
# 尽量采用''.join()(效率更高),而不是 str + str
s1, s2 ,s3 = 'a', 'b', 'c'
print(s1+s2+s3, ''.join([s1, s2, s3])) # ('abc', 'abc')
 
# map 与 list 结合
list0 = [('a','b'), ('c','d')]
formatter = "choose {0[0]} and {0[1]}".format
for item in map(formatter, list0):
    print(item)  # choose a and b  choose c and d
# map 结合 type
product_info = '1-2-3'
a, b, c = map(int, product_info.split('-'))
print(a, b, c)  # (1, 2, 3)
 
# 格式化输出,尽量采用 format,采用 %s 输出元组时需要加逗号
itemname = list0[0] + list0[1]
print(itemname) # ('a', 'b', 'c', 'd')
print('itemname is %s' % (itemname,))   # 必须有个逗号 itemname is ('a', 'b', 'c', 'd')
print('itemname is {}'.format(itemname)) # itemname is ('a', 'b', 'c', 'd')
# 格式化输出 %2.5f,小数点后5位优先级高
print('data: %6.3f' % 123.456789123# data: 123.457
print('data: %2.5f' % 123.456789123# data: 123.45679
 
# class传参:__init__ 中传入可变对象 - 会在子类中继承该可变对象的值
class ChangeA():
    def __init__(self, list0 = []): # mutable 可变
        self.list0 = list0
    def addChange(self, content):
        self.list0.append(content)
a = ChangeA()
a.addChange('add change')
b = ChangeA()
print(a.list0, b.list0) # (['add change'], ['add change'])
# 函数传参:传对象或对象的引用。若可变对象 - 共享, 若不可变对象 - 生成新对象后赋值
def inc(n, list0):
    n = n + 1
    list0.append('a')
n = 3
list0 = [1]
inc(n, list0)
print(n, list0) # (3, [1, 'a'])
# 子类继承父类,传参举例
class Father():
    def print_fa(self):
        print(self.total)
    def set(self, total):
        self.total = total
class SonA(Father):
    pass
class SonB(Father):
    pass
a = SonA()
a.set([1])
a.print_fa() # [1]
b = SonB()
b.set([2])
b.print_fa() # [2]
 
# 在需要生成列表的时候使用列表解析
# 对于大数据处理不建议用列表解析,过多的内存消耗会导致MemoryError
print([(a,b) for a in [1,2,3] for b in [2,3,4] if a != b])
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 2), (3, 4)]
 
# class 中的 装饰符 :类方法,静态方法,实例方法
class CS():
    def instance_method(self,x):
        print(x)
    @classmethod
    def class_method(cls,x):
        print('class',x)
    @staticmethod
    def static_method(x):
        print('static',x)
CS().instance_method(1) # 1
CS().class_method(2) # ('class', 2)
CS().static_method(3) # ('static', 3)
 
# itemgetter 字典排序,输出为元组
dict0 = {'a':1, 'c':3, 'b':2}
from operator import itemgetter
print(sorted(dict0.viewitems(), key = itemgetter(1))) # [('a', 1), ('b', 2), ('c', 3)]
 
# Counter 计数
from collections import Counter
print(Counter('success')) # Counter({'s': 3, 'c': 2, 'e': 1, 'u': 1})
 
# 配置文件:优点:不需修改代码,改变程序行为,继承[DEFAULT]属性
with open('format.conf', 'w') as f:
    f.write('[DEFAULT]' + '\n')
    f.write('conn_str = %(dbn)s://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' + '\n')
    f.write('dbn = mysql' + '\n')
    f.write('user = root' + '\n')
    f.write('host = localhost' + '\n')
    f.write('port = 3306' + '\n')
    f.write('[db1]' + '\n')
    f.write('user = aaa' + '\n')
    f.write('pw = ppp' + '\n')
    f.write('db = example1' + '\n')
    f.write('[db2]' + '\n')
    f.write('host = 192.168.0.110' + '\n')
    f.write('pw = www' + '\n')
    f.write('db = example2' + '\n')
from ConfigParser import  ConfigParser
conf = ConfigParser()
conf.read('format.conf')
print(conf.get('db1', 'conn_str')) # mysql://aaa:ppp@localhost:3306/example1
print(conf.get('db2', 'conn_str')) # mysql://root:www@192.168.0.110:3306/example2
 
# pandas - 大文件(1G)读取操作 - 需要安装 pandas
f = open('large.csv', 'wb')
f.seek(1073741824 - 1)
f.write('\0')
f.close()
import os
print(os.stat('large.csv').st_size) # 1073741824
import csv
with open('large.csv', 'rb') as csvfile:
    mycsv = csv.reader(csvfile, delimiter = ';')
    # for row in mycsv: # MemoryError
        # print(row)
# import pandas as pd
# reader = pd.read_table('large.csv', chunksize = 10, iterator = True)
# iter(reader).next()
 
# 序列化:把内存中的数据结构在不丢失其身份和类型信息的情况下,转成对象的文本或二进制表示。
# pickle, json, marshal, shelve
import cPickle  as pickle
my_data = {'a':1, 'b':2, 'c':3}
fp = open('picklefile.dat', 'wb')
pickle.dump(my_data, fp) # class - __getstate__(self)
fp.close()
fp = open('picklefile.dat', 'rb')
out = pickle.load(fp) # class - __setstate__(self, state)
fp.close()
print(out) # {'a': 1, 'c': 3, 'b': 2}
pickle.loads("cos\nsystem\n(S'dir'\ntR.") # 列出当前目录下所有文件,不安全 - 解决:继承类并定制化内容
 
# 编码器 json.JSONEncoder
try:
    import simplejson as json
except ImportError:
    import json
import datetime
d = datetime.datetime.now()
d1 = d.strftime('%Y-%m-%d %H:%M:%S')
print(d1, json.dumps(d1, cls = json.JSONEncoder)) # 也可以继承修改指定编码器json.JSONEncoder
# ('2017-09-28 11:00:46', '"2017-09-28 11:00:46"')
 
# traceback:出错时查看 调用栈
import sys
print(sys.getrecursionlimit()) # 最大递归深度:1000
import traceback
try:
    a = [1]
    print(a[1])
except IndexError as ex:
    print(ex) # list index out of range
    # traceback.print_exc() # 会导致程序中断
tb_type, tb_val, exc_tb = sys.exc_info()
for filename, linenum, funcname, source in traceback.extract_tb(exc_tb):
    print("%-33s:%s '%s' in %s()" % (filename, linenum, source, funcname))
    # H:/python/suggest0928.py         :353 'print(a[1])' in <module>()
 
# LOG的五个等级:DEBUG, INFO, WARNING(默认), ERROR, CRITICAL
# Logger, Handler, Formatter, Filter
import logging
logging.basicConfig(
    level = logging.DEBUG,
    filename = 'log.txt',
    filemode = 'w',
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
)
logger = logging.getLogger()
logger.info('[INFO]:I am a tester')
logger.debug('test logging module')
logger.error('this is error')
logger.critical('this is critical')
 
# thread: 多线程底层支持,以低级原始的方式处理和控制线程,较复杂
# threading: 基于thread,操作对象化,提供丰富特性
import threading
import time
def myfunc(a, delay):
    print('calculate %s after %s' % (a, delay))
    time.sleep(delay)
    print('begin')
    res = a*a
    print('result:', res)
    return res
t1 = threading.Thread(target = myfunc, args = (2, 5))
t2 = threading.Thread(target = myfunc, args = (6, 8))
print(t1.isDaemon()) # False 守护线程,默认False
print(t2.isDaemon())
# t2.setDaemon(True) # True 表示 线程全部执行完成后,主程序才会退出
t1.start()
t2.start()
 
# lock, mutex, condition, event, with lock, put,get
# 生产者消费者模型
import Queue
import threading
import random
write_lock = threading.Lock()
class Producer(threading.Thread):
    def __init__(self, q, con, name):
        super(Producer, self).__init__()
        self.q = q
        self.name = name
        self.con = con
        print('Producer ', self.name, ' started')
    def run(self):
        while(1):
            global write_lock
            # self.con.acquire()
            if self.q.full():
                with write_lock:
                    print('Queue is full, producer wait')
                # self.con.wait()
            else:
                value = random.randint(0,10)
                with write_lock:
                    print(self.name, 'put value:', self.name+':'+str(value), 'into queue')
                self.q.put(self.name+':'+str(value))
                # self.con.notify()
        # self.con.release()
class Consumer(threading.Thread):
    def __init__(self, q, con, name):
        super(Consumer, self).__init__()
        self.q = q
        self.name = name
        self.con = con
        print('Consumer ', self.name, ' started')
    def run(self):
        while(1):
            global write_lock
            # self.con.acquire()
            if self.q.empty():
                with write_lock:
                    print('Queue is empty, consumer wait')
                # self.con.wait()
            else:
                value = self.q.get()
                with write_lock:
                    print(self.name, 'get value:', value, 'from queue')
                # self.con.notify()
        # self.con.release()
q = Queue.Queue(10) # 先进先出,循环队列大小10
con = threading.Condition()
p1 = Producer(q, con, 'P1')
p2 = Producer(q, con, 'P2')
c1 = Consumer(q, con, 'C1')
p1.setDaemon(False)
p2.setDaemon(False)
c1.setDaemon(False)
# p1.setDaemon(True)
# p2.setDaemon(True)
# c1.setDaemon(True)
# p1.start()
# p2.start()
# c1.start()
 
'''
设计模式,静态语言风格
单例模式,保证系统中一个类只有一个实例而且该实例易于被外界访
模板方法:在一个方法中定义一个算法的骨架,并将一些事先步骤延迟到子类中。
    子类在不改变算法结构的情况下,重新定义算法中的某些步骤。
    混入mixins模式:基类在运行中可以动态改变(动态性)。
'''
 
# 发布 publish 订阅 subscribe 松散耦合 - 中间代理人 Broker
# blinker - python-message
# 库函数:关注日志产生,不关注日志输出;
# 应用:关注日志统一放置,不关注谁产生日志。
from collections import defaultdict
route_table = defaultdict(list)
def sub(topic, callback):
    if callback in route_table[topic]:
        return
    route_table[topic].append(callback)
def pub(topic, *a, **kw):
    for func in route_table[topic]:
        func(*a, **kw)
def greeting(name):
    print('hello, %s' % name)
sub('greet', greeting) # 订阅的时候将待调用的greeting放入dict中
pub('greet', 'tester') # hello, tester 发布的时候调用greeting函数
 
# 类的状态转移,例,当telnet\注册成功后,就不再需要登录\注册了。
def workday():
    print('work hard')
def weekend():
    print('play harder')
class People(): pass
people = People()
while True:
    for i in range(1,8,1):
        if i == 6:
            people.day = weekend
        if i == 1:
            people.day = workday
        people.day()
    break
 
# 工厂模式
# __init__(): 在类对象创建好后,进行变量的初始化
# __new__(): 创建实例,类的构造方法,需要返回object.__new__()
class TestMode(object):
    def __init__(self):
        print('i am father')
    def test(self):
        print('test is father')
class A(TestMode):
    def __init__(self):
        print('i am A')
    def test(self):
        print('test is A')
class B(TestMode):
    def __init__(self):
        print('i am B')
    def test(self):
        print('test is B')
class FactoryTest(object):
    content = {'a':A, 'b':B}
    def __new__(cls, name):
        if name in FactoryTest.content.keys():
            print('create old %s' % name)
            return FactoryTest.content[name]()
        else:
            print('create new %s' % name)
            return TestMode()
FactoryTest('a').test() # create old a - i am A - test is A
FactoryTest('A').test() # create new A - i am father - test is father
 
# 局部作用域 > 嵌套作用域 > 全局作用域 > 内置作用域
a = 1
def foo(x):
    global a
    a = a * x
    def bar():
        global a
        b = a * 2
        a = b + 1
        print(a)
    return bar()
foo(1) # 3
 
# self 隐式传递 -- 显式 优于 隐式
# 当子类覆盖了父类的方法,但仍然想调用父类的方法
class SelfTest():
    def test(self):
        print('self test')
SelfTest.test(SelfTest()) # self test
assert id(SelfTest.__dict__['test']) == id(SelfTest.test.__func__)
 
# 古典类 classic class
class A: pass
# 新式类 new style class
class B(object): pass
class D(dict): pass
# 元类 metaclass
class C(type): pass
a = A
b = B()
c = C(str)
d = D()
print(type(a)) # <type 'classobj'>
print(b.__class__, type(b)) # (<class '__main__.B'>, <class '__main__.B'>)
print(c.__class__, type(c)) # (<type 'type'>, <type 'type'>)
print(d.__class__, type(d)) # (<class '__main__.D'>, <class '__main__.D'>)
 
# 菱形继承 - 应避免出现
try:
    class A(object): pass
    class B(object): pass
    class C(A, B): pass
    class D(B, A): pass
    class E(C, D): pass
except:
    print('菱形继承 - '+'order (MRO) for bases B, A')
 
# __dict__[] 描述符,实例调用方法为bound,类调用方法为unbound
class MyClass(object):
    def my_method(self):
        print('my method')
print(MyClass.__dict__['my_method'], MyClass.my_method)
# (<function my_method at 0x03B62630>, <unbound method MyClass.my_method>)
print(MyClass.__dict__['my_method'](MyClass()), MyClass.my_method(MyClass()))
a = MyClass()
print(a.my_method, MyClass.my_method)
# (<bound method MyClass.my_method of <__main__.MyClass object at 0x038D3650>>, <unbound method MyClass.my_method>)
print(a.my_method.im_self, MyClass.my_method.im_self)
# (<__main__.MyClass object at 0x0391D650>, None)
 
# __getattribute__()总会被调用,而__getattr__()只有在__getattribute__()中引发异常的情况下才会被调用
class AA(object):
    def __init__(self, name):
        self.name  = name
        self.x = 20
    def __getattr__(self, name):
        print('call __getattr__:', name)
        if name == 'z':
            return self.x ** 2
        elif name == 'y':
            return self.x ** 3
    def __getattribute__(self, attr):
        print('call __getattribute__:', attr)
        try:
            return super(AA, self).__getattribute__(attr)
        except KeyError:
            return 'default'
a = AA("attribute")
print(a.name) # attribute
print(a.z) # 400
if hasattr(a, 'test'): # 动态添加了 test 属性,但不会在 __dict__ 中显示
    c = a.test
    print(c) # None
else:
    print('instance a has no attribute t')
print(a.__dict__) # {'x': 20, 'name': 'attribute'} 没有‘test’
 
# 数据描述符:一个对象同时定义了__get__()和__set__()方法,高级 - property装饰符
# 普通描述符:一种较为低级的控制属性访问机制
class Some_Class(object):
    _x = None
    def __init__(self):
        self._x = None
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.getter
    def x(self):
        return self._x
    @x.deleter
    def x(self):
        del self._x
obj = Some_Class()
obj.x = 10
print(obj.x + 2) # 12
print(obj.__dict__) # {'_x': 10}
del obj.x
print(obj.x) # None
print(obj.__dict__) # {}
 
# metaclass元类是类的模板,元类的实例为类
# 当你面临一个问题还在纠结要不要使用元类时,往往会有其他更为简单的解决方案
# 元方法可以从元类或者类中调用,不能从类的实例中调用。
# 类方法可以从类中调用,也可以从类的实例中调用
class TypeSetter(object):
    def __init__(self, fieldtype):
        print('TYpeSetter __init__', fieldtype)
        self.fieldtype = fieldtype
    def is_valid(self, value):
        return isinstance(value, self.fieldtype)
class TypeCheckMeta(type): # type为父类,是对type的重写,作为一个元类
    def __new__(cls, name, bases, dict):
        print('TypeCheckMeta __new__', name, bases, dict)
        return super(TypeCheckMeta, cls).__new__(cls, name, bases, dict)
    def __init__(self, name, bases, dict):
        self._fields = {}
        for key,value in dict.items():
            if isinstance(value, TypeSetter):
                self._fields[key] = value
    def sayHi(cls):
        print('HI')
class TypeCheck(object):
    __metaclass__ = TypeCheckMeta
    # 所有继承该类的子类都将使用元类来指导类的生成
    # 若未设置__metaclass__,使用默认的type元类来生成类
    def __setattr__(self, key, value):
        print('TypeCheck __setattr__')
        if key in self._fields:
            if not self._fields[key].is_valid(value):
                raise TypeError('Invalid type for field')
        super(TypeCheck, self).__setattr__(key, value)
class MetaTest(TypeCheck): # 由元类 TypeCheckMeta 指导生成
    name = TypeSetter(str)
    num = TypeSetter(int)
mt = MetaTest()
mt.name = 'apple'
mt.num = 100
MetaTest.sayHi() # 元方法可以从元类或者类中调用,不能从类的实例中调用。
# ('TypeCheckMeta __new__', 'TypeCheck', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <class '__main__.TypeCheckMeta'>, '__setattr__': <function __setattr__ at 0x0393DA70>})
# ('TYpeSetter __init__', <type 'str'>)
# ('TYpeSetter __init__', <type 'int'>)
# ('TypeCheckMeta __new__', 'MetaTest', (<class '__main__.TypeCheck'>,), {'__module__': '__main__', 'num': <__main__.TypeSetter object at 0x03951D50>, 'name': <__main__.TypeSetter object at 0x03951CF0>})
# TypeCheck __setattr__
# TypeCheck __setattr__
# HI
 
# 协议:一种松散的约定,没有相应的接口定义。
# 迭代器:统一的访问容器或集合 + 惰性求值 + 多多使用,itertools
from itertools import *
# print(''.join(i) for i in product('AB', repeat = 2))
for i in product('ABCD', repeat = 2):
    print(''.join(i)), # AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
print
for i in combinations('ABCD', 2): # AB AC AD BC BD CD
    print(''.join(i)),
print
 
# 生成器:按一定的算法生成一个序列。
# 生成器函数:使用了 yield,返回一个迭代器,以生成器的对象放回。
def fib(n):
    a, b = 1, 1
    while a < n:
        test = (yield a)
        print('test:', test)
        a, b = b, a+b
for i, f in enumerate(fib(10)):
    print(f), # 1 1 2 3 5 8
# 调用生成器函数时,函数体并不执行,当第一次调用next()方法时才开始执行,并执行到yield表达式后中止。
generator = fib(10)
print(generator, generator.next(), generator.next()) # (<generator object fib at 0x03A39EB8>, 1, 1)
print(generator.send(3)) # ('test:', 3)
 
# yield 与 上下文管理器 结合
from contextlib import contextmanager
@contextmanager
def tag(name):
    print('<%s>' % name)
    yield
    print('<%s>' % name)
with tag('hi'):
    print('hello')
# <hi>
# hello
# <hi>
 
# GIL : Global Interpreter Lock 全局解释器锁
# sys.setcheckinterval 自动线程间切换,默认每隔100个时钟
# 单核上的多线程本质上是顺序执行的
# 多核的效率比较低,考虑 multiprocessing
 
'''
无论使用何种语言开发,无论开发的是何种类型,何种规模的程序,都存在这样一点相同之处。
即:一定比例的内存块的生存周期都比较短,通常是几百万条机器指令的时间,
而剩下的内存块,起生存周期比较长,甚至会从程序开始一直持续到程序结束。
'''
# 引用计数算法 - 无法解决循环引用问题 - 设置threshold阈值 gc 模块
import gc
print(gc.isenabled()) # True
print(gc.get_threshold()) # (700, 10, 10)
print(gc.garbage) # []
# 循环引用可以使一组对象的引用计数不为0,然而这些对象实际上并没有被任何外部对象所引用,
# 它们之间只是相互引用。这意味着不会再有人使用这组对象,应该回收这组对象所占用的内存空间,
# 然后由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放。
a = []
b = []
a.append(b)
b.append(a)
print(a, b) # ([[[...]]], [[[...]]])
# python解决方案:当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,
# 而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,
# 而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。
# 在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,
# 当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
# 在Python中,总共有3“代”,也就是Python实际上维护了3条链表
 
# PyPI : Python Package Index - Python包索引
# https://pypi.python.org/pypi/{package}
# python setup.py install
# PyUnit unittest模块 - 测试代码先于被测试的代码,更有利于明确需求。
# import unittest
# unittest.main()
# 使用 Pylint 检查代码风格
# 代码审查工具:review board
# 将包发布到PyPI,供下载使用 - 这个流程需要走一遍
# 代码优化:
# 优先保证代码是可工作的
# 权衡优化的代价
# 定义性能指标,集中力量解决首要问题
# 不要忽略可读性
# 定位性能瓶颈问题 - CProfile
import cProfile
def foo():
    sum = 0
    for i in range(100):
        sum += i
    return sum
cProfile.run('foo()') # 针对 foo() 函数的运行时间分布统计
 
# 算法的评价 = 时间复杂度(重点) + 空间复杂度(硬件),一般采用以空间换时间的方法
# O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(cn)<O(n!)<O(nn)
 
# 循环优化:减少循环过程中的计算量,将内层计算提到上一层
# 使用不同的数据结构优化性能
# 列表 list
# 栈和队列 deque
# heapify()将序列容器转化为堆 heapq
import heapq
import random
list0 = [random.randint(0,100) for i in range(10)]
print(list0) #[55, 62, 17, 56, 82, 45, 87, 48, 65, 32]
heapq.heapify(list0)
print(list0) # [17, 32, 45, 48, 62, 55, 87, 56, 65, 82]
 
import array
a = array.array('c', 'string')
print(a.tostring()) # string
import sys
print(sys.getsizeof(a)) # 28
print(sys.getsizeof(list('string'))) # 72
import timeit
t = timeit.Timer("''.join(list('string'))")
print(t.timeit()) # 0.688437359057
t = timeit.Timer("a.tostring()", "import array; a = array.array('c', 'string')")
print(t.timeit()) # 0.163860804606
 
# set 集合的使用
list0 = [i for i in range(10)]
list1 = [i for i in range(20)]
print(set(list0)&set(list1)) # set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
 
# 进程同步:multiprocessing - Pipe, Queue - 解决多核下的GIL效率问题
# 线程同步:threading - Lock, Event, Condition, Semaphore
# 线程的生命周期:创建,就绪,运行,阻塞,终止
# 避免多次创建线程 - 线程池 threadpool
posted @   Gitwow  阅读(290)  评论(0编辑  收藏  举报

点击右上角即可分享
微信分享提示

🔸目录导航🔸