python实战 Python基础 爱吃窝窝头 2023-11-30 2023-11-30 ⼀、Python基础 [TOC]
Python基础 主要总结Python常⽤内置函数;Python独有的语法特性、关键词 nonlocal, global等; 内置数据结构包括:列表(list), 字典(dict), 集合(set), 元组(tuple) 以及相关的⾼级模块 collections中 的 Counter, namedtuple, defaultdict, heapq模块。⽬前共有 90个⼩例⼦。
1 求绝对值 绝对值或复数的模
2 元素都为真 接受⼀个迭代器,如果迭代器的 所有元素 都为真,那么返回 True,否则返回 False
3 元素⾄少⼀个为真 接受⼀个迭代器,如果迭代器⾥ ⾄少有⼀个 元素为真,那么返回 True,否则返回 False
4 ascii展⽰对象 调⽤对象的repr() ⽅法,获得该⽅法的返回值,如下例⼦返回值为字符串
class Student (): def __init__ (self,id ,name ): self.id = id self.name = name def __repr__ (self ): return 'id = ' +self.id +', name = ' +self.name xiaoming = Student(id ='001' ,name='xiaoming' ) print (xiaoming)
5 ⼗转⼆ 将 ⼗进制 转换为 ⼆进制
6 ⼗转⼋ 将 ⼗进制 转换为 ⼋进制
7 ⼗转⼗六 将 ⼗进制 转换为 ⼗六进制
8 判断是真是假 测试⼀个对象是True, 还是False.
9 字符串转字节 将⼀个 字符串 转换成 字节 类型
s = "apple" bytes (s, "utf-8" )
10 转为字符串 将 字符类型 、 数值类型 等转换为 字符串 类型
11 是否可调⽤ 判断对象是否可被调⽤,能被调⽤的对象就是⼀个 callable 对象,⽐如函数 str, int 等都是可被调 ⽤的,但是例⼦4 中 xiaoming实例是不可被调⽤的:
如果想让 xiaoming能被调⽤ xiaoming(), 需要重写 Student类的 __call__⽅法:
class Student (): def __init__ (self,id ,name ): self.id = id self.name = name def __repr__ (self ): return 'id = ' +self.id +', name = ' +self.name def __call__ (self ): print ('I can be called' ) print (f'my name is {self.name} ' ) t = Student('001' ,'xiaoming' ) t()
12 ⼗转ASCII 查看⼗进制整数对应的 ASCII字符
13 ASCII转⼗ 查看某个 ASCII字符 对应的⼗进制数
14 类⽅法 classmethod 装饰器对应的函数不需要实例化,不需要 self参数,但第⼀个参数需要是表⽰⾃⾝类 的 cls 参数,可以来调⽤类的属性,类的⽅法,实例化对象等。
class Student (): def __init__ (self,id ,name ): self.id = id self.name = name def __repr__ (self ): return 'id = ' +self.id +', name = ' +self.name @classmethod def f (cls ): print (cls)
15 执⾏字符串表⽰的代码 将字符串编译成python能识别或可执⾏的代码,也可以将⽂字读成字符串再编译。
s = "print('Hello world!')" r = compile (s,"<string>" ,"exec" )
16 创建复数 创建⼀个复数
17 动态删除属性 删除对象的属性
18 转为字典 创建数据字典
dict (zip (['a' ,'b' ],[1 ,2 ]))
19 ⼀键查看对象所有⽅法 不带参数时返回 当前范围 内的变量、⽅法和定义的类型列表;带参数时返回 参数 的属性,⽅法列表。
20 取商和余数 分别取商和余数
21 枚举对象 返回⼀个可以枚举的对象,该对象的next()⽅法将返回⼀个元组。
s = ["a" ,"b" ,"c" ] for i,v in enumerate (s,1 ): print (i,v)
22 计算表达式 将字符串str 当成有效的表达式来求值并返回计算结果取出字符串中内容
23 查看变量所占字节数 import syss = {"a" :"b" ,"b" :"a" } sys.getsizeof(s)
24 过滤器 在函数中设定过滤条件,迭代元素,保留返回值为 True的元素:
fil = filter (lambda x : x > 10 ,[1 ,11 ,2 ,45 ,7 ,6 ,13 ]) print (list (fil))
25 转为浮点类型 将⼀个整数或数值型字符串转换为浮点数
如果不能转化为浮点数,则会报 ValueError:
26 字符串格式化 格式化输出字符串,format(value, format_spec)实质上是调⽤了value的format(format_spec)⽅法。
print ("i am {0},age{1}" .format ("tom" ,18 ))
27 冻结集合 创建⼀个不可修改的集合。
28 动态获取对象属性 获取对象的属性
class Student (): def __init__ (self,id ,name ): self.id = id self.name = name def __repr__ (self ): return 'id = ' +self.id +', name = ' +self.name xiaoming = Student(id ='001' ,name='xiaoming' ) getattr (xiaoming,'id' )
29 对象是否有这个属性
hasattr (xiaoming,'address' )
30 返回对象的哈希值 返回对象的哈希值,值得注意的是⾃定义的实例都是可哈希的, list, dict, set等可变对象都是不 可哈希的(unhashable)
31 ⼀键帮助 返回对象的帮助⽂档
32 对象门牌号 返回对象的内存地址
33 获取⽤户输⼊ 获取⽤户输⼊内容
34 转为整型 int(x, base =10) , x可能为字符串或数值,将x 转换为⼀个普通整数。如果参数是字符串,那么它可能包 含符号和⼩数点。如果超出了普通整数的表⽰范围,⼀个长整数被返回。
35 isinstance 判断object是否为类classinfo的实例,是返回true
isinstance (xiaoming,Student)
36 ⽗⼦关系鉴定 class undergraduate (Student ): def studyClass (self ): pass def attendActivity (self ): pass
issubclass (undergraduate,Student)
issubclass (object ,Student)
issubclass (Student,object )
如果class是classinfo元组中某个元素的⼦类,也会返回True
issubclass (int ,(int ,float ))
37 创建迭代器类型 使⽤ iter(obj, sentinel), 返回⼀个可迭代对象, sentinel可省略(⼀旦迭代到此元素,⽴即终⽌)
lst = [1 ,3 ,5 ] for i in iter (lst): print (i)
class TestIter (object ): def __init__ (self ): self.l=[1 ,3 ,2 ,3 ,4 ,5 ] self.i=iter (self.l) def __call__ (self ): item = next (self.i) print ("__call__ is called,fowhich would return" ,item) return item def __iter__ (self ): print ("__iter__ is called!!" ) return iter (self.l)
38 所有对象之根 object 是所有类的基类
39 打开⽂件 返回⽂件对象
f = open ('./json.js' ,mode='r' , encoding='GBK' ) f.read()
mode取值表:
40 次幂 base为底的exp次幂,如果mod给出,取余
41 打印
print ('lst:{}' .format (lst))
42 创建属性的两种⽅式 返回 property 属性,典型的⽤法:
class C : def __init__ (self ): self._x = None def getx (self ): return self._x def setx (self, value ): self._x = value def delx (self ): del self._x x = property (getx, setx, delx, "I'm the 'x' property." )
使⽤python装饰器,实现与上完全⼀样的效果代码:
class C : def __init__ (self ): self._x = None @property def x (self ): return self._x @x.setter def x (self, value ): self._x = value @x.deleter def x (self ): del self._x
43 创建range序列
range(stop) 2) range(start, stop[,step])
⽣成⼀个不可变序列:
44 反向迭代器 rev = reversed ([1 ,4 ,2 ,3 ,1 ]) for i in rev: print (i)
45 四舍五⼊ 四舍五⼊, ndigits代表⼩数点后保留⼏位:
46 转为集合类型 返回⼀个set对象,集合内不允许有重复元素:
47 转为切⽚对象 class slice(start, stop[, step])
返回⼀个表⽰由 range(start, stop, step) 所指定索引集的 slice对象,它让代码可读性、可维护性变好。
a = [1 ,4 ,2 ,3 ,1 ] my_slice_meaning = slice (0 ,5 ,2 ) a[my_slice_meaning]
48 拿来就⽤的排序函数 排序:
a = [{'name' :'xiaoming' ,'age' :18 ,'gender' :'male' },{'name' :'xiaohong' ,'age' :20 ,'gender' :'female' }] sorted (a,key=lambda x:x['age' ],reverse=False )print (a)
49 求和函数 求和:
a = [1 ,4 ,2 ,3 ,1 ] sum (a)sum (a,10 )
50 转元组 tuple() 将对象转为⼀个不可变的序列类型
i_am_list = [1 ,3 ,5 ] i_am_tuple = tuple (i_am_list) i_am_tuple
51 查看对象类型 class type(name, bases, dict) 传⼊⼀个参数时,返回 object 的类型:
class Student (): def __init__ (self,id ,name ): self.id = id self.name = name def __repr__ (self ): return 'id = ' +self.id +', name = ' +self.name
xiaoming = Student(id ='001' ,name='xiaoming' ) type (xiaoming)
52 聚合迭代器 创建⼀个聚合了来⾃每个可迭代对象中的元素的迭代器:
x = [3 ,2 ,1 ] y = [4 ,5 ,6 ] list (zip (y,x))
a = range (5 ) b = list ('abcde' ) b [str (y) + str (x) for x,y in zip (a,b)]
53 nonlocal⽤于内嵌函数中 关键词 nonlocal常⽤于函数嵌套中,声明变量 i 为⾮局部变量; 如果不声明, i+=1表明 i 为函数 wrapper内的局部变量,因为在 i+=1引⽤(reference)时,i未被声明,所以会报 unreferenced variable的错误。
import timedef excepter (f ): i = 0 t1 = time.time() def wrapper (): try : f() except Exception as e: nonlocal i i += 1 print (f'{e.args[0 ]} : {i} ' ) t2 = time.time() if i == n: print (f'spending time:{round (t2-t1,2 )} ' ) return wrapper
54 global 声明全局变量 先回答为什么要有 global,⼀个变量被多个函数引⽤,想让全局变量被所有函数共享。有的伙伴可能 会想这还不简单,这样写:
i = 5 def f (): print (i) def g (): print (i) pass f() g()
f和g两个函数都能共享变量 i ,程序没有报错,所以他们依然不明⽩为什么要⽤ global.
但是,如果我想要有个函数对 i 递增,这样:
此时执⾏程序,bang, 出错了! 抛出异常: UnboundLocalError,原来编译器在解释 i+=1时会把 i 解析为函数 h()内的局部变量,很显然在此函数内,编译器找不到对变量 i 的定义,所以会报错。
global就是为解决此问题⽽被提出,在函数h内,显⽰地告诉编译器 i 为全局变量,然后编译器会在 函数外⾯寻找 i 的定义,执⾏完 i+=1后, i 还为全局变量,值加1:
i = 0 def h (): global i i += 1 h() print (i)
56 不⽤else和if实现计算器 from operator import *def calculator (a, b, k ): return { '+' : add, '-' : sub, '*' : mul, '/' : truediv, '**' : pow }[k](a, b) calculator(1 , 2 , '+' ) calculator(3 , 4 , '**' )
57 链式操作 from operator import (add, sub)def add_or_sub (a, b, oper ): return (add if oper == '+' else sub)(a, b) add_or_sub(1 , 2 , '-' ) add_or_sub(1 , 2 , '+' )
58 交换两元素 def swap (a, b ): return b, a print (swap(1 , 0 ))
59 去最求平均 def score_mean (lst ): lst.sort() lst2=lst[1 :(len (lst)-1 )] return round ((sum (lst2)/len (lst2)),1 ) lst=[9.1 , 9.0 ,8.1 , 9.7 , 19 ,8.2 , 8.6 ,9.8 ] score_mean(lst)
60 打印99乘法表 打印出如下格式的乘法表
1 *1 =1 1 *2 =2 2 *2 =4 1 *3 =3 2 *3 =6 3 *3 =9 1 *4 =4 2 *4 =8 3 *4 =12 4 *4 =16 1 *5 =5 2 *5 =10 3 *5 =15 4 *5 =20 5 *5 =25 1 *6 =6 2 *6 =12 3 *6 =18 4 *6 =24 5 *6 =30 6 *6 =36 1 *7 =7 2 *7 =14 3 *7 =21 4 *7 =28 5 *7 =35 6 *7 =42 7 *7 =49 1 *8 =8 2 *8 =16 3 *8 =24 4 *8 =32 5 *8 =40 6 *8 =48 7 *8 =56 8 *8 =64 1 *9 =9 2 *9 =18 3 *9 =27 4 *9 =36 5 *9 =45 6 *9 =54 7 *9 =63 8 *9 =72 9 *9 =81
⼀共有10 ⾏,第 i ⾏的第 j 列等于: j*i,
其中,
i 取值范围: 1<=i<=9
j 取值范围: 1<=j<=i
根据 例⼦分析 的语⾔描述,转化为如下代码:
for i in range (1 ,10 ): for j in range (1 ,i+1 ): print (f"{i} *{j} ={i*j} " ,end="\t" ) print ()
61 全展开 对于如下数组:
如何完全展开成⼀维的。这个⼩例⼦实现的 flatten是递归版,两个参数分别表⽰带展开的数组,输出 数组。
from collections.abc import *def flatten (lst, out_lst=None ): if out_lst is None : out_lst = [] for i in lst: if isinstance (i, Iterable): flatten(i, out_lst) else : out_lst.append(i) return out_lst
调⽤ flatten:
print (flatten([[1 ,2 ,3 ],[4 ,5 ]]))print (flatten([[1 ,2 ,3 ],[4 ,5 ]], [6 ,7 ]))print (flatten([[[1 ,2 ,3 ],[4 ,5 ,6 ]]]))
62 列表等分 from math import ceildef divide (lst, size ): if size <= 0 : return [lst] return [lst[i * size:(i+1 )*size] for i in range (0 , ceil(len (lst) / size))] r = divide([1 , 3 , 5 , 7 , 9 ], 2 ) print (r) r = divide([1 , 3 , 5 , 7 , 9 ], 0 ) print (r) r = divide([1 , 3 , 5 , 7 , 9 ], -3 ) print (r)
63 列表压缩 def filter_false (lst ): return list (filter (bool , lst)) lst = [None , 0 , False , '' , [], 'ok' , [1 , 2 ]] r = filter_false(lst) print (r)
64 更长列表 def max_length (*lst ): return max (*lst, key=lambda v: len (v)) r = max_length([1 , 2 , 3 ], [4 , 5 , 6 , 7 ], [8 ]) print (f'更长的列表是{r} ' ) r = max_length([1 , 2 , 3 ], [4 , 5 , 6 , 7 ], [8 , 9 , 10 , 11 , 11 ]) print (f'更长的列表是{r} ' )
65 求众数 def top1 (lst ): return max (lst, default='列表为空' , key=lambda v: lst.count(v)) lst = [1 , 3 , 3 , 2 , 1 , 1 , 2 ] r = top1(lst) print (f'{lst} 中出现次数最多的元素为:{r} ' )
66 多表之最 def max_lists (*lst ): return max (max (*lst, key=lambda v: max (v))) r = max_lists([1 , 2 , 3 ], [6 , 7 , 8 ], [4 , 5 ]) print (r)
67 列表查重 def has_duplicates (lst ): return len (lst) == len (set (lst)) x = [1 , 1 , 2 , 2 , 3 , 2 , 3 , 4 , 5 , 6 ] y = [1 , 2 , 3 , 4 , 5 ] has_duplicates(x) has_duplicates(y)
68 列表反转 def reverse (lst ): return lst[::-1 ] r = reverse([1 , -2 , 3 , 4 , 1 , 2 ]) print (r)
69 浮点数等差数列 def rang (start, stop, n ): start,stop,n = float ('%.2f' % start), float ('%.2f' % stop),int ('%.d' % n) step = (stop-start)/n lst = [start] while n > 0 : start,n = start+step,n-1 lst.append(round ((start), 2 )) return lst rang(1 , 8 , 10 )
71 map实现向量运算 lst1=[1 ,2 ,3 ,4 ,5 ,6 ] lst2=[3 ,4 ,5 ,6 ,3 ,2 ] list (map (lambda x,y:x*y+1 ,lst1,lst2))
72 值最⼤的字典 def max_pairs (dic ): if len (dic) == 0 : return dic max_val = max (map (lambda v: v[1 ], dic.items())) return [item for item in dic.items() if item[1 ] == max_val] r = max_pairs({'a' : -10 , 'b' : 5 , 'c' : 3 , 'd' : 5 }) print (r)
73 合并两个字典 def merge_dict (dic1, dic2 ): return {**dic1, **dic2} merge_dict({'a' : 1 , 'b' : 2 }, {'c' : 3 })
74 topn字典 from heapq import nlargestdef topn_dict (d, n ): return nlargest(n, d, key=lambda k: d[k]) topn_dict({'a' : 10 , 'b' : 8 , 'c' : 9 , 'd' : 10 }, 3 )
75 异位词 from collections import Counterdef anagram (str1, str2 ): return Counter(str1) == Counter(str2) anagram('eleven+two' , 'twelve+one' ) anagram('eleven' , 'twelve' )
76 逻辑上合并字典 (1) 两种合并字典⽅法 这是⼀般的字典合并写法
dic1 = {'x' : 1 , 'y' : 2 } dic2 = {'y' : 3 , 'z' : 4 } merged1 = {**dic1, **dic2}
修改merged[‘x’]=10,dic1中的x值 不变 , merged是重新⽣成的⼀个 新字典 。
但是, ChainMap却不同,它在内部创建了⼀个容纳这些字典的列表。因此使⽤ChainMap合并字典, 修改merged[‘x’]=10后,dic1中的x值 改变 ,如下所⽰:
from collections import ChainMapmerged2 = ChainMap(dic1,dic2) print (merged2)
77 命名元组提⾼可读性 from collections import namedtuplePoint = namedtuple('Point' , ['x' , 'y' , 'z' ]) lst = [Point(1.5 , 2 , 3.0 ), Point(-0.3 , -1.0 , 2.1 ), Point(1.3 , 2.8 , -2.5 )] print (lst[0 ].y - lst[1 ].y)
使⽤命名元组写出来的代码可读性更好,尤其处理上百上千个属性时作⽤更加凸显。
78 样本抽样 使⽤ sample抽样,如下例⼦从100个样本中随机抽样10个。
from random import randint,samplelst = [randint(0 ,50 ) for _ in range (100 )] print (lst[:5 ])lst_sample = sample(lst,10 ) print (lst_sample)
79 重洗数据集 使⽤ shuffle⽤来重洗数据集,值得注意 是对lst就地(in place)洗牌,节省存储空间
from random import shufflelst = [randint(0 ,50 ) for _ in range (100 )] shuffle(lst) print (lst[:5 ])
80 10个均匀分布的坐标点 random模块中的 uniform(a,b)⽣成[a,b)内的⼀个随机数,如下⽣成10个均匀分布的⼆维坐标点
from random import uniform[(uniform(0 ,10 ),uniform(0 ,10 )) for _ in range (10 )]
81 10个⾼斯分布的坐标点 random模块中的 gauss(u,sigma)⽣成均值为u, 标准差为sigma的满⾜⾼斯分布的值,如下⽣成10个 ⼆维坐标点,样本误差(y-2*x-1)满⾜均值为0,标准差为1的⾼斯分布:
from random import gaussx = range (10 ) y = [2 *xi+1 +gauss(0 ,1 ) for xi in x] points = list (zip (x,y)) points
82 chain⾼效串联多个容器对象 chain函数串联a和b,兼顾内存效率同时写法更加优雅。
from itertools import chaina = [1 ,3 ,5 ,0 ] b = (2 ,4 ,6 ) for i in chain(a,b): print (i)
83 操作函数对象 def f (): print ("i\'m f" ) def g (): print ("i\'m g" ) [f,g][0 ]()
创建函数对象的list,根据想要调⽤的index,⽅便统⼀调⽤。
84 ⽣成逆序序列
第三个参数为负时,表⽰从第⼀个参数开始递减,终⽌到第⼆个参数(不包括此边界)
85 函数的五类参数使⽤例⼦ python五类参数:位置参数,关键字参数,默认参数,可变位置或关键字参数的使⽤。
def f (a,*b,c=10 ,**d ): print (f'a:{a} ,b:{b} ,c:{c} ,d:{d} ' )
默认参数c不能位于可变关键字d后:
调用f:
f(1 ,2 ,5 ,width=10 ,height=20 )
可变位置参数 b 实参后被解析为元组 (2,5);⽽c取得默认值10; d被解析为字典. 再次调⽤f:
a=1传⼊时a就是关键字参数,b,d都未传值,c被传⼊12,⽽⾮默认值。 注意观察参数 a , 既可以 f(1),也可以 f(a=1) 其可读性⽐第⼀种更好,建议使⽤f(a=1)。如果要强制使 ⽤ f(a=1),需要在前⾯添加⼀个星号:
def f (*,a,*b ): print (f'a:{a} ,b:{b} ' )
此时f(1)调⽤,将会报错: TypeError: f() takes 0 positional arguments but 1 was given 只能 f(a=1)才能OK. 说明前⾯的 * 发挥作⽤,它变为只能传⼊关键字参数,那么如何查看这个参数的类型呢?借助python 的 inspect模块:
from inspect import signaturefor name,val in signature(f).parameters.items(): print (name,val.kind)
可看到参数 a 的类型为 KEYWORD_ONLY,也就是仅仅为关键字参数。
但是,如果f定义为:
def f (a,*b ): print (f'a:{a} ,b:{b} ' )
查看参数类型:
for name,val in signature(f).parameters.items(): print (name,val.kind)
可以看到参数 a 既可以是位置参数也可是关键字参数
86 使⽤slice对象 ⽣成关于蛋糕的序列cake1:
cake1 = list (range (5 ,0 ,-1 )) b = cake1[1 :10 :2 ] b cake1
再⽣成⼀个序列:
from random import randintcake2 = [randint(1 ,100 ) for _ in range (100 )] d = cake2[1 :10 :2 ] d
你看,我们使⽤同⼀种切法,分别切开两个蛋糕cake1,cake2. 后来发现这种切法 极为经典 ,又拿它去切 更多的容器对象。
那么,为什么不把这种切法封装为⼀个对象呢?于是就有了slice对象。
定义slice对象极为简单,如把上⾯的切法定义成slice对象:
perfect_cake_slice_way = slice (1 ,10 ,2 ) cake1_slice = cake1[perfect_cake_slice_way] cake2_slice = cake2[perfect_cake_slice_way] cake1_slice cake2_slice
与上⾯的结果⼀致。
对于逆向序列切⽚, slice对象⼀样可⾏:
a = [1 ,3 ,5 ,7 ,9 ,0 ,3 ,5 ,7 ] a_ = a[5 :1 :-1 ] named_slice = slice (5 ,1 ,-1 ) a_slice = a[named_slice] a_ a_slice
频繁使⽤同⼀切⽚的操作可使⽤slice对象抽出来,复⽤的同时还能提⾼代码可读性。
87 lambda 函数的动画演⽰ 有些读者反映, lambda函数不太会⽤,问我能不能解释⼀下。
⽐如,下⾯求这个 lambda函数:
def max_len (*lists ): return max (*lists, key=lambda v: len (v))
有两点疑惑:
1.参数 v 的取值?
2.lambda函数有返回值吗?如果有,返回值是多少?
调⽤上⾯函数,求出以下三个最长的列表:
r = max_len([1 , 2 , 3 ], [4 , 5 , 6 , 7 ], [8 ]) print (f'更长的列表是{r} ' )
程序完整运⾏过程,动画演示如下:
结论:
1.参数v的可能取值为 *lists,也就是 tuple 的⼀个元素。
2.lambda函数返回值,等于 lambda v 冒号后表达式的返回值。
88 粘性之禅 7 ⾏代码够烧脑,不信试试~~
def product (*args, repeat=1 ): pools = [tuple (pool) for pool in args] * repeat result = [[]] for pool in pools: result = [x+[y] for x in result for y in pool] for prod in result: yield tuple (prod)
调⽤函数:
rtn = product('xyz' , '12' , repeat=3 ) print (list (rtn))
快去⼿动敲敲,看看输出啥吧~~
89 元类 xiaoming, xiaohong, xiaozhang 都是学⽣,这类群体叫做 Student.
Python 定义类的常见⽅法,使⽤关键字 class
class Student (object ): pass
xiaoming, xiaohong, xiaozhang 是类的实例,则:
xiaoming = Student() xiaohong = Student() xiaozhang = Student()
创建后,xiaoming 的 class 属性,返回的便是 Student类
问题在于, Student 类有 __class__属性,如果有,返回的又是什么?
xiaoming.__class__.__class__
哇,程序没报错,返回 type
那么,我们不妨猜测: Student 类,类型就是 type
换句话说, Student类就是⼀个对象,它的类型就是 type
所以,Python 中⼀切皆对象,类也是对象
Python 中,将描述 Student 类的类被称为:元类。
按照此逻辑延伸,描述元类的类被称为:元元类 ,开玩笑了~ 描述元类的类也被称为元类。
聪明的朋友会问了,既然 Student 类可创建实例,那么 type 类可创建实例吗? 如果能,它创建的实
例就叫:类 了。 你们真聪明!
说对了, type 类⼀定能创建实例,⽐如 Student 类了
Student = type ('Student' ,(),{}) Student
它与使⽤ class 关键字创建的 Student 类⼀模⼀样。
Python 的类,因为又是对象,所以和 xiaoming, xiaohong 对象操作相似。⽀持:
1.赋值
2.拷贝
3.添加属性
4.作为函数参数
StudentMirror = Student Student.class_property = 'class_property' hasattr (Student, 'class_property' )
元类,确实使⽤不是那么多,也许先了解这些,就能应付⼀些场合。就连 Python 界的领袖 Tim Peters 都说:
“元类就是深度的魔法,99%的⽤户应该根本不必为此操⼼。”
90 对象序列化 对象序列化,是指将内存中的对象转化为可存储或传输的过程。很多场景,直接⼀个类对象,传输不方便。
但是,当对象序列化后,就会更加⽅便,因为约定俗成的,接⼜间的调⽤或者发起的 web 请求,⼀般 使⽤ json 串传输。
实际使⽤中,⼀般对类对象序列化。先创建⼀个 Student 类型,并创建两个实例。
class Student (): def __init__ (self,**args ): self.ids = args['ids' ] self.name = args['name' ] self.address = args['address' ] xiaoming = Student(ids = 1 ,name = 'xiaoming' ,address = '北京' ) xiaohong = Student(ids = 2 ,name = 'xiaohong' ,address = '南京' )
导⼊ json 模块,调⽤ dump ⽅法,就会将列表对象 [xiaoming,xiaohong],序列化到⽂件 json.js 中。
import jsonwith open ('json.js' , 'w' ) as f: json.dump([xiaoming,xiaohong], f, default=lambda obj: obj.__dict__,ensure_ascii=False , indent=2 , sort_keys=True )