COMP9021 Principles of Programming WEEK5

1. nbtutor module

nbtutor用来演示python指令的执行过程,但一些local, nonlocal,
global的variable的演示有小错误,大体上可以参考。python安装说明
(1)PIP安装

pip install nbtutor
jupyter nbextension install --overwrite --py nbtutor
jupyter nbextension enable --py nbtutor

(2)conda安装

conda install -c conda-forge nbtutor

(3)Jupyter Notebook使用

load_ext nbtutor
%%nbtutor
代码

注意:load_ext nbtutor要先执行,和import不一样;另外,安装好后要重启jupyter notebook

2. local, nonlocal, global variable

%%nbtutor
a = 0
m = 0
n = 0
x = 0
#以上都是global variable,且assign的过程和之前文章内容一样,python并不重新创建多个内存表示相同的内容(这里是0),而是把v_name指向v_storage。
#所以上述4条命令其实只有一个v_storage 0,而有4个v_name

print('PRINT 0:  a =', a,
      ' m =', m, ' n =', n,
      '        x =', x)
#输出全局变量的值
#>>> PRINT 0:  a = 0  m = 0  n = 0         x = 0

def f_1():
#python中所有内容都认为是一个object,f_1是一个object
    m = 1
    global n
    n = 1
    x = 1
    y = 1
    z = 1
    #以上variable,除了n以外,都是f_1的local variable,随着f_1的存在而存在,一旦f_1不存在,这些assign也都没有意义。
    #variable n声明了global,所以不属于f_1
    print('PRINT 1:  a =', a,
          ' m =', m, ' n =', n,
          '        x =', x, ' y =', y, ' z =', z)
    #输出4个f_1局部变量和2个全局变量a, n的值,编译逻辑是先找v_name在local的名称,如果没有则找global的v_name
    #>>> PRINT 1:  a = 0  m = 1  n = 1         x = 1  y = 1  z = 1

    def f_2():
        global m
        m = 2
        # Cannot write:
        # nonlocal n
        #因为nonlocal是去该object上一层object中查找,如果上一层没有找到则再去上一层查找,但是不能出现在global中,f_1中没有n,只有global中有n,所以不能用nonlocal
        global n
        n = 2
        global p
        #如果定义一个global不存在的variable,则新创建一个,但最好不要这么写,复杂程序很难看清楚
        p = 2
        x = 2
        nonlocal y
        y = 2
        # Cannot write:
        # nonlocal u
        #因为上一层不存在variable u
        print('PRINT 2:  a =', a,
              ' m =', m, ' n =', n, ' p =', p,
              ' x =', x, ' y =', y, ' z =', z)
        #输出全局变量a,m,n,p,f_1变量y,z,f_2变量x
        #>>> PRINT 2:  a = 0  m = 2  n = 2  p = 2  x = 2  y = 2  z = 1

        def f_3():
            nonlocal x
            x = 3
            #使f_2的x指向3,而不是f_1的x,虽然变量名相同,但是不一样
            nonlocal y
            y = 3
            #使f_2的y指向3,因为f_2的y是nonlocal,同时指向f_1的y,所以f_1的y和f_2的y都指向3
            nonlocal z
            z = 3
            #首先去f_2找z,但是没有找到,再向上去f_1找z,这时把f_1的z指向3
            print('PRINT 3:  a =', a,
                  ' m =', m, ' n =', n, ' p =', p,
                  ' x =', x, ' y =', y, ' z =', z)
            #输出global的a, m, n, p,f_2的x,y,z
            #>>> PRINT 3:  a = 0  m = 2  n = 2  p = 2  x = 3  y = 3  z = 3

        f_3()
        print('PRINT 4:  a =', a,
              ' m =', m, ' n =', n, ' p =', p,
              ' x =', x, ' y =', y, ' z =', z)
        #这层属于f_2,所以输出global的a, m, n, p,f_2的x, y, z
        #>>> PRINT 4:  a = 0  m = 2  n = 2  p = 2  x = 3  y = 3  z = 3

    f_2()
    print('PRINT 5:  a =', a,
          ' m =', m, ' n =', n, ' p =', p,
          ' x =', x, ' y =', y, ' z =', z)
    #这层属于f_1,所以输出global的a, n, p,f_1的m, x, y, z
    #>>> PRINT 5:  a = 0  m = 1  n = 2  p = 2  x = 1  y = 3  z = 3

f_1()
print('PRINT 6:  a =', a,
      ' m =', m, ' n =', n, ' p =', p,
      ' x =', x)
#global层,输出global的a,m,n,p,x,这层没有定义y,z
#PRINT 6:  a = 0  m = 2  n = 2  p = 2  x = 0

local是在当前object level;
nonlocal是向上找object level但是不能无限向上到global level;
global level是最外层

"The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.

Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).

Names listed in a nonlocal statement must not collide with pre- existing bindings in the local scope"(https://stackoverflow.com/questions/33211272/what-is-the-difference-between-non-local-variable-and-global-variable)

3. file operation

3.1 create directory

import os
import sys

original_directory = 'names'
#已经创建好的当前路径下的一个路径名
new_directory = original_directory + '_classified'
#准备一个新的在当前路径下的路径名,等于原路径名加上"_classified"

if os.path.isdir(new_directory):
#os.path.isdir(directoryname)用来判断directoryname是否在当前路径
    print(f'{new_directory} already exists, leaving it there.')
    sys.exit()
os.mkdir(new_directory)
#在当前路径下创建新的路径
male_directory = new_directory + '/males'
female_directory = new_directory + '/females'
os.mkdir(male_directory)
os.mkdir(female_directory)

