>>>t=(1, 2, [30 ,40])
>>>t[2] += [50, 60]到底会发生下面4种情况中的那一种
a. t变成(1, 2, [30, 40, 50 ,60])
b. 因为tuple不支持对它的元素赋值, 所以会抛出TypeError异常
c. 以上俩个都不对
d. a和b都是对的
答案是d. a和b都是对的。
tPython 2.7.17 (default, Nov 7 2019, 10:07:09)
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> t = (1, 2, [30, 40])
>>> t[2] +=[50, 60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])由此可知
- 增量赋值不是一个原子操作。
- 不要把可变对象放到元组里面。
- 如果只需要一个只包含数字的列表,那么array.array比list更高效。
- python 里面所有的不可变类型都是可散列的, 这个说法是不准确的,比如虽然元组本身是不可散列的,但是他里面的元素可能是其他可变类型。
- 散列值就是他们id()返回的值。
- 字典在内存上的开销特别大。
- 字典使用的是散列表,而散列表又必须是稀疏的,这导致在空间上的效率低下。
- 用元组取代字典就能节约空间的原因有俩个:其一是避免了散列表所耗费的空间,其二是无需把记录中字段的名字在每个元素李都存一遍。
- 字典是实现是典型的空间换取时间:字典类型有着巨大的内存开销,但是他们无视数据量的大小的快速访问---只要字典能被装载到内存中。
>>> str1 = "swift"
>>> str1[0]==str1[:1]
True
>>> list1 = [1,2,3,4]
>>> list1[1]==list1[:1]
False- 需要在多台设备中或多种场合下运行的代码,一定不能依赖默认编码。打开文件时始终应该明确传入encoding=参数,因为不同的设备使用的默认编码可能不同,有时隔一天也会发生变化。
- 如果使用字节序列构建正则表达式,\d和\w等模式只能匹配ASCII字符;相比之下,如果是字符串模式,就能匹配ASCII之外的Unicode数字或字母。
- 所有的函数都是对象
>>> def factorial(n):
... '''return n!'''
... return 1 if n<2 else n*factorial(n-1)
...
>>> factorial(23)
25852016738884976640000
>>> factorial.__doc__
'return n!'
>>> type(factorial)
<class 'function'>
>>> fact = factorial
>>> fact
<function factorial at 0x7f9267333c80>
>>> factorial
<function factorial at 0x7f9267333c80>
>>> fact(5)
120
>>> map(factorial, range(11))
<map object at 0x7f9266c961d0>
>>> list(map(fact, range(11)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]-
别的名称使用函数,再把函数作为参数传递
-
python 也可叫做函数式编程风格
-
接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higher-order function)。map函数就是一例
-
在函数式编程范式中,最为人熟知的高阶函数有map、filter、reduce和apply。apply函数在Python 2.3中标记为过时,在Python 3中移除了,因为不再需要它了。如果想使用不定量的参数调用函数,可以编写fn(*args, **keywords),不用再编写apply(fn, args, kwargs)。
-
函数式语言通常会提供map、filter和reduce三个高阶函数(有时使用不同的名称)。在Python3中,map和filter还是内置函数,但是由于引入了列表推导和生成器表达式,它们变得没那么重要了。列表推导或生成器表达式具有map和filter两个函数的功能,而且更易于阅读。
>>> list(map(fact, range(6)))
[1, 1, 2, 6, 24, 120]
>>> [fact(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> list(map(fact, filter(lambda n: n%2, range(6))))
[1, 6, 120]
>>> [fact(n) for n in range(6) if n%2]
[1, 6, 120]- 在Python 3中,map和filter返回生成器(一种迭代器),因此现在它们的直接替代品是生成器表达式(在Python 2中,这两个函数返回列表,因此最接近的替代品是列表推导)。
- 在Python 2中,reduce是内置函数,但是在Python 3中放到functools模块里了。这个函数最常用于求和,自2003年发布的Python 2.3开始,最好使用内置的sum函数。在可读性和性能方面,这是一项重大改善。
- lambda关键字在Python表达式内创建匿名函数。
- Python简单的句法限制了lambda函数的定义体只能使用纯表达式。换句话说,lambda函数的定义体中不能赋值,也不能使用while和try等Python语句。
- 在参数列表中最适合使用匿名函数。
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'reaspberry', 'banana']
>>> sorted(fruits, key=lambda word: word[::-1])
['banana', 'apple', 'fig', 'reaspberry', 'strawberry', 'cherry']-
除了作为参数传给高阶函数之外,Python很少使用匿名函数。由于句法上的限制,非平凡的lambda表达式要么难以阅读,要么无法写出。
Lundh提出的lambda表达式重构秘笈如果使用lambda表达式导致一段代码难以理解,Fredrik Lundh建议像下面这样重构。
(1)编写注释,说明lambda表达式的作用。
(2)研究一会儿注释,并找出一个名称来概括注释。
(3)把lambda表达式转换成def语句,使用那个名称来定义函数。
(4)删除注释。
除了用户定义的函数,调用运算符(即( ))还可以应用到其他对象上。如果想判断对象能否调用,可以使用内置的callable( )函数。Python数据模型文档列出了7种可调用对象。
用户定义的函数
使用def语句或lambda表达式创建。
内置函数
使用C语言(CPython)实现的函数,如len或time.strftime。
内置方法
使用C语言实现的方法,如dict.get。
方法
在类的定义体中定义的函数。
类
调用类时会运行类的__new__方法创建一个实例,然后运行__init__方法,初始化实例,最后把实例返回给调用方。因为Python没有new运算符,所以调用类相当于调用函数。(通常,调用类会创建那个类的实例,不过覆盖__new__方法的话,也可能出现其他行为。)
类的实例
如果类定义了__call__方法,那么它的实例可以作为函数调用。
生成器函数
使用yield关键字的函数或方法。调用生成器函数返回的是生成器对象。
>>> abs, str ,13
(<built-in function abs>, <class 'str'>, 13)
>>> [callable(obj) for obj in (abs, str, 13)]
[True, True, False]import random
class BingoCage:
def __init__(self, items):
self.__items = list(items)
random.shuffle(self.__items) # 随机排序
def pick(self):
try:
return self.__items.pop()
except IndexError:
raise LookupError("pick empty BingoCage")
def __call__(self, *args, **kwargs):
return self.pick()>>> from bingocall import BingoCage
>>> bingo = BingoCage(range(5))
>>> bingo.pick()
3
>>> bingo()
1
>>> callable(bingo)
True实现__call__方法的类是创建函数类对象的简便方式,此时必须在内部维护一个状态,让它在调用之间可用,例如BingoCage中的剩余元素。装饰器就是这样。装饰器必须是函数,而且有时要在多次调用之间“记住”某些事[例如备忘(memoization),即缓存消耗大的计算结果,供后面使用]。
def tag(name, *content, cls=None, **attrs):
"""生成一个或多个HTML标签"""
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
else:
attr_str = ""
if content:
return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)>>> from tag import tag
>>> tag('br')
'<br />'
>>> tag('p', 'hello')
'<p>hello</p>'
>>> tag('p', 'hello', 'world')
'<p>hello</p>\n<p>world</p>'
>>> print(tag('p', 'hello', 'world'))
<p>hello</p>
<p>world</p>
>>> tag('p', 'hello', id=33)
'<p id="33">hello</p>'
>>> print(tag('p', 'hello', 'world', cls='sidebar'))
<p class="sidebar">hello</p>
<p class="sidebar">world</p>
>>> tag(content='testing', name="img")
'<img content="testing" />'
>>> my_tag = {'name':'img', 'title': 'Sunset Bulevard', 'src': 'sunset.jpg', 'cls': 'framed'}
>>> tag(**my_tag)
'<img class="framed" src="sunset.jpg" title="Sunset Bulevard" />'❶ 传入单个定位参数,生成一个指定名称的空标签。
❷ 第一个参数后面的任意个参数会被*content捕获,存入一个元组。
❸ tag函数签名中没有明确指定名称的关键字参数会被attrs捕获,存入一个字典。
❹ cls参数只能作为关键字参数传入。
❺ 调用tag函数时,即便第一个定位参数也能作为关键字参数传入。
❻ 在my_tag前面加上,字典中的所有元素作为单个参数传入,同名键会绑定到对应的具名参数上,余下的则被**attrs捕获。