- 全局变量就是在函数体外声明的变量
- 函数体内声明的变量是局部变量.

- 可以直接访问全局变量
- 但是不能直接赋值,直接赋值的时候,编译器会认为是重新创建了一个局部变量,只是这个局部变量和全局变量重名,然后会把全局的变量覆盖掉.

- 需要借助
global关键字声明global声明会告诉编译器,这个变量是全局变量,然后在使用和编译的时候就会当成全局变量来使用.

方法1: 第一反应是pop

从上面的示例可以看出来,字典的pop(key)确实可以删除字典的键,但是有两个要求
pop(key)函数没有默认参数,必须提供一个参数键.pop(key)参数key必须是字典中存在的键,否则就会报错
解法2: 第二反应是remove,不确定remove可不可以,尝试一下.

尝试失败,字典中没有remove方法,然后使用dir(dict)看看字典的一些属性方法:如下

注意看这里有一个
popitem方法,这个方法和pop有什么区别呢? 我们看看官方的解释怎么说?

翻译一下:
大概的意思就是移除掉确定的key(参数传递进来的),并且返回它对应的value.如果key不存在,如果提供了默认值,就返回默认值,如果没有提供,就报KeyError

可以看出来 popitem()是没有参数要求的,它是移除掉一个键值对,并且返回,但是具体移除哪个键值队不能明确.如果字典为空,就报KeyError

第三反应: del

del dct[key] 的方式也可以删除字典的键,在key不存在的时候也报错.返回值是None
方法1: 记忆中有个update方法用来合并字典的,但是具体的应用不是很清晰了.我们看下文档怎么说?

[E,]**F -> None. 这是个啥? 不要急,遇到这种事情,我也感觉很烦躁,为啥别人写的文档,我们看不懂.先慢慢看.
[E,] 这种带中括号[]的都表示这个参数是可选参数,可以提供,也可以不提供,就是这个函数的定义中有默认的参数了.
**F 表示 它接收数量可变的关键字参数作为F.
如果E提供了并且有一个keys()方法, 然后就遍历它,赋值给D
如果E提供了但是没有keys()方法,然后就遍历k,v,进行赋值
无论是哪种情况,都会执行 for k in F: D[k] = F[k]
先看看只有E的情况以及E和F同时存在的情况:

再看看只有F的情况:

方法3: 构造函数 dict(d1,**d2)

显而易见,这种方式有一个局限,那就是第二个字典必须是字符串作为键才行.
方法4: 字典推导式

注意: 这个字典推导式是双层的嵌套的,因为要先遍历两个字典,然后每个字典分别使用推导式来进行赋值推导.
方法5: 元素拼接,通过列表拼接,然后转换为字典

方法6: 字典拆分法,通过大括号{},可以直接组成新字典
newDict = {**d1,**d2,**d3,...}

__init__和__new__的区别?区别主要从两个方面来说:
功能上来讲:
__init__主要是用来初始化对象,它调用的前提是必需__new__返回了当前的对象的时候,__init__才会被调用.__new__对象构造的时候,通过__new__来创建一个当前对象的实例.
调用的时机和条件:
__new__一般是不需要定义的,它由编译器自动创建,在创建对象的时候,先调用__new__.__init__一般需要自己定义,用来指定自己的个性化初始化,在创建对象的时候,先调用__new__,正常来讲这个__new__会返回一个当前对象的实例,如果返回了当前对象的实例会自动调用__init__方法,如果没有则__init__方法不会被调用
参数和返回值:
__new__()至少要有一个cls参数,代表当前的类,此参数在实例化的时候由Python解释器自动识别.一般是要返回当前的实例.__init__()至少要有一个参数self,这个self其实就是__new__返回的实例.一般是返回None
看下如果__new__没有返回当前实例的情况,还有就是__new__这个参数cls到底是个什么东西?

可以看到 __new__()当中的这个cls其实就时Person类,但是上面我们返回的不是Person的实例对象,所以__init__根本就没有调用.

可以看到如果使用Person类去实例化对象,__init__就会被调用. 这里直接用object.__new__(Person) 其实和 super().__new__(cls)是等价的.
打开文件不用with的写法:

注意: 这里a.txt不能存在就报了异常.所以我们加入了try catch,又因为最后无论如何都要关闭文件流,我们再加一个finally.