import os,使用其中的常见函数:
os.path.isfile(path)
Return True if path is an existing regular file. 注意这个函数是用来判断是不是file的;
os.path.isdir(path)
Return True if path is an existing directory.注意这个函数是用来判断是不是directory的;

3.2 file operation

for filename in os.listdir(original_directory):
#在准备好的路径下逐一读取file
    if not filename.endswith('.txt'):
        continue
    #筛选所有.txt类型file
    with open(original_directory + '/' + filename) as names,\
                   open(male_directory + '/' + filename, 'w') as male_names,\
                            open(female_directory + '/' + filename, 'w') as female_names:
    #同时打开3个文档,1个是准备好的路径下的文件,另2个是在male和female路径下创建的相同文件名的文件,3个文件都赋予了v-name
        for line in names:
            name, gender, count = line.split(',')
            #读取准备好的文件中的数据,并把每一行的数据按照commma分隔形成一个list,再分别assign给3个variable
            if gender == 'F':
                print(name, ',', count, file = female_names, sep = '', end = '')
            else:
                print(name, ',', count, file = male_names, sep = '', end = '')
            #按照性别分别输出到新创建的文件中,删除性别的信息

3.3 information retrieval

(1)review dict和defaultdict的区别

D = {}
D['paul'] = [1887]
D['paul'].append(1896)
D
>>>
{'paul': [1887, 1896]}
from collections import defaultdict
D = defaultdict(list)
D['paul'].append(1887)
D['paul'].append(1896)
D
>>>
defaultdict(list, {'paul': [1887, 1896]})

看起来上述dict和defaultdict的操作实现了同样的功能,但是defaultdict能够实现不存在的key的添加,如下

D = {}
D['paul'].append(1887)
D['paul'].append(1896)
D

如果使用dict,'paul'不属于D的key,则无法append,但是defaultdict可以。可以简单将defaultdict理解成创建了空key,value为实现定义类型的dict。例如,D = defaultdict(list),创建了一个key为空,value为空list的一个dict。

(2)找寻一个名字出现在记录中的所有年份

import os
import sys
from collections import defaultdict

original_directory = 'names'

years_by_name = defaultdict(list)
#assign years_by_name类型是defaultdict,这个dict中的value都是list
for filename in os.listdir(original_directory):
    if not filename.endswith('.txt'):
        continue
    with open(original_directory + '/' + filename) as names:
        year = int(filename[3: 7])
        #命名[3:7]是因为所有文件名都是“yob1880.txt”这样的格式
        for line in names:
            name, gender, count = line.split(',')
            if gender == 'M':
                break
            years_by_name[name].append(year)
print(years_by_name['Helen'])

(3)找寻一个名字在记录中gap最大的记录

import os
import sys
from collections import defaultdict

original_directory = 'names'

years_by_name = defaultdict(list)
for filename in os.listdir(original_directory):
    if not filename.endswith('.txt'):
        continue
    with open(original_directory + '/' + filename) as names:
        year = int(filename[3: 7])
        for line in names:
            name, gender, count = line.split(',')
            if gender == 'M':
                break
            years_by_name[name].append(year)
            #到这里创建了所有名字对应出现年份的dictionary,key是名字,value是一个包含所有年份的list,可以使用下面的print()来输出检查
            #print(years_by_name['Helen'])
            #因为原始数据中是按照年份大小排列的,所以输出的value中的list也是按照年份大小从小到大排列的

data = [(years_by_name[name][i + 1] - years_by_name[name][i], years_by_name[name][i], name)
        for name in years_by_name
        for i in range(len(years_by_name[name]) - 1) 
       ]
#list生成方法中使用了循环的嵌套,先循环years_by_name中的所有item,找到一个item后再循环key[value]中的所有list成员,这里注意因为要算gap,所以循环到length - 1,否则最后1个无法做gap计算。
#两层循环嵌套后,根据找到的当前成员的年龄算前后两个的gap
#最终形成所有任意连续两个record之间的gap数据的一个list,list中每一个成员都是一个tuple,包含gap, year, name三个信息,命名为data

for (gap, year, name) in sorted(data, reverse = True)[: 10]:
    print(f'{name} was not given for {gap} may years, the last time '
          f'between {year} and {year + gap}')
#按照gap从大到小排列data,输出10个最大的gap
>>>
Levy was not given for 119 may years, the last time between 1887 and 2006
Izzie was not given for 115 may years, the last time between 1891 and 2006
Izma was not given for 108 may years, the last time between 1899 and 2007
Leannah was not given for 107 may years, the last time between 1889 and 1996
Auguste was not given for 106 may years, the last time between 1892 and 1998
Saidee was not given for 102 may years, the last time between 1893 and 1995
Caledonia was not given for 101 may years, the last time between 1900 and 2001
Enora was not given for 100 may years, the last time between 1910 and 2010
Sella was not given for 97 may years, the last time between 1916 and 2013
Nolah was not given for 97 may years, the last time between 1907 and 2004

4. Vigenère cipher

维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。
课上代码在lecture4的文件夹下面,有很多值得学习的写法。
理解参考:
https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
https://zh.wikipedia.org/wiki/%E7%BB%B4%E5%90%89%E5%B0%BC%E4%BA%9A%E5%AF%86%E7%A0%81

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,397评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,585评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,521评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,645评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,489评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,366评论 1 274
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,787评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,432评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,732评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,775评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,550评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,393评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,802评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,036评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,324评论 1 253
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,757评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,958评论 2 336

推荐阅读更多精彩内容