原来Python函数只是个对象
写Python越多,写函数越多,于是乎有人觉得Python是函数式语言,其实不然,Python只是从函数式语言中借鉴了一些好的想法而已。
写Python越多,写函数越多,于是乎有人觉得Python是函数式语言,其实不然,Python只是从函数式语言中借鉴了一些好的想法而已。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 集合 集合的字面量是{1}、{1, 2},和字典有点像,不同的是集合只有值没有键。 set构造方法 set构造方法如下: my_set = {1, 2, 3} my_set = set([1, 2, 3]) 前者比后者更快更易读,因为对于前者,Python会利用一个专门的叫做BUILD_SET的字节码来创建集合。而对于后者,Python必须先从set这个名字来查询构造方法,然后新建一个列表,最后再把这个列表传入到构造方法里。 {}是空字典,空集合必须用set()。 集合也有集合推导: >>> my_set = {x for x in range(1, 4)} >>> my_set {1, 2, 3} >>> type(my_set) <class 'set'> 集合还有个不可变类型叫做frozenset,如同元组之于列表,它的构造函数如下: >>> frozenset(range(10)) frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 只有这一种方法,没有字面量。 集合的操作 集合的本质是许多唯一对象的聚集,它最常见的操作是用来去重: >>> my_list = [1, 2, 2, 3] >>> set(my_list) {1, 2, 3} >>> list(set(my_list)) [1, 2, 3] 除此之外,集合还能进行数学运算,比如求交集、并集、差集等。示例,求needles的元素在haystack里出现的次数,暴力解法: found = 0 for n in needles: if n in haystack: found += 1 集合解法: found = len(needles & haystack) 即使不是set也能先转换为set: found = len(set(needles) & set(haystack)) ## 另一种写法 found = len(set(needles).intersection(haystack)) 集合支持的操作如下: 散列表揭秘 这一部分的内容略微有点硬,请注意提前喝点水! 从上篇的简介可以知道,散列表就是一张表,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录。散列表其实是一个稀疏数组(总是有空白元素的数组称为稀疏数组),散列表里的单元叫作表元,在dict的散列表中,每个键值对占用一个表元,每个表元有两个部分,一个是对键的引用,另一个是对值的引用,因为所有表元的大小一致,所以可以通过偏移量来读取某个表元。 为什么要用稀疏数组?举个例子,身份证号411697199702076425,如果把它作为键存储到数组中,虽然能用O(1)时间就找到,但是需要开辟一个999999999999999999大的空间。假如只有1的空间,就只能把最后一位作为键存储到数组中,多个身份证号的键就容易冲突,得多看n位才能找到,要用O(n)时间。空间既不能太大,也不能太小,需要结合时间,在两者之间产生一个平衡,即空间和时间的平衡,所以要用稀疏数组! Python会设法保证大概还有三分之一的表元是空的,用空间换时间,提高散列表查询效率。如果剩余空间不足,原有的散列表会被复制到一个更大的空间里面。 散列表的键值,又称为散列值,Python中可以用hash()方法来计算所有内置类型对象的散列值。 自定义类型实际上调用的是自定义的__hash__。 如果两个对象在比较的时候是相等的,那么它们的散列值必须相等,否则散列表就不能正常运行了: >>> a = 1 >>> b = 1 >>> a == b True >>> hash(a) 1 >>> hash(b) 1 >>> a = "x" >>> b = "x" >>> a == b True >>> hash(a) 706802421 >>> hash(b) 706802421 越是相似但不相等的对象,它们的散列值的差别越大: ...
“字典这个数据结构活跃在所有Python程序的背后,即便你的源码里并没有直接用到它”,摘抄自《代码之美》第18章Python的字典类:如何打造全能战士。字典是Python语言的基石!在函数的关键字参数、实例的属性和模块的命名空间都能够看到它的身影,我们自己写代码时也经常会用到。
序列赋值是Python默认操作,如果使用不当,有可能会掉入语法陷阱。
在DRF官方教程的学习过程中,一个很明显的感受是框架在不断地进行封装,我们自己写框架/工具/脚本/平台也可以模仿模仿,先完成底层代码,再做多层封装,让使用者很容易就上手操作。本文是教程的最后一篇,介绍ViewSets和Routers。
切片,就像面包,给几刀,切成一片一片,可以做成吐司,也可以做成三明治,口味更佳:
很多API并不是真正的实现了RESTful,而应该叫做RPC (Remote Procedure Call 远程过程调用),Roy Fielding曾经提到了它们的区别,原文如下:
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 元组拆包 元组是不可变列表,列表是通过索引取值的,元组也是: tuple_test = (1, 2, 3) a = tuple_test[0] b = tuple_test[1] c = tuple_test[2] 但Python是出了名的一行代码解决问题,元组拆包就是精髓技术之一: a, b, c = tuple_test print("%s %s %s" % tuple_test) 把元组一一对应拆出来,就叫做元组拆包。拆包有个要求,元组中的元素数量必须跟接受这些元素的空挡数一致,否则会报错: tuple_test = (1, 2, 3) a, b = tuple_test # ValueError: too many values to unpack (expected 2) _占位符 使用_占位符可以解决这个问题: tuple_test = (1, 2, 3) a, b, _ = tuple_test 这样就只获取到部分数据了,这在取函数返回值时特别有用,比如: import os _, filename = os.path.split("/home/dongfanger/.ssh/idrsa.pub") print(filename) # "idrsa.pub" *前缀 当返回值特别多时,_占位符写起来麻烦,可以用*来处理剩下的元素: >>> a, b, *rest = range(5) >>> a, b, *rest (0, 1, [2, 3, 4]) 注意rest是个列表,如果没有足够元素,会返回空列表: >>> a, b, *rest = range(2) >>> a, b, *rest (0, 1, []) *前缀变量能放在任意位置,比如,放在中间: >>> a, *body, c, d = range(5) >>> a, body, c, d (0, [1, 2], 3, 4) 放在前面: ...
Django可以用LoginRequiredMixin和PermissionRequiredMixin给类视图添加认证和权限,DRF做了高级封装,提供了更简洁的实现方式。我们通过继续学习官网教程来进行了解。
本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 数据模型==对象模型 Python官方文档说法是“Python数据模型”,大多数Python书籍作者说法是“Python对象模型”,它们是一个意思,表示“计算机编程语言中对象的属性”。这句话有点抽象,只要知道对象是Python对数据的抽象,在Python中万物皆对象就可以了。 官方文档严谨说法,Python程序中的所有数据都是用对象或对象之间的关系来表示的。 对象三要素 对象有三个要素:编号(identity)、类型(type)、值(value)。 identity 编号就是对象的内存地址,从创建后就不会改变。is运算符用来比较2个对象的编号。id()函数返回对象编号的整数表示。 identity也可以翻译为身份,对象身份。 type 类型决定了可以对对象做哪些操作,也定义了对象的可能值,比如int和bool类型的值就不一样。type()函数返回对象类型。很多人会误以为Python是弱类型语言,其实Python是强类型语言,这个误解的真实原因是,Python不需要编译,不需要提前知道变量的类型,在运行时才检查类型,这应该叫做动态语言。 JavaScript是弱类型语言,在Python中1+"2"会运行失败,在JavaScript中能运行成功。 类型在创建后也不会改变,虽然可以进行类型转换,但转换实际会产生新对象: a = 1 print(id(a)) print(id(str(a))) print(id(a)) 结果为: 140715000207008 2136059506160 140715000207008 value 对象三要素中唯一能改变的就只有值了。官网有一句正确的废话:允许改变值的对象是mutable(可变的),不允许改变值的对象是immutable(不可变的)。它的意义在于当不可变对象的值是对可变对象的引用时,该如何判断对象的可变性?结论是不可变对象仍然是不可变的,因为这个引用是不能变的,但是我们通常会认为这个不可变对象的值是可变的,尤其是对象容器。对象类型也会决定是否可变,比如numbers、strings、tuples是不可变的,dictionaries、lists是可变的。 对象容器 有些对象包含了对其他对象的引用,这叫做containers对象容器,比如tuples、lists、dictionaries。大多数情况下,我们说容器的值,说的是引用的对象的值,而不是引用编号。但讨论容器可变性时,则仅仅是指容器直接包含的引用编号。比如tuple是不可变的,如果它包含了对一个可变对象的引用后,当该可变对象改变时容器的值也会改变。 对象回收 对象不会被显式销毁,但是它们会被当做垃圾回收,只要不存在对象引用,这就是Python垃圾回收机制!垃圾回收机制比较复杂,比如循环引用,实际上已经没有使用了,但是还存在引用等,涉及到算法规则,等写完Python进阶,在写Python原理时做进一步研究。 Python垃圾回收机制不是银弹,不能解决所有问题,所以在引用外部资源,比如打开文件后,我们需要注意显式close,防止资源始终占用内存,无法释放,造成内存泄漏。close除了手动调用close()方法外,也可以使用with来自动close。 使用try...except可能会让对象继续存活。 类型决定一切 对象的类型几乎决定了对象的一切行为,甚至是对象编号,比如对于不可变类型: a = 1 b = 1 a和b可能会指向同一个值为1的对象,也可能会指向两个不同的值为1的对象,这取决于具体实现。 但是对于可变类型: c = [] d = [] c和d一定会指向两个不同的单独的空列表。 注意c = d = [] 则是将同一个对象赋值给 c 和 d。 小结 Python数据模型就是常说的对象模型,万物皆对象,有编号、类型、值三个要素。了解了对象模型后,Python另一个重要概念即将浮出水面,它就是数据结构。 参考资料: 《流畅的Python》 https://docs.python.org/3/reference/datamodel.html