From 77858a21a479ce9043f7425f9a4cbf5eb87c1015 Mon Sep 17 00:00:00 2001 From: Hui Lan Date: Sun, 14 Apr 2019 20:56:43 +0800 Subject: =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E4=BB=B6=E4=B8=80=E7=AB=A0?= =?UTF-8?q?=EF=BC=8C=E4=B8=BB=E8=A6=81=E6=98=AF=E5=AE=9E=E9=AA=8C=E7=AD=94?= =?UTF-8?q?=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LectureNotesOnPython.html | 261 +++++++++++++++++++++++++++++++--------------- LectureNotesOnPython.rst | 106 ++++++++++++++++++- 2 files changed, 283 insertions(+), 84 deletions(-) diff --git a/LectureNotesOnPython.html b/LectureNotesOnPython.html index f56596b..600059c 100644 --- a/LectureNotesOnPython.html +++ b/LectureNotesOnPython.html @@ -376,58 +376,59 @@ ul.auto-toc {

内容目录

-

前言

+

前言

非学究写书,无空洞行文。

Python语法简洁,库函数全面强大,编程速度快,运行速度也不慢。

大学里, 往往是专家教初学者。 专家也是从初学者过来的,只不过专家经常忘 @@ -449,12 +450,12 @@ ul.auto-toc { 初学者说“我明白了”。

-

Python的发音纠正

+

Python的发音纠正

国人普遍把th发作s。 Not quite correct。

ˈpī-ˌthän , -thən pronounciation

-

Python源流

+

Python源流

Python之父Guido van Rossum,荷兰人,1956年生,1982年阿姆斯特丹大学获得 数学与计算机科学硕士学位。有过ABC语言的工作经验。1989年设计了Python语 言。

@@ -504,7 +505,7 @@ ul.auto-toc {
-

Python的关键词

+

Python的关键词

def pass
from import
@@ -526,7 +527,7 @@ ul.auto-toc {

关键词被语言留用(reserved),无法作变量名。

-

值的类型

+

值的类型

所有的值都是对象。a = 5, help(a) a.bit_length()

数字。1, 1.,1.1, .1, 1e1, 1e-1, 1E1, 1E-1

@@ -546,7 +547,7 @@ A list of objects

元组(tuple),字典(dict)。

-

变量(Variable)

+

变量(Variable)

是一个名字(name),是指向一个值(value)的名字。

值存放在内存(memory)中的某个地址。

尽量选有意义的简短的名字。比如,代表个数用n,代表索引用i,j,k。

@@ -635,7 +636,7 @@ A list of objects
-

可变(mutable)类型与不可变类型

+

可变(mutable)类型与不可变类型

字符串是不可变的(immutable)类型,不能在原内存地址改变。

a = 'hello' 不可以原地修改a[0] = 'H'。需要修改a的值时,需要对a进行重新赋值a = 'Hello'。

列表是可变(mutable)类型,能在原内存地址改变。

@@ -660,7 +661,7 @@ A list of objects
-

数与格式化显示

+

数与格式化显示

x = 3.1415926
@@ -708,7 +709,7 @@ A list of objects
-

字符串(Strings)

+

字符串(Strings)

由字符组成。

fruit = 'banana!'
@@ -764,7 +765,7 @@ A list of objects

以上 # [start,stop,step] 代表注释(comment),注释以 # 号开头。

-

字符串相加(concatenation)

+

字符串相加(concatenation)

输出Jack, Kack, Lack, Mack, Nack, Ouack, Pack, and Quack

prefixes = 'JKLMNOPQ'
@@ -783,7 +784,7 @@ A list of objects
-

子串(slice)

+

子串(slice)

s[n:m],其中n或m可省略。 包括第n个字符,不包括第m个字符。(索引自0开始)

@@ -807,7 +808,7 @@ A list of objects
-

搜索字符串

+

搜索字符串

def find(word, c):
@@ -833,7 +834,7 @@ A list of objects

练习:用上面三参数的find来做。

-

String类(对象)方法

+

String类(对象)方法

upper()
lower()
@@ -846,14 +847,14 @@ A list of objects
-

in操作符

+

in操作符

'a' in 'banana' 'seed' in 'banana'

练习:写出下面的函数,使得 in_both('apples', 'oranges')返回'aes'。

-

字符串比较

+

字符串比较

字典序(alphabetical order)。大写字母排在小写字母前。

字符串之间可以有以下对比操作:

@@ -869,7 +870,7 @@ in_both('apples', 'oranges')返回'aes'。

即兴定义函数,制造一个长度不小于4的密码。

-

列表

+

列表

语言的内置(built-in)类型。注意与String类比,index也是从0开始, in操作符, 求长度,获得字串,遍历操作类似。

@@ -987,7 +988,7 @@ a与b是指向[1,2,3]的两个references。 error-prone(易错)

-

列表作为参数

+

列表作为参数

def delete_head(t):
@@ -1003,7 +1004,7 @@ error-prone(易错)

-

注意区别 append+ 操作符

+

注意区别 append+ 操作符

t1 = [1, 2]
@@ -1030,7 +1031,7 @@ error-prone(易错)

-

TDD - Test-driven Development

+

TDD - Test-driven Development

测试驱动开发。 My favourite。 刺激有挑战性。 帮助厘清需求。 帮助编写代码。

推荐使用pytest。如何安装? 使用命令 pip install pytest

test_cases.py 写如下测试用例。然后在命令行运行: python -m pytest test_cases.py

@@ -1070,13 +1071,13 @@ error-prone(易错)

-

计算复杂度

+

计算复杂度

用Big O表述复杂度。O(n), O(n^2), O(n^3)。

密码实验回顾。

-

字典(Dictionary)

+

字典(Dictionary)

Mutable数据类型。

实际开发中超级有用。

@@ -1100,7 +1101,7 @@ error-prone(易错)

key-value pair (item)

item的顺序不可预测,不是按照创建时的顺序。

-

递增开发(Incremental Development)

+

递增开发(Incremental Development)

每次完成一小点。从易到难。

练习:给定一个字符串,数出每个字母出现的频率。

@@ -1208,7 +1209,7 @@ error-prone(易错)

练习: 改写函数 word_frequency , 使它能接受第三个参数, black_lstblack_lst 是包含要排除考虑的单词的列表。 例如, black_lst 可以是 ['the', 'and', 'of', 'to']

-

key与value互换

+

key与value互换

注意到在原来的字典中一个value可能对应多个key的值。比如 d = {'a':1, 'b':2, 'c':2} 中,2就对应两个key,'b'与'c'。

 def inverse_dictionary(d):
@@ -1245,14 +1246,14 @@ error-prone(易错)

-

字典里面可以有字典

+

字典里面可以有字典

 d = { 'john':{'dob':'1990-10-23', 'height':'6 feet 5 inches'} }
 
-

函数

+

函数

当我们开始不断复制黏贴代码时,就要考虑把这部分代码做成函数了。

函数 unique_wordsunique_words2 哪个运行速度快?

@@ -1271,11 +1272,11 @@ error-prone(易错)

print(unique_words2(['hello', 'world', 'am', 'he'] * N))
-

局部变量

+

局部变量

在函数之内。函数执行结束,局部变量消失。

-

全局变量

+

全局变量

全局变量位于函数之外,模块之内。全局变量对所有模块内的函数可见(可读)。如果在函数内要对全局变量重新赋值,那么要先用 global 声明之 (declare)。

 verbose = True
@@ -1325,7 +1326,7 @@ error-prone(易错)

练习: 定义一个函数 empty_dict 清空字典 record。 要求: 不能用 return 语句。 提示: 可以用 pop 方法, 或者直接给 record 赋值 {}

-

调用函数与传递参数

+

调用函数与传递参数

在使用函数前要先确定函数已经被定义。

区别 argumentparameter 。传过去的是 argument , 函数头的参数列表是 parameterargument 的值赋给 parameterparameter 是函数的局部变量。

argumentparameter 的名字可以相同也可以不同。

@@ -1346,17 +1347,105 @@ error-prone(易错)

以上 t 一个是全局变量一个是局部变量。

-

函数执行顺序 (flow of execution)

+

函数执行顺序 (flow of execution)

函数的定义不执行,被调用时才执行。

顺序执行。 当遇到函数调用时,跳转到函数,执行函数,函数返回后继续执行跳转地后一条语句。

-

排序

+

文件

+

信息多存储在文件中。所以文件的读写是最最常见的操作。 本节主要考虑纯文本文件。 以下后缀结尾的文件一般都是纯文本文件: txt, csv, html, rst, md。

+
+
实验: 读取纽约新生儿的名字统计文件 PopularBabyNames
+
写命令行程序 lookupname.py 。给定性别与种族,输出最流行的头几个名字。 +命令行例子: python lookupname.py girl white top5 。 这个命令输出最流行的5个白人女孩的名字。 +第一个参数可以是 girl/boy , 第二个参数可以是 asian/white/black/hispanic 。第三个参数以 top 开始,默认是 1。
+
+
+# Copyright (C) 2019 Hui Lan
+# lanhui AT zjnu.edu.cn
+# Purpose: 1. Introduce command line argument parsing. 2. Introduce nested dictionaries.
+# Usage:
+#   python lookupname.py asian boy top10
+#   python lookupname.py white girl top5
+#   python lookupname.py girl white top
+
+
+def map(x):
+    d = {'FEMALE':'girl', 'MALE':'boy', 'ASIAN AND PACIFIC ISLANDER':'asian', 'ASIAN AND PACI':'asian',
+         'BLACK NON HISPANIC':'black', 'BLACK NON HISP':'black', 'HISPANIC':'hispanic', 'WHITE NON HISPANIC':'white', 'WHITE NON HISP':'white'}
+    return d[x]
+
+
+def file2dict(fname):
+    d = {} # will be a nested dictionary: e.g., d[gender] = {'asian':{'name':count}, 'black':[], 'white':[], 'hispanic':[]}
+    f = open(fname)
+    lines = f.readlines()
+    for line in lines[1:]:
+        line = line.strip()
+        lst = line.split(',')
+        gender = map(lst[1])
+        ethnicity = map(lst[2])
+        firstname = lst[3].title()
+        count = int(lst[4])
+        if not gender in d:
+            d[gender] = {ethnicity: {firstname:count}}
+        else:
+            if not ethnicity in d[gender]:
+                d[gender][ethnicity] = {firstname:count}
+            else:
+                if not firstname in d[gender][ethnicity]:
+                    d[gender][ethnicity][firstname] = count
+                else:
+                    d[gender][ethnicity][firstname] += count
+    f.close()
+    return d
+
+
+def get_commandline_parameter(lst):
+    d = {'gender':'', 'ethnicity':'', 'top':1}
+    for x in lst:
+        o = x.lower()
+        if o in ['asian', 'black', 'white', 'hispanic']:
+            d['ethnicity'] = o
+        elif o in ['girl', 'boy']:
+            d['gender'] = o
+        elif o == 'top':
+            pass # use default value 1
+        elif 'top' in o:
+            d['top'] = int(o[3:])
+        else:
+            raise Exception('Not recognised option %s' % (x))
+    return d
+
+
+def sort_by_value(d):
+    ''' Return a sorted list of tuples, each tuple containing a key and a value.
+        Note that the tuples are order in descending order of the value.'''
+    import operator
+    lst = sorted(d.items(), key=operator.itemgetter(1), reverse=True)
+    return lst
+
+
+import sys
+if __name__ == '__main__':
+    d = file2dict('Popular_Baby_Names.csv')
+    args = get_commandline_parameter(sys.argv[1:])
+    gender = args['gender']
+    ethnicity = args['ethnicity']
+    top = args['top']
+    d2 = d[gender][ethnicity]
+    lst = sort_by_value(d2)
+    for i in range(top):
+        print(lst[i][0])
+
+
+
+

排序

排序是常见重要的操作。 按照成绩排序。 按照文件名排序。 按照文件大小排序。 按照时间排序。

Python自带的 sorted 可以很好满足排序需求。

-
-

排序一组数或一组字符串

+
+

排序一组数或一组字符串

如果需要从大到小排序, 添加 reverse=True

 # Sort numbers
@@ -1381,13 +1470,16 @@ error-prone(易错)

print(sa_decr)
-
-

自定义排序算法

-

为了弄清排序的原理, 我们看两种排序算法。

-

选择排序

+

自定义排序算法

+

为了弄清排序的原理, 我们看两种排序算法。

+
+

选择排序

遍历列表,每次把最小的那个放到最左边位置。

+# Copyright (C) 2019 Hui Lan
+# lanhui AT zjnu.edu.cn
+
 def swap(L, i, j):
     L[j], L[i] = L[i], L[j]
 
@@ -1418,9 +1510,12 @@ error-prone(易错)

-

合并排序 (Merge sort)

+

合并排序 (Merge sort)

将列表一分为二,对每半部分排序,把排好序的两部分合并之(确保合并后同样是排好序的)。 注意到,以下的实现方式是递归。

+# Copyright (C) 2019 Hui Lan
+# lanhui AT zjnu.edu.cn
+
 def _merge(L, R):
     ''' Return a sorted list that combines the sorted list L and sorted list R.'''
     nL = len(L)
@@ -1463,8 +1558,8 @@ error-prone(易错)

-
-

比较排序速度

+
+

比较排序速度

排序是 Python 的核心算法,所以是优化了再优化。

Python 自带的排序算法最快, selection_sort 最慢。

@@ -1490,7 +1585,7 @@ error-prone(易错)

result2 = selection_sort(L) print(time.time() - now) -assert result0== result1 +assert result0 == result1 assert result1 == result2

在命令行运行上面的程序,在作者的计算机上得到如下的结果。

@@ -1503,8 +1598,8 @@ error-prone(易错)

11.57
-
-

排序元组列表

+
+

排序元组列表

一个元组由多个元素组成,多个元组组成元组列表, 如何按照某个元素进行排序呢?

可以有以下两种方案。一种用模块 operator , 一种用 lambda 函数。

@@ -1534,7 +1629,7 @@ error-prone(易错)

-

巧用 lambda 函数进行灵活排序

+

巧用 lambda 函数进行灵活排序

如何把一个由字符串组成的列表按照字符串的长短进行排序?

 lst = ['this', 'is', 'a', 'example']
@@ -1591,8 +1686,8 @@ What here shall miss, our toil shall strive to mend.'''
 
-
-

参考

+
+

参考

diff --git a/LectureNotesOnPython.rst b/LectureNotesOnPython.rst index a729f22..216c148 100644 --- a/LectureNotesOnPython.rst +++ b/LectureNotesOnPython.rst @@ -1071,6 +1071,104 @@ key与value互换 +文件 +------------------------------------------------ + +信息多存储在文件中。所以文件的读写是最最常见的操作。 本节主要考虑纯文本文件。 以下后缀结尾的文件一般都是纯文本文件: txt, csv, html, rst, md。 + +实验: 读取纽约新生儿的名字统计文件 PopularBabyNames_ 。 + 写命令行程序 lookupname.py 。给定性别与种族,输出最流行的头几个名字。 + 命令行例子: ``python lookupname.py girl white top5`` 。 这个命令输出最流行的5个白人女孩的名字。 + 第一个参数可以是 ``girl/boy`` , 第二个参数可以是 ``asian/white/black/hispanic`` 。第三个参数以 ``top`` 开始,默认是 1。 + +.. _PopularBabyNames: https://data.cityofnewyork.us/api/views/25th-nujf/rows.csv?accessType=DOWNLOAD + +.. code:: python + + # Copyright (C) 2019 Hui Lan + # lanhui AT zjnu.edu.cn + # Purpose: 1. Introduce command line argument parsing. 2. Introduce nested dictionaries. + # Usage: + # python lookupname.py asian boy top10 + # python lookupname.py white girl top5 + # python lookupname.py girl white top + + + def map(x): + d = {'FEMALE':'girl', 'MALE':'boy', 'ASIAN AND PACIFIC ISLANDER':'asian', 'ASIAN AND PACI':'asian', + 'BLACK NON HISPANIC':'black', 'BLACK NON HISP':'black', 'HISPANIC':'hispanic', 'WHITE NON HISPANIC':'white', 'WHITE NON HISP':'white'} + return d[x] + + + def file2dict(fname): + d = {} # will be a nested dictionary: e.g., d[gender] = {'asian':{'name':count}, 'black':[], 'white':[], 'hispanic':[]} + f = open(fname) + lines = f.readlines() + for line in lines[1:]: + line = line.strip() + lst = line.split(',') + gender = map(lst[1]) + ethnicity = map(lst[2]) + firstname = lst[3].title() + count = int(lst[4]) + if not gender in d: + d[gender] = {ethnicity: {firstname:count}} + else: + if not ethnicity in d[gender]: + d[gender][ethnicity] = {firstname:count} + else: + if not firstname in d[gender][ethnicity]: + d[gender][ethnicity][firstname] = count + else: + d[gender][ethnicity][firstname] += count + f.close() + return d + + + def get_commandline_parameter(lst): + d = {'gender':'', 'ethnicity':'', 'top':1} + for x in lst: + o = x.lower() + if o in ['asian', 'black', 'white', 'hispanic']: + d['ethnicity'] = o + elif o in ['girl', 'boy']: + d['gender'] = o + elif o == 'top': + pass # use default value 1 + elif 'top' in o: + d['top'] = int(o[3:]) + else: + raise Exception('Not recognised option %s' % (x)) + return d + + + def sort_by_value(d): + ''' Return a sorted list of tuples, each tuple containing a key and a value. + Note that the tuples are order in descending order of the value.''' + import operator + lst = sorted(d.items(), key=operator.itemgetter(1), reverse=True) + return lst + + + import sys + if __name__ == '__main__': + d = file2dict('Popular_Baby_Names.csv') + args = get_commandline_parameter(sys.argv[1:]) + gender = args['gender'] + ethnicity = args['ethnicity'] + top = args['top'] + d2 = d[gender][ethnicity] + lst = sort_by_value(d2) + for i in range(top): + print(lst[i][0]) + + + + + + + + 排序 ------------------------------------------------ @@ -1121,6 +1219,9 @@ Python自带的 ``sorted`` 可以很好满足排序需求。 .. code:: python + # Copyright (C) 2019 Hui Lan + # lanhui AT zjnu.edu.cn + def swap(L, i, j): L[j], L[i] = L[i], L[j] @@ -1157,6 +1258,9 @@ Python自带的 ``sorted`` 可以很好满足排序需求。 .. code:: python + # Copyright (C) 2019 Hui Lan + # lanhui AT zjnu.edu.cn + def _merge(L, R): ''' Return a sorted list that combines the sorted list L and sorted list R.''' nL = len(L) @@ -1231,7 +1335,7 @@ Python 自带的排序算法最快, ``selection_sort`` 最慢。 result2 = selection_sort(L) print(time.time() - now) - assert result0== result1 + assert result0 == result1 assert result1 == result2 -- cgit v1.2.1