forked from feelingu1314/learn-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecord.py
3538 lines (2815 loc) · 124 KB
/
record.py
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
# split 按照指定的分隔符对字符串进行分割
str.split(str='',num=string.count(str))
#str -- 分隔符
#num -- 分割次数
a = ('/usr/lib/system/systemd')
a.split('/',1)
a.split('/',2)
# 循环判断
name = input('Please input your name:')
while True:
s1 = input('Please input your score of last year:')
if s1.isdigit():
s1 = float(s1)
while True:
s2 = input('Please input score of this year:')
if s2.isdigit():
s2 = float(s2)
p = (s2 - s1)/s2 * 100
# format method have two
print('Hi {0}, your score update {1:.1f}% in this year'.format(name,p))
print ('Hi %s, your score update %.1f%% in this year' % (name,p))
break
else:
print ('You must input number , Please try again')
break
else:
print('Your input invalid,Please input number ,try again')
# 生成器
# 把一个列表生成式由[]变成(),就可以变成一个生成器
# 生成器保存算法,不马上运算,而是在调用时才运算,一般用next()来调用,或者使用for循环来迭代
# 如果一个函数中有yield ,这个函数就是个生成器
# 迭代器
# 可用于for循环的对象称之为可迭代对象
# 可用next()函数调用返回下一个值的对象为迭代器
# 生成器都是迭代器
# list,dict,str等是可迭代对象,但不是迭代器,使用iter()可让他们变成迭代器
# 递归函数
class Tower(object):
def __init__(self):
self.counter = 0
def hanoi(self, n, org, aux, dst):
if n == 1:
self.counter += 1
print('{0}->{1}'.format(org, dst))
else:
self.hanoi(n - 1, org, dst, aux)
self.hanoi(1, org, aux, dst)
self.hanoi(n - 1, aux, org, dst)
def homework(*args):
tower = Tower()
print('移动步骤如下:')
tower.hanoi(*args)
print('总共移动次数为: {0}'.format(tower.counter))
homework(100,'a','b','c')
# 切片and递归函数
def trim(s):
if s[:1] != ' ' and s[-1:] != ' ':
return s
elif s[:1] == ' ':
return trim(s[1:])
elif s[-1:] == ' ':
return trim(s[:-1])
# 迭代和递归函数
def findMinAndMax(L):
if len(L) == 0:
result = None,None
elif len(L) == 1:
result = L[0],L[0]
# 边界条件
elif len(L) == 2:
if L[0] < L[1]:
result = L[0], L[1]
else:
result = L[1], L[0]
else:
# 每次递归都会用L[0]和minimum,maximum进行比较得出一个result
minimun, maximum = findMinAndMax(L[1:])
print(minimun,maximum)
if minimun > L[0]:
result = L[0],maximum
elif maximum < L[0]:
result = minimun,L[0]
else:
result = minimun,maximum
return result
s=[5,3,8,4,7]
print(findMinAndMax(s))
# 实现过程大致如下
# 5 和 findMinAndMax(3,8,4,7)里面得到的结果对比,但是要得出结果必须执行如下过程
# 3 和 findMinAndMax(8,4,7)里面得到的结果对比,但是要得出结果必须执行如下过程
# 8 和findMinAndMax(4,7)里面得到的结果对比,但是要得出结果必须执行如下过程
# findMinAndMax(4,7)里面得到的结果是minimum=4,maximum=7
#8和(4,7)对比得到的结果是minmum=4,maximum=8
#3和(4,8)对比得到的结果是minimum=3,maximum=8
#5和(3,8)对比得到的结果是minimum=3,maximum=8
# 列表生成式
# 要生成的元素放前面,后面跟for循环,最后跟条件
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [x.lower() for x in L1 if not isinstance(x,int) if x != None]
# 生成器,递归,以及杨辉三角
def triangles(n):
def _triangles(n):
if n == 1:
return [1]
else:
pre_line = _triangles(n - 1)
line = [pre_line[i] + pre_line[i + 1] for i in range(len(pre_line) - 1)]
line.insert(0, 1)
line.append(1)
return line
for y in range(n):
x = _triangles(y+1)
yield x
# map 及 reduce
# map 接受一个函数,作用与每个元素,然后将新结果返回
# reduce 接受一个函数,将元素中的两个参数计算,然后把结果继续和下一个元素做累计计算
def str2float(s):
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
l = s.split('.')
def char2num(s):
return DIGITS[s]
def to_int(x,y):
return x * 10 + y
def to_float(f):
n = 1
i = 0
while i < len(l[1]):
n = n * 10
i = i + 1
return f / n
if '.' not in s:
result = reduce(to_int,map(char2num,l[0]),0.0)
else:
result = reduce(to_int,map(char2num,l[0]))+to_float(reduce(to_int,map(char2num,l[1])))
return result
# filter
# 接受一个函数,依次作用与每个元素,然后根据返回值是True还是false决定是保留还是丢弃该元素
def _odd_iter():
n = 1
while True:
yield n
n = n + 1
def _is_palindrome(n):
return str(n) == str(n)[::-1]
def palindrome():
it = _odd_iter()
while True:
n = next(it)
yield n
it = filter(_is_palindrome,it)
for n in palindrome():
if n < 200:
print(n)
else:
break
# sorted
# 接受一个函数,作用于list中的每一个元素上
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return sorted(t,key=lambda name: name[0])
def by_score(t):
return sorted(t,key=lambda score: score[1],reverse=True)
# 返回函数及闭包
def createCounter():
def f():
n = 1
while True:
yield n
n = n + 1
sum = f()
def counter():
return next(sum)
return counter
# 匿名函数
# lambda 匿名函数,冒号前面为函数参数,右边为返回值
print(list(filter(lambda n: n % 2 == 1,range(1,20))))
def build(x,y):
return lambda: x*x+y*y
s = build(3,4)
# 装饰器
def metric(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
start = time.clock()
execfunc = func(*args,**kwargs)
end = time.clock()
duration = end-start
print('{0} execued in {1}'.format(func.__name__,duration))
return execfunc
return wrapper
@metric
def fast(x,y):
time.sleep(0.0012)
return x + y
f=fast(11,22)
print(f)
@metric
def slow(x,y,z):
time.sleep(0.1234)
return x * y * z
s = slow(11,22,33)
print(s)
# 偏函数
其实就是函数调用的时候,有多个参数 参数,但是其中的一个参数已经知道了,我们可以通过这个参数重新绑定一个新的函数,然后去调用这个新函数
通常用于函数需要多次调用同一个参数的时候
import tkinter
root=tkinter.Tk()
这个函数就是下面那个偏函数的定义版,随便用那个都可以,但是相对而言,还是偏函数更方便,更简洁
#def mybutton(**kw):
# return tkinter.Button(root,bg='blue',fg='white',**kw)
mybutton=partial(tkinter.Button,root,bg='blue',fg='white')
b1=mybutton(text='nihiao')
b2=mybutton(text='buhao')
b1.pack()
b2.pack()
root.mainloop()
# class 及 instance
class Person(object):
# 这里就是初始化你将要创建的实例的属性
def __init__(self,hight,weight,age):
self.hight = hight
self.weight = weight
self.age = age
# 定义你将要创建的实例所有用的技能
def paoniu(self):
print('you have')
def eat(self):
print('you can eat')
# 开始创建实例
zhangsan=Person(170,50,29)
lisi = Person(175,100,30)
# 你的实例开始使用它的技能
zhangsan.paoniu()
lisi.eat()
# class 访问限制
# class 内部的变量加上__变成私有变量,只有内部可以访问,外部无法访问
# 如果看到只有一个下划线_的变量,这样的实例,外部是可以访问的,但是意思是虽然我可以被访问,但是请视我为私有变量,不要随意访问
class Student(object):
def __init__(self,name,gender):
self.__name = name
self.__gender = gender
def __check_gender(self):
if self.__gender not in ('male','female'):
raise ValueError('bad')
def get_gender(self):
self.__check_gender()
return self.__gender
def set_gender(self,gender):
self.__gender = gender
self.__check_gender()
# class 的继承和多态
# 多态,直白点说,多个类型的对象拥有同样的方法,当然这不准确,可以从这个角度去想,比如,三种不同形状的按钮,但是,他们有一样的作用,就是click()
# 假若你现在有个编辑器,你根本不知道用户将要打开什么类型的文件(可能是pdf,word,excel,ppt...)
# 为此,我们创建一个Document类型的父类,有一个show()的方法
# 然后,我们分别创建pdf,word类型的class,继承Document,并且有它自己的show()方法
# 这样我们就可以打开不同类型的文件了,这就是多态了
# 说到多态,还不得不说一个鸭子类型,所谓鸭子类型,其实就是只要这个对象"看起来像鸭子,走起来像鸭子,那它就是个鸭子",什么意思呢,看下面的例子
# 在python中,对象的有效语义并不是由继承特定的类或实现特定的接口,而是由当前方法和属性的集合决定的。
# 鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用
# 其实多态在python表现的并不那么cool,python中更多的是鸭子类型
# 多态更多的表现在同一个方法,可以对多种类型进行操作,比如说 + 可以对数字进行操作,也可以对字符串进行操作,这就是多态的体现了
class Document:
def __init__(self, name):
self.name = name
def show(self):
raise NotImplementedError("Subclass must implement abstract method")
class Pdf(Document):
def show(self):
return 'Show pdf contents!'
class Word(Document):
def show(self):
return 'Show word contents!'
# 这个Job就是有个show()使它看起来像Document,所以,它就是个看起来像鸭子的"鸭子",但是,如果你通过isinstance(Job,Document)来判断的话,它实际上不真的是Document类型
class Job(object):
def __init__(self,name):
self.name = name
def show(self):
return 'Show job contents!'
documents = [Pdf('Document1'),
Pdf('Document2'),
Word('Document3'),
Job('Document4')]
for document in documents:
print(document.name + ': ' + document.show())
# class 获取对象信息,下面 有个例子
# 首先你有一个command.py文件,内容如下,这里我们假若它后面还有100个方法
class MyObject(object):
def __init__(self):
self.x = 9
def add(self):
return self.x + self.x
def pow(self):
return self.x * self.x
def sub(self):
return self.x - self.x
def div(self):
return self.x / self.x
# 然后我们有一个入口文件 exec.py,要根据用户的输入来执行后端的操作
from command import MyObject
computer=MyObject()
def run():
inp = input('method>')
if inp == 'add':
computer.add()
elif inp == 'sub':
computer.sub()
elif inp == 'div':
computer.div()
elif inp == 'pow':
computer.pow()
else:
print('404')
# 上面使用了if来进行判断,那么假若我的command里面真的有100个方法,那我总不可能写100次判断吧,所以这里我们就会用到python的反射特性,看下面的代码
from command import MyObject
computer=MyObject()
def run(x):
inp = input('method>')
# 判断是否有这个属性
if hasattr(computer,inp):
# 有就获取然后赋值给新的变量
func = getattr(computer,inp)
print(func())
else:
# 没有我们来set一个
setattr(computer,inp,lambda x:x+1)
func = getattr(computer,inp)
print(func(x))
if __name__ == '__main__':
run(10)
# class 模块及类的动态加载
import importlib
imp_module = 'hello'
imp_class = 'ClassA'
ip_module = importlib.import_module('.',imp_module)
ip_module_cls = getattr(ip_module,imp_class)
cls_obj = ip_module_cls()
print(dir(cls_obj))
for attr in dir(cls_obj):
if attr[0] != '_':
class_attr_obj = getattr(cls_obj,attr)
if hasattr(class_attr_obj,'__call__'):
class_attr_obj()
else:
print(attr,' Type:',type(class_attr_obj),' Value:', class_attr_obj)
# 重新加载模块,但原来已经使用的实例还是会使用旧的模块,而新生产的实例会使用新的模块,reload后还是用原来的内存地址。
ip_module = importlib.reload(ip_module)
print(dir(cls_obj))
# class 类属性
# 实例属性和类属性不要使用相同的名字
class Student(object):
count = 0
def __init__(self,name):
self.name = name
Student.count = Student.count + 1
# __slots__ 绑定限制
# 正常情况下,我们可以给实例绑定属性,也可以个实例绑定方法
# 但是,绑定的属性和方法只对当前实例有效,如果有要为所有实例绑定属性和方法,则可以为类绑定属性和方法
# __slots__ 可以限定绑定的属性
# __slots__ 只对当前类实例起作用,对继承的子类是不起作用的,除非在子类中也定义__slots__,这时候子类运行绑定的属性就是父类+子类的__slots__
# property
@property
#举个例子,现在我们有一个class,可以将温度转化为华氏度
class Celsius(object):
def __init__(self,temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
man = Celsius()
man.temperature = 37
man.to_fahrenheit()
#然后,有个客户提出需求,要求我们的温度不能低于-273,这时候我们可以将属性temperature隐藏起来,并且可以对参数的输入进行一下检查
class Celsius(object):
def __init__(self,temperature = 0):
self.set_temperature(temperature)
def get_temperature(self):
return self._temperature
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def set_temperature(self,value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
c = Celsius(-277)
c = Celsius(37)
c.get_temperature()
c.set_temperature(10)
#这时候温度确实被检查,已经不能设置低于-273度了,但是,这时候,我们需要对所有obj.temperature = value 修改成 obj.temperature(value)
#如果代码少还好说,要是多了,那就不得了了,那么有没有既能检查参数,又能像像属性那样的方式来访问方法呢,这时候就要用到@property了
class Celsius(object):
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value
temperature = property(fget=get_temperature,fset=set_temperature)
#property() 本身是一个内置的函数,它的签名是property(fget=None,fset=None,fdel=None,doc=None)
#一个property对象有三种方法,getter(),setter(),delete(),对应的fget,fset,fdel
#像我们上面的temperature = property(fget=get_temperature,fset=set_temperature)
#我们可以理解为
temperature = property()
temperature = temperature.getter(get_temperature)
temperature = temperature.setter(set_temperature)
#想想前面学的装饰器,我们就知道了temperature obj通过temperature.getter装饰器来装饰了get_temperature,然后又有了temperature.setter装饰器
#所以,最终我们可以写成如下
class Celsius(object):
def __init__(self,temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self._temperature
@temperature.setter
def temperature(self,value):
if value < -273:
raise ValueError('Temperature below -273 is not possible')
print("setting value")
self._temperature = value
# 多重继承
# 所谓多重继承,是指python的类可以有两个以上的父类
# 要熟悉多重继承,只要了解结构算法中的拓扑排序即可
# 多重继承的继承关系,按照C3算法得出,通常是从入度为0的位置查起,剪掉入度为0位置的相关边,接着继续查找入度为0的位置,依次重复
# 定制类
# 在我们编写一个新的Python类的时候,总是在最开始位置写一个初始化方法__init__,以便初始化对象,然后会写一个__str__方法,方面我们调试程序。
class Student(object):
def __init__(self,name):
self._name = name
def __str__(self):
return 'Student object(name: {})'.format(self._name)
__repr__ = __str__
s = Student('Michael')
print(s)
# 如果我们要写一个生成器类,那么我们就得用到`__iter__`和`__next__`
class Fib(object):
def __init__(self):
self.a,self.b=0,1
def __iter__(self):
return self
def __next__(self):
self.a,self.b = self.b,self.a+self.b
if self.a > 10:
raise StopIteration()
return self.a
s = Fib()
for i in s:
print(i)
# for为了兼容性其实有两种机制,如果对象有__iter__会使用迭代器,但是如果对象没有__iter__,但是实现了__getitem__,会改用下标迭代的方式
class Fib(object):
def __init__(self):
self.a,self.b=0,1
def __getitem__(self, item):
self.a,self.b = self.b,self.a+self.b
if self.a > 20:
raise StopIteration()
return self.a
s = Fib()
print(s[0])
# __getattr__
# 在没找到属性的情况下调用__getattr__
class Chain(object):
def __init__(self, path=''):
self._path = path
def __getattr__(self, path): # __getattr__返回一个Chain类的实例,所以后面继续使用点符访问属性也是可以的,这就是链式调用的本质
self._path = '{0}/{1}'.format(self._path,path)
return self
# return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
__call__ = __getattr__
__repr__ = __str__
print(Chain('/status').users('michael').repos)
# __call__
# 一个对象实例可以有自己的属性和方法,当我们调用实例方法时,我们用 实例名.方法名() 的方式来调用。能不能直接把实例本身当作一个方法调用呢
# 对任何类来说,只需要实现 __call__() 方法,就可以直接对该类的实例进行调用
class Student(object):
def __init__(self, name):
self.name = name
# 当我们取消__call__的注释之后,实例就变成了可被调用的对象了
# def __call__(self):
# print('My name is %s.' % self.name)
s = Student('Michael')
print(callable(s))
# 枚举类
# 枚举成员名称不能重复,但是值是可以重复的
# 标准的Enum枚举是无法进行比较的
# 我们可以使用IntEnum类进行枚举,成员就可以与整数进行比较
from enum import Enum,unique
#1、函数式API调用
# 第一个参数是枚举名称
# 第二个参数是枚举成员名称的源
Month = Enum('Month',('Jan','Feb','Mar'))
for name,member in Month.__members__.items(): # list all enum members,including aliases,既然是map自然就会有items
print(name,'=>',member,',',member.value) #value属性是自动赋给成员的int常量,默认从1开始记数
#2、自定义枚举类
@unique #保证不重复
class Weekday(Enum):
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
#访问这些枚举类型可以有若干种方法:
day1 = Weekday.Mon
print(day1) #Weekday.Mon
print(day1.value) #1,通过枚举常量获取value
print(Weekday(1)) #Weekday.Mon,通过value获取枚举常量
# 枚举类可以按定义顺序进行迭代
for value in Weekday:
print(value,value.value)
# 元类
# 元类就是用来创建这些类(对象)的,元类就是类的类,
# 1.拦截类的创建;2.修改类;3.返回修改之后的类
# 除了使用type()动态创建类以外,要控制类的创建行为,就可以使用metaclass。
# type实际上就是一个元类,因此type()函数可以创建class
# 要创建一个class对象,type()函数依次传入3个参数
# 1.class 名称;2.继承的父类集合;3.class的方法名称与函数绑定
def fn(self,name='world'):
print('Hello,{0}'.format(name))
Hello = type('Hello',(object,),dict(hello=fn))
# 看下面这个例子
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)
# 我们知道在python中一切皆对象
# 那么下面我们的s其实就是一个类对象,它的__name__其实和Foo的__name__是一样的
# 看下面的方法是不是和type创建类有点像?
s = UpperAttrMetaclass('Foo',(object,),{'bar':'bip'})
print(hasattr(s,'bar'))
print(hasattr(s,'BAR'))
print(s.BAR)
class Foo(object,metaclass=UpperAttrMetaclass):
bar='bip'
print(hasattr(Foo,'bar'))
print(hasattr(Foo,'BAR'))
print(Foo.BAR)
# 最后它们输出的结果其实是一模一样的,这就说明了类其实和我们普通的实例对象差不多,只不过普通实例是通过类创建,而类是通过元类创建
# 而__new__就是用来创建实例的,不论是普通的实例,还是类实例,总之就是个实例
# __new__()方法接收到的参数依次是:
# 1.当前准备创建的类的对象;2.类的名字;3.类继承的父类集合;4.类的方法集合。
# 实际上在我们实例化对象时,python默认执行了__new__操作,先创建类实例,然后才使用__init__初始化实例
# python新类允许用户重载__new__和__init__方法。__new__创建类实例,__init__初始化一个已被创建的实例。看下面的代码
class newStyleClass(object):
def __new__(cls):
print("__new__ is called")
return super(newStyleClass, cls).__new__(cls)
def __init__(self):
print("__init__ is called")
print("self is: ", self)
newStyleClass()
# 我们发现__new__函数先被调用,接着__init__函数在__new__函数返回一个实例的时候被调用,并且这个实例作为self参数被传入了__init__函数
# 这里需要注意的是,如果__new__函数返回一个已经存在的实例(不论是哪个类的),__init__不会被调用。看下面的代码
obj = 12
# obj can be an object from any class, even object.__new__(object)
class returnExistedObj(object):
def __new__(cls):
print("__new__ is called")
return obj
def __init(self):
print("__init__ is called")
returnExistedObj()
# 错误处理
from functools import reduce
def str2num(s):
try:
if '.' not in s:
return int(s)
else:
return float(s)
except Exception as e:
raise
def calc(exp):
ss = exp.split('+')
ns = map(str2num, ss)
return reduce(lambda acc, x: acc + x, ns)
def main(s):
r = calc(s)
print('{0}={1}'.format(s,r))
a='100 + 200 + 345'
b='99 + 88 + 7.9'
if __name__ == '__main__':
main(a)
main(b)
# 调试
# 就调试而言有很多种方式
# assert断言,IDE调试,logging才是终极方案
import logging
# 定义日志级别
logging.basicConfig(level=logging.ERROR)
s = '0'
n = int(s)
# assert n !=0,'n is zero'
# 可以通过-O参数来关闭assert
# 输出错误,或者可以输出到文件
logging.error('n={0}'.format(n))
print(10/n)
# 单元测试
# 我们写好代码之后,往往需要写一些单元测试来测试程序是否满足我们的需求
# 这时候引入python自带的unittest模块,写一个测试模块
# 写一个测试类,从unittest.TestCase继承
# 每一类测试都需要编写一个test_xxx()方法
# 常用的断言是assertEqual(),判断函数返回结果是否和给出的结果相等
# assertTrue(),返回的结果是否为True
# assertRaise(KeyError),期待抛出指定类型的Error,比如说,当一个条件不满足时,抛出KeyError
# 实际例子
# mydict.py
class Dict(dict):
def __init__(self, **kw):
super().__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
# 这里我们定义了一个AttributeError
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
#mydict_test.py
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
# 另外,我们还可以在单元测试中写两个特殊的方法setUp,setDown,这两个方法会分别在没调用一个测试方法的前后分别执行
# 比如我们要测试一个跟数据库有关的程序时,就可以在setUp中链接数据库,在setDown中关闭数据库
def setUp(self):
print('setUp...')
def tearDown(self):
print('tearDown...')
def test_init(self):
d = Dict(a=1, b='test')
# 断言部分,d.a 是否为1
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
# 断言部分,d是否为一个dict
self.assertTrue(isinstance(d, dict))
def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEqual(d.key, 'value')
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value')
def test_keyerror(self):
d = Dict()
# 这里我们就期待返回我们程序中定义的KeyError
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
# 这里我们就期待返回我们程序中定义的AttributeError
with self.assertRaises(AttributeError):
value = d.empty
if __name__ == '__main__':
unittest.main()
# 写好测试模块后,我们可以使用 python -m unittest mydict_test来直接运行单元测试
# 用这种方法,可以依次批量运行多个单元测试
# 文档测试
# 写了个函数,或者写了个类,具体要怎么使用,可以在注释中说明,然后写个文档测试放在里面,在直接运行命令的时候,执行文档测试
def fact(n):
"""
Calculate 1*2*3...*n
>>> fact(1)
1
>>> fact(10)
3628800
"""
if n < 1:
raise ValueError()
if n == 1:
return 1
return n * fact(n-1)
if __name__=='__main__':
import doctest
doctest.testmod()
# I/O编程
# IO操作有两个数据流input和output,这个是相对内存而言
# IO中有同步IO和异步IO
# 同步IO为,当程序部分代码需要执行一段时间,那么CPU等待着,等这部分代码执行完成后再执行后续的代码
# 而异步IO为,程序需要长时间执行的代码还是做它的事,而CPU继续去执行它后后面的代码
# 而根据通知方式的不同,如果CPU时不时的来查看这段代码是否执行完,则为轮询模式,如果是代码执行完之后,通知CPU,这就是回调模式
# 文件读写
# 如果文件小,直接read即可
# 如果文件大,用read(size)
# readline()一次读取一行
# readlines()一次读取所有内容,并返回一个list,配置文件会用到比较多
# 用with..open..as..代替try...except...finally,关闭io
with open('test.txt','r') as f:
print(f.read())
# 像open()函数返回的这种带有read()方法的对象,称为file-like object,除了file外,还可以是内存的字节流,网络流,自定义流
# StringIO就是在内存中创建的file-like object,用作临时缓冲
# 如果我们要读取图片,视频,二进制文件,那么用'rb'模式打开即可
with open('video.mp4','rb') as f:
print(f.read())
# 如果要读取非UTF-8编码的文件,要给open()函数传入一个encoding参数
with open('test.txt','r',encoding='gbk') as f:
print(f.read())
# 如果我们遇到某些文本中包含了一些非编码的字符,遇到这种情况,我们只需要加上一个errors='ignore'直接忽略掉即可
with open('test.txt','r',encoding='gbk',errors='ignore') as f:
print(f.read())
# 如果是写入文件,那么就是传入标识符不一样而已,写的时候,传入的标识符是'w',或者二进制为'wb',如果是追加文件内容则传入'a'
with open('test.txt','w') as f:
f.write('nihao')
with open('test.txt','a',encoding = 'utf-8') as f:
f.write('\nworld!')
# 同样如果要写入特定编码的文件,在open()函数传入encoding指定编码即可
with open('test.txt','w',encoding='utf-8') as f:
f.write('nihao')
# 替换文本文件中的一些内容
# 没那么复杂,打开文件,然后读取内容到内存中
with open('test.txt','r') as f:
s = f.readlines()
# 接着打开文件,用replace替换掉你内存中的内容,然后写入文件
with open('test.txt','w') as w:
for i in s:
w.write(i.replace('nihao','hi'))
# StringIO和BytesIO
# stringIO 比如说,这时候,你需要对获取到的数据进行操作,但是你并不想把数据写到本地硬盘上,这时候你就可以用stringIO
from io import StringIO
from io import BytesIO
def outputstring():
return 'string \nfrom \noutputstring \nfunction'
s = outputstring()
# 将函数返回的数据在内存中读
sio = StringIO(s)
# 可以用StringIO本身的方法
print(sio.getvalue())
# 也可以用file-like object的方法
s = sio.readlines()
for i in s:
print(i.strip())
# 将函数返回的数据在内存中写
sio = StringIO()
sio.write(s)
# 可以用StringIO本身的方法查看
s=sio.getvalue()
print(s)
# 如果你用file-like object的方法查看的时候,你会发现数据为空
sio = StringIO()
sio.write(s)
for i in sio.readlines():
print(i.strip())