从上面的示例中可以看到with语句做了什么事情.
1) 抛出异常.2) 关闭文件流.with语句的实现原理:
with语句的实现是通过上下文管理器来实现的,不是所有的方法都可以实现with语句,只有那种实现了上下文管理协议的才能使用with语句.
上下文管理器协议
__enter__(self)方法,with语句开始运行的时候,会在上下文管理器上调用__enter__方法,这个函数一般返回一个对象,一般是自身,此函数的返回值分配给变量following as后面的那个变量上面.__with__语句运行结束的时候,会在上下文管理对象上调用__exit__(self,exc_type,exc_value,traceback)方法,以此扮演finally子句的角色.我们看看这三个参数到底是个什么玩意exc_type,exc_val, exc_tb
写一个上下文管理器,然后看看怎么运行的.

本质上,如果从块内的任何地方抛出了异常,则将__exit__()调用该对象的函数.如您所见,与引发的异常关联的类型,值和堆栈跟踪将传递给此函数.在这种情况下,您可以看到ZeroDivisionError抛出异常.实现库的人员可以在其__exit__()功能中编写清理资源,关闭文件等代码.
我的第一反应map是一个映射函数,前面是一个可迭代的序列,后面是对应的映射方法,应该是长这个样子的
map(iterable,somefunction)
下面测试下:

这里明显不对,说函数是不可以迭代的. 难道是我记反了,前面是映射方法,后面是可迭代对象,我再试试.

果然,是记错了.前面是映射的方法,后面才是可迭代对象,所以我在做这个题的时候,就引申出来一个思考,为啥不能前面是可迭代对象,后面是映射方法呢?
答案是很简单的,因为可迭代对象可能有多个,但是映射方法只能有1个,看下下面的用两个可迭代对象进行映射的例子:

如果多个可迭代对象的个数不一样呢,只要有一个迭代结束,映射就结束.

然后研究到这里的时候,其实我还是很好奇,如果可迭代对象的个数,大于映射的参数的个数的时候,会发生什么?

可以看到报错了,同理,如果参数太少,也是会报错.
所以知道了map的用法,上面的答案就容易搞定了,就是直接用带条件的列表推导式再求一层就能解决.

我首先想到的是这个,生成随机的整数.具体对不对,我们去看看,测试下.

好了,现在我们查看一下这个函数的说明:

翻译君给大家翻译一下:
就是返回一个[a,b]之间的一个整数,包含a和b. 如果验证,包含a和b呢

我印象中生成小数的有一个这样的函数,到底有没有,还是要去验证一下.

果然有,这个函数返回的是[0,1)的一个浮点数,注意这类不包括1,但是包括0.

我记得好像有这个函数,但是记得不太清楚了,去验证一下:

事实证明,是没有的,具体有什么函数呢? 我们使用dir(random)看下

这里面有很多的函数,我们先看看哪个比较像我们找的.我们先看看randrange()是个什么东西?

翻译君翻译一下:
得到一个随机整数,从range(start,stop[,step])范围内,这个解决了randint()中包含最后那个点的问题.有些时候,可能不需要最后那个点被随机到,就可以使用这种方法.

这个虽然也是求随机数,但是明显不是我们要找的那个求随机小数的方法,我们继续看下一个.
sample()像不像?这里我真的没什么印象,就直接看文档吧.

啊,好长,突然就像放弃了,但是既然遇到了,就研究下这个东西是个啥吧?
翻译君翻译中.......
简单的解释就是从 population这个序列或者是集合当中选择k个唯一的随机元素.
返回一个新的列表包含从population中选取的元素,并且维持population中的元素不变.
结果列表按照顺序排列,所以所有的子片都是有效的随机样本.
这允许抽奖获胜者(本样本)可以进行分区,分成一等奖和二等奖(子列)
样本集合中的数据不必是可哈希或者是唯一的,如果样本中包含重复的元素,那么重复的元素的每一个都可能是样本的选择.这个不确定的.
要在整数范围内选择一个样本,请使用range()作为参数.对于从a总采样,这是特别快速和节省空间的.

搞到了这里之后,其实我对于那个一等奖和二等奖还不是很理解,我想大概意思就是它的子序列依旧可以当成一个完整的随机序列的意思.
然后去看看那个 uniform()函数,这个是在查资料的时候发现的,这个就是生成范围内随机小数的.
看看官方文档怎么说?

根据四舍五入的情况获取[a,b]或者[a,b)的随机数,也可能是随机小数.