分类目录归档:计算机

第 2 课 字符串和数据结构

第 2 课 字符串和数据结构

不会的东西可以在群里提问、或搜索查看标准库文档入门教程。( Ctrl + F )

课程纲要和笔记

  1. 数据结构
    • 复习变量
      • 变量是内存的名字,赋值过程就是名字的重新绑定。例子:a = 1 a = a + 1
    • 复习数据类型
      • int, float: + - * \ \\ %
      • str: + == replace() split() format() strip() notice:*
      • bool: or and not
      • str(), float(), int():特定的类型有特定的运算,所以需要进行类型转换。
  • 数据结构是什么以及意义是?
    • 上述数据类型是最基本的、不可分割的数据结构。例子:学生信息表:学号、身份证、姓名。
    • 由于内存的性质,我们需要把现实世界的数据用线性的结构表示。数据结构,要考虑其结构操作
  • list 列表
    • 数据:本质上是表格,线性排列,可以是任何类型,
    • 操作:
    • append() [] * n +
    • pop() pop(i)
    • array[i] = n
    • fruits.index(x)
    • 更多特性
  • tuple 不可变列表
  1. 字符串和文件读写
  • f = open(file_name, 'w', encoding="utf-8") f.close()
    • 如何存储文件?文件读写
    • 需要 close 因为操作系统的规定。
    • f.read() , f.readline()
    • f.write()
  1. 简要复习上一课的内容,解答作业
    1. 编写一个程序:能顺序地输入两个数,回车后,程序将在在屏幕上打印两个数分别加减乘除的结果,程序代码应该包括你的注释
    2. 编写一个程序:能先输入字符串 s,然后输入一个整数 n,程序将把 n 个字符串拼接打印出来。

课后作业

  1. 编程作业,程序满足:自定义一个list里面包含一些整数,自行对其进行增删改查操作,转换成str类型,按照utf-8编码输出为txt文件。

  2. 复制下列代码,并利用它在屏幕上打印出Google likes Python

L = [
    ['Apple', 'Google', 'Microsoft'],
    ['Java', 'Python', 'Ruby', 'PHP'],
    ['likes', 'dislikes', 'own']
]

附录

  • 注意:上课的时候突然卡壳了!readline() 在遇到行尾的时候返回空白字符串,转成bool型是False,正确的按行读取并且加载到数组中应该是这样:

    array = []
    with open("test.txt", "r", encoding="utf-8") as f:
      text = f.readline()
      array.append(text)
      while text:
          text = f.readline()
          array.append(text)
    print(array)
  • 上课代码

    if __name__ == '__main__':
      print("hello")
      a = 1
      a = a + 1
      a = "test"
    
      print(a.capitalize())
      print(a == b)
      user = input()
      age = input()
      welcome = "hello, {0}, {1}".format(user, age)
      print(welcome)
      b = "hello"
      n = int(input())
      #   integer
      #   int(n) * str(b)   --> str
      print(n * b)
      flag = True
      # not
      # not True = False
      # or
      # (bool) and (bool)
      print(flag and False)
    
      #   原子
      #   学生表 :学号(str or int)、身份证(str)、姓名(str)。
      #   学生表 : x1 学号身份证姓名
      #   学生表 : x2 学号身份证姓名
      #   图 1-256
      array = [2, "s", 1.16 ]
      a = [1, 9, 3]
      b = [2, 2,2]
      matrix = [
          a ,
          b ,
          [  2,3,5  ]
      ]
    
      array.append("hello")
      array = ["s"] * 9
    
      new_list = array + matrix
      print(new_list)
      new_list.pop(3)
    
      new_list[0] = "T"
    
      new_list.clear()
      print(new_list)
    
      print(new_list.index("s"))
      # (list) .index( )
    
      t1 = tuple([1, 2, 4, 5, 8])
    
      table = tuple(["monday", "tuesday"])
      print(table[0])
    
      string = "s12255122sw"
      #   []
      print(string[1:-2])
      print(string[-2:])
      #   gbk
      #   utf-8
      #   01010 -->  a
      #   01010 -->  b
      #
      f = open("test.txt", "w", encoding="utf-8")
      # r: read w:write
      f.write(string * 10)
      f.close()
    
      # array = []
      #
      with open("test.txt", "r", encoding="utf-8") as f:
          text = "2"
          while text:
              text = f.readline()
              array.append(text)
    
      print(array)
    
      a = float(input())
      b = float(input())
      print(a * b, a + b , a / b)
    
      s = input()
      n = int(input())
      print(n * s)

第 1 课 变量和类型,用内存的视角看数据

第 1 课 变量和类型,用内存的视角看数据

注意,任何情况下,新手应该从官方的教程和API教程开始:Python 文档,而不是网上良莠不齐的资料。同时,不要成为语言律师 ( language lawyer )。

  • 运行 Python 脚本的两种运行方法是什么?
  • 什么是内存?
  • 什么是变量?
  • 什么是类型?
  • 变量和字面量有什么关系?
  • 当我们 print 的时候,计算机发生了什么?

课程纲要

  • 程序如何运行(了解)
    • 抽象
    • 内存
    • 运行 Python 脚本发生了什么(用命令行、用IDE)
  • 变量与类型(掌握,请在课后阅读官方教程加深理解)
    • 变量的意义及其命名
    • 变量内存中的表现(以后再深入,先大致了解)
    • 布尔类型及逻辑运算
    • 数字及算术运算
    • 整数
    • 字符串及其操作
    • 拼接、*、strip()、split() 等操作
    • 转义符号
    • 字符串编码
    • 「烫烫烫烫」是什么(utf-8, gbk 等编码问题,深入可以了解 字符编码笔记:ASCII,Unicode 和 UTF-8
    • str(), float(), int()
    • input(), print(), len()
  • 加餐(学有余力的同学可看)
    • 数字编码
    • 整数:补码和原码
    • 小数:浮点数
    • 计算机体系结构
    • 冯诺依曼结构
    • 当我们 print 的时候,计算机发生了什么?
    • 真正的互联网,已经死了

课后作业

  1. 编写一个程序:能顺序地输入两个数,回车后,程序将在在屏幕上打印两个数分别加减乘除的结果,程序代码应该包括你的注释
  2. 编写一个程序:能先输入字符串 s,然后输入一个整数 n,程序将把 n 个字符串拼接打印出来。

授课笔记

  • 程序如何运行(了解)
    • 计算机最重要的概念——抽象是什么?出租车的例子
    • 内存
    • CPU就像我们的大脑,内存就像我们的草稿本
    • 是一组线性的空间
    • 运行 Python 脚本发生了什么?
    • IDE: pycharm, idle 命令行调用:cmd, bash, ssh
    • 学有余力的同学可以学后面的计算机体系结构
  • 变量与类型(掌握,请在课后阅读官方教程加深理解)
    • 变量的意义及其命名
    • 为啥需要变量?因为这是一个变动的世界
    • 如何命名?用英文单词,函数和变量 = 小写 + 下划线, 类名使用驼峰命名法(PyCharm 会提示你)
    • 类型是什么?
    • 变量内存中的表现(以后再深入,先大致了解)
    • 变量和字面量有什么关系?
    • 布尔类型及逻辑运算
    • why: 因为我们需要根据不同情况去运行不同的解决方法,比如登录账号的时候。
    • and, or, not
    • 数字及算术运算
    • why: int 和 float 处理生活的数据
    • 加减乘除,求幂,取模,// 向下取整
    • 字符串及其操作
    • 跨行输入、拼接、*、strip()、split() 等操作
    • 转义符号
    • 字符串编码
    • 「烫烫烫烫」是什么(utf-8, gbk 等编码问题,深入可以了解 字符编码笔记:ASCII,Unicode 和 UTF-8
    • str(), float(), int()
    • input(), print(), len()
  • 加餐(学有余力的同学可看)

    • 数字编码

    • 整数:补码和原码

    • 小数:浮点数

    • 计算机体系结构

    • 冯诺依曼结构:我们需要先大致了解计算机的体系结构:

    • gda
    • 1182611-20190530163801121-1848365582
    • 当我们 print 的时候,计算机发生了什么?

    • 真正的互联网,已经死了

第 0 课 Hello, world!

第 0 课 Hello, world!

1.前言

“软件定义世界”,不仅因为「移动支付让超市不再找零,使口香糖销量大减」这样的小事,还说明未来程序将不可避免地深入人们的生活,而且会重构现实世界。

以前的生活需要一个门卫守停车场,而现在可以做到只需要监视器和二维码,意味着什么?

  1. 停车场不再可能发生门卫让自己的熟人进来,或中饱私囊的事情。程序把流程写死,可以定义社会规则。
  2. 停车场不再需要一个人守在门口,只需电力和少数维护成本。程序将替换机械的工作,节省人力成本,提高生产力。
  3. 用算法对调度各区域的停车场车位,人们将不会浪费时间在找停车场上。程序可以对资源进行抽象,用数学让效率最大化

用最短路算法实现地图导航、用协同过滤推荐调节商品供需关系…… 从这点来看,只要人们还需要提高生产力,软件就会持续地改变世界。

编程对不是计算机的专业有什么用?

8岁时李笑来向他妈妈要了10元钱,去少年宫学习计算机编程。后来在新东方当老师,编写《TOEFL核心词汇21天突破》一书时,他用自己编写的批处理程序,短时间内完成了海量词汇处理工作。在现在看来,写这样一本按词频收集单词的书,对一个过了四级的学过编程的人其实毫无难处,难的是在一个「少年宫」还流行的年代,还学到了编程,并且在自己的领域内发现了计算机的能力。

计算机是人大脑的延伸,学编程是学会用计算机的视角看世界。更重要的信息的搜集能力,和快速学习的能力,前者是靠的是领域经验,后者更多的是靠天赋和后天的积累。所以本节课重点不教编程,只教搜集。

2. 方法

接下来你需要学习如何使用搜索引擎,不要怀疑,大多数人并不懂搜索。网上已经有很多资料了:

上面的技巧,不需要全部都会,知道一点点就可以了,大多数搜索引擎都可以使用。

推荐两个搜索引擎:
http://bing.com/
https://duckduckgo.com/

下面是锻炼你搜索能力的题目,安装两个软件,在上面写出代码,并且正确运行。

网上其实有无数的教程和博客去说这两件事情,那么问题其实是,如何快速找到并了解一个新事物、一个未知的逻辑?

请完成下一节的练习

3. 安装编程环境

根据自己的操作系统,安装下面两个软件。目前不需要知道下面两个软件是什么,先安装好再说。

3. Hello, world! 开始你的第一个程序

配置好解释器,下载安装好后在 pycharm 新建一个项目,新建一个 py 文件,内容是:

print("Hello, world!")

复制、粘贴、运行就可以了。

日程

虽然简单,做完后,请把运行成功的全屏截图,发到我的邮箱kevtyle@hotmail.com,过期算一次不交作业哦。

做完后,请把运行成功的全屏截图,发到下列邮箱:

python[\at]benearyou.com (为防止垃圾邮件骚扰,把 [\at] 改成 @ 为真实邮箱)

这次作业改为课后作业,课程简介更新了,请仔细查看。

直播 12月27日 20:00(暂定),直播当天发布下一次课的内容。

课后作业 12月30日 23:59

作业 12月28日 23:59 截止。

隔一天一次直播,即下一次课为12月29日 20:00

这个冬天跟 Python 有一个约会

Dating-with-python-this-winter

visitor badge

这个冬天跟 Python 有一个约会——一个兴趣使然的 Python 课程。

前言

课程目的是让大家了解编程——最好是编程思想,掌握 Python 的基本操作。考虑到大家来自各种各样的专业,爬虫指定是不行,对大家没啥用,客户端或者后端也是对程序员才有用。

所以,学会 Python 基础之后,一个具体目的暂定是

学习数据处理、分析, 掌握 Numpy, Pandas 等框架。

起源

你为啥要搞这样的教学啊?

这次课程源自于某个北京研究生豆瓣群,有人问一个月适合学什么啊?我回答 Python,于是就成立了!随后,我想反正都是教,为什么不多拉点人呢,于是就去豆瓣拉人了,也去了即刻,区域也从北京到各地(云南、内蒙古、湖南……)。

如何上课?

课程分为三个部分

课前预习:大家可以试着完成,全凭自觉噢。

课中讲解:一个小时直播。哔哩哔哩直播

课后编程实践:需要自主完成作业,编程是实践技术,跟厨师和木匠一样,所以每次请你认真完成作业,一节课的作业截止日期一般是下一节课上完之后的一天。不再强制交作业了,如果需要催作业和批改作业服务,可以参与硬币计划,所有付费将捐给孩子们。

  • 免费:课程除了催作业和批改作业服务之外,视频、文档、群里答疑都是免费的。

  • 答疑:希望大家可以自主思考,有问题发到群里大家一起讨论。可以直接私信我,或者直接发群里交流,最后我们可以把这些答疑沉淀为文档。

  • 时间安排:开课后,一般隔两天上一节课,一天空闲是留给课前问题和课后编程的。

  • 硬币计划:目前我们还推出了硬币计划,你自行为孩子们进行捐款,可享受群主夺命催作业和批改作业服务。当然,不付费也可以参与课程和答疑,详情见下方链接:Github |博客

    欢迎加入噢!

  • 闻道有先后,术业有专攻。虽然是免费的,希望大家也能认真对待自己的时间和精力,如果觉得自己不能坚持学习,那应该提前退群,免得浪费时间。

课程目录和时间点

节数 文档和视频 直播时间(20:00) 课后作业期限(23:59)
0 Hello, world! Github | 博客 | 12月27日录播 12月27日 12月30日
1 变量和类型,用内存的视角看数据 Github | 博客 | 12月29日录播 12月29日 1月1日
2 字符串和数据结构 Github | 博客 | 1月1日录播 1月1日 1月5日
3 控制流 Github | 博客 | 1月3日录播 1月3日 1月7日
4 计算的本质 Github | 博客 | (1月8日点错了按钮,是没有录成视频,可惜……) 1月8日 无作业
5 函数与作用域 Github | 博客 | 1月11日录播 1月11日 1月14日
6 类与数据结构 Github | 博客 | 1月14日录播 1月14日 1月17日
7 面向对象的类设计 Github | 博客 | [1月17日录播]() 1月17日 1月20日
第 8 课 数据分析初步 Github | 博客 | 1月21日录播 1月21日 1月23日
第 9 课 NumPy 之 ndarray Github | 博客 | 1月24日录播 1月24日 1月26日
第 10 课 NumPy 计算和广播原理 Github | 博客 | 1月26日录播 1月26日 动手实现代码
第 11 课 Matplotlib 画图 Github | 录播 动手实现代码
第 12 课 Pandas (1) Github | 视频 动手实现代码
第 13 课 Pandas (2) Github

注意,后续机器学习与数据分析课程
https://github.com/xrandx/Dating-with-Machine-Learning

注意

如何参与

内容指引

  • 变量定义
  • 算术运算
  • for 循环语句,while 循环语句,goto 语句
  • 函数定义,函数调用
  • 递归
  • 静态类型系统
  • 类型推导
  • lambda 函数
  • 基于对象和面向对象
  • 垃圾回收与内存模型
  • 指针算术
  • ……

正则表达式-非捕获组的迷思 ( non-capturing group ) (?:)

(?:…)
正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串不能在执行匹配后被获取或是之后在模式中被引用。

这解释真叫人头大。

例一

(aa|bb) 匹配 aabb

结果是

类型 范围 内容
Match 1
Full match 0-2 aa
Group 1. 0-2 aa
Match 2
Full match 2-4 bb
Group 1. 2-4 bb

例二

(aa|bb)+ 匹配 aabb

结果是

类型 范围 内容
Match 1
Full match 0-4 aabb
Group 1. 2-4 bb

第一个先匹配到 aa ,再匹配到 bb 。第二个直接匹配了 aabb 。
第一个和第二个的差别在于,用 + 重复匹配组,后果就是组只会保留最后一个迭代。

例三

我们再试试:

(?:aa|bb)+ 匹配 aabb

类型 范围 内容
Match 1
Full match 0-4 aabb

组保存的消失了?这就是非捕获组的用处,意思就是不保存组的内容到内存中,也就不会标号,于是只会得到匹配。

例四

这个用处是什么呢
先看看这个 Python 代码:

reg = r"(0\d{2})-(\d{7})"

s = "010-3838438"

re.findall(reg, s)

#  Out:[('010', '3838438')]

reg = r"(?:0\d{2})-(?:\d{7})"

s = "010-3838438"

re.findall(reg, s)

#  Out:['010-3838438']

上述差别如何发生?

第一个匹配的结果是

类型 范围 内容
Full match 0-11 010-3838438
Group 1. 0-3 010
Group 2. 4-11 3838438

而第二个匹配的结果是

类型 范围 内容
Full match 0-11 010-3838438

Python 自带的 re 模块函数:

re.findall
对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。

也就是从左到右,按正则表达式,不重复地匹配字符串,返回一个字符串列表。 如果正则表达式有一个或更多的组,返回组的列表,优先返回组。

第一个匹配里有两个组,所以只返回了组。

不得不说这个函数实现的很失败,为什么不把所有结果都返回?

最后一个例子

建议你自己猜一下输出结果:

s = 'exp=50;exp=51;'

re.findall(r'exp=(50|51);', s)

re.findall(r'exp=(?:50|51);', s)




#  Out:['50', '51']

#  Out:['exp=50;', 'exp=51;']

为什么出现这种差别?

前者有两个匹配,每个匹配有一个组。后者只有两个匹配。

因为 findall 总是尽力返回捕获的组,也就是括号内的字符串。(太蠢了)

使用了 (?:) ,它不会保存匹配的组。如果 findall 没有捕获到组,就会返回所有匹配的字符串。

Python 利器之 SQLAlchemy

参考

请参考官方文档:sqlalchemy

SQLAlchemy 是什么

相当于 Java 的 Hibernate 和 Mybatis (我更喜欢MybatisPlus :),是 Python 里数一数二的 ORM框架。
ORM框架,本质上就是程序员懒得写 SQL 语句或者实体对象代码,于是让对象代码生成 SQL 语句或者让 SQL 语句生成对象,形成所谓的对象关系映射的程序框架(Object Relational Mapping)

初始化

初始化填好数据库信息,连接数据库,生成引擎,建立会话就好。当然它还可以连接内存数据库 sqlite 。
echo参数可以控制是否显示数据库操作细节。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String

mysql_config = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (username, password, host, port, database_name)
engine = create_engine(mysql_config, echo=False)
Base = declarative_base()
DbSession = sessionmaker(bind=engine, expire_on_commit=False)
session = DbSession()

通过 declarative_base ,框架会处理你的类声明,自动将你的类与数据库表绑定。
如下:User 继承 Base 。

最好在类内声明数据类型。 primary_key 参数代表是否为主键。
tablename 为数据表表名。

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

增加

user1 = User(name='lihua', age=18)
session.add(user1)

user2 = User(name='hanmeimei', age=18)
user3 = User(name='songwenhua', age=18)

session.add_all([user1, user2])
session.commit()
# commit 才能提交更改

查找

过滤器有 filter_by 和 filter ,前者用于简单的查询。
filter_by 只支持 = 运算。
filter 支持 ==, >, < ,还支持 like, has, in_, or_, and_ 等自带操作。
查找后要加 all(), first(), 或者 limit() 。

session.query(User).filter_by(id=1).first()
# 代表第一个
# desc(): 降序
session.query(User).order_by(User.id.desc()).all()
# asc():升序
session.query(User).order_by(Users.name.desc(),User.id.asc()).all()

#  例子
query.filter(Address.user == someuser)
query.filter(Address.user != someuser)
query.filter(Address.user == None)
# 名称中包含
query.filter(User.addresses.contains(someaddress))
# 用于多对一关系
query.filter(User.addresses.any(Address.email_address == 'bar'))

删除

User.query.filter(User.id == 123).delete()
session.commit()

修改

只需要查找之后,修改对象的值,commit 就可以了。

p = session.query(ParamClass).filter_by(id=1).first()
p.k1 = k1
session.commit()

flush 和 commit区别

flush 只是将语句发送到数据库内存,这种改变在这个会话可以看见,其他会话则不然。
commit 会提交所有更改,存至磁盘,其他会话也能查询到这种更改。

如何动态绑定表

接下来是重头戏了,由于业务需求,我需要根据情况,将同一类型的对象,存储在不同的表,也就是将数据存多个表,这些表的列名和结构都一致。
Python 的一个特性是可以动态生成类,利用 type() 不仅可以判断数据类型,还可以生成类:

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

由于框架是根据tablename来绑定表的,而且类的tablename是无法改变的。
于是可以用字典在一开始就把表名和类相关联,Model 是存粹的数据模型,Base 是 declarative_base 而来。这样就可以根据情况来匹配类了。

class User():
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

table_mapper_dict[table_name] = type(
    table_name,
    (Model, Base),
    {'__tablename__': table_name}
)