First Touch of Python
First Touch of Python
Python千千万, 到处都在吹, 我也知道它很好, 只是我不爱.
算了, 为了更好的学习和与他人交流, 我现在要学一点python.
但是, 因为我学过一点点(真的只有一点点)半吊子的ruby,
所以我会用ruby来学习python, 并且尽量找一种可以把python
代码用ruby来写的做法.
没什么关系的前言
这真的不知道该高兴呢还是伤心, 感觉python超级受欢迎,
有很多的支持和帮助, 结果就导致了文档到处都有.
一个库有一个库的文档, 分散(确切的来说,
应该是被不同的”友好”的组织发布)在不同的地方.
查找起来就很让人不爽了.
但是ruby虽然有一些看起来很官方的文档,
rdoc简直就是天堂. 不得不佩服ruby程序员.
程序员笑话: 程序员最讨厌的事情就是看没有注释和文档的代码, 以及写注释和文档.
(但是这是不是因为ruby实在是太冷门了?
感觉完全没有人想要在它身上捞烂钱. 所以除了官方,
其他人也没什么动力来搞它? 好像也不是,
因为以前还是有神仙的. )
(所以自学python等价于在网上看视频, 看书, 看教材…
自学ruby等于看文档, 看源码, 看命… ?)
Python Basis
运算符, 赋值, 类型
目测和ruby是大同小异的
string = "Hello, this is python. "
x = 3
y = 4
((1 + 2 / 4) ** x - ((6 % y) << 7)) // 4
# // 是整除的运算
# 在ruby里面默认是整除
# 比如3/2 => 1; 3.0/2 => 1.5
# 这是因为整数和浮点数的区别
# python自动做了这样的事
这里有一个注记: python的变量有点像是C里面的指针,
是和对象的地址相关联的东西.
高级操作: (和ruby一样)
x, y = 4, 5 # x = 4, y = 5
x, y = y, x # 交换变量
c = d = 6 # c = 6, d = 6
简单IO
print("yes? or no? ")
# 发现print("a", "b", "c")的话,
# 会自动在输出中间插入空格
# => "a b c"
# 嗯, 又是一个不一样的地方
input("Okay? ")
这样就可以得到输入和输出了
print(end="") # end 最后的字符
print(sep="") # seprate 分隔字符
和ruby不一样的是, ruby不强制要求函数输入括号;
但是ruby给了很多的输出函数, 这些函数还都有一点点的…
tricky…(QAQ, 这种时候感觉自己输了. )
puts("hello") # 和puts "hello"一样, 输出的末尾自带"\n"换行符
print("yes? ") # 输出的末尾不会换行, python 的会换行
p("ooo") # 一种输出, 不过很少见到, 在打印对象的时候会遇到
gets() # 得到输入, 唯一坑爹的是最后会加上一个"\n"
python好像也有类似的打印命令,
但是要引入一个库.
import pprint
pprint.pprint(obj) # => 会打印出来好的形式
pprint.pformat(obf) # => 会输出一个字符串
String
s = "this is a string"
# 字符串的长度
len(s) # => 16, ruby: s.length
# 类型转换
# int(string, base=10)
int("23") # => 23, ruby: s.to_i
# float() 同理
float("-0.13") # => -0.13, ruby: s.to_f
# str(obj)
str(23) # => "23", ruby: a.to_s
控制流
条件 if
在python中判断条件, 并进行分支.
if a:
print("a is true\n")
print("good. \n")
else:
print("a is false\n")
print("also good, too. \n")
if a:
# ...
elif b:
# ...
elif c:
# ...
else:
# ...
在ruby中也是这样的:
if condition == true then # 可以把then给扔掉
# hai~
elsif conditon == nil
# ruby 里面有true, nil(空), false
# 虽然nil可以用在逻辑判断中和false等价
# 但是实际上nil是一种类似于0一样的占位符
# 好像可以这样理解:
# 我不知道这个变量的值是什么, 所以就叫它nil算了
# python 里面也有, 叫做None
else
# ...
end
# ruby有行if和unless
# unless等价于写了if但是把条件加了一个not
puts a unless a.nil?
循环
python里面有while和for,
虽然和ruby一样, 这个for和C的for很不一样.
while:
while condition == true:
# ...
while True:
if condition != True:
break # 跳出while循环
if restartCondition == True:
continue # 回到循环的开头
for:
for i in range(5):
print("the", i, "times")
# range(start, end, step)
# range(start, end), step = 1
# range(end), step = 1, start = 0
这个时候ruby就有很多的骚操作了,
你可以写的超级花里胡哨, 总之是怎么花怎么来.
5.times do |i|
puts "the #{i} time"
end
5.times{print "ruby"}
(0..100).step(4).each{|i| puts i}
loop do
# 等价于while true
# break if ...
end
while condition == true
# ...
end
吐槽
这里可以看到python该死的块结构, 我觉得就很迷幻,
为什么要用缩进来表示块结构, 这个冒号:也太容易打漏了,
我看代码的时候也很累.
(好吧, 只是一己之偏见, 实际上ruby也是这样的啦,
也有缩进, 虽然不强制. end在多重嵌套的时候又会漏. )
不过不得不说, 感觉ruby就是一个超级缝合怪,
什么语言很高级, 很优美, 就吸收什么语言的特性,
佩服一下Matz, (刚好近代史纲提了一嘴日本).
函数
def funcName(arg, defaultArg="default value"):
# 如果一开始没有设定默认值的参数
# 在调用的时候就一定要给参数, 否则就会尬
# do things
return None # 返回值 不一定强制写返回值, 可以自动给出最后一个运算的值
在这个时候就会有一个叫作环境的概念,
不同的代码块可以看作是不同的环境,
可以想象一种global的环境, 就是总的代码的运行环境,
里面放了很多的东西, 但是当进入了一个新的环境的时候,
比如说在调用函数的时候, 就会局部开一个新的环境.
在这样的环境中, 如果调用变量的话就要有一些考虑了.
(一个猜想, 不一定对, 没准这就是stack的机理. )
x = 1
def hello():
print(x) # 这里的x是外环境的变量
def helloTwo():
x = 3 # 这里的x是局部变量
print(3)
def helloThree():
global x # 这里用global强制地声明x是外环境的变量
x = 3 # 改变了外环境的x
print(x)
hello() # => 1
hello() # => 3
print(x) # => 1, 没有改变外环境的x
helloThree()
print(x) # => 3
# 这样的函数比较危险, 还是少用为妙
简单的ruby代码:
def func(x, y=0)
print(x+y)
return x, y
end
异常处理
try:
# codes
# for example:
x = 4 / 0
except ZeroDivisionError:
print("Error")
# 处理代码, 救命用
在ruby中的形式:
begin
# ...
rescue => exception
# ...
else
# ...
end
数据结构
列表 List
这一节写的比较乱, 以后再改吧.
在ruby里面叫Array
- 定义列表:
list = ["a", 1, ["a", "asd"]] - 访问元素:
- index:
list[0] # => "a"顺着拿, 从0开始 - negative index:
list[-1] # => ["a", "asd"]倒着拿, 从1开始
- index:
- 修改元素:
list[index] = value
- 列表操作:
len(list) # => 3列表长度ruby:a.lengthdel list[index]删除值ruby:a.delete_at indexlist.append(value)向末尾添加值ruby:a << valuelist.insert(index, value)往index处插入元素ruby:a.insert index, valuevalue in list是否在列表里ruby:a.include? value
value not in list不再列表list.index(value)找到值的位置ruby:a.index value
list.remove(value)删除值ruby:a.delete value不一样的地方是python找不到就会报ValueError,ruby找不到的话就会返回nila
一样的地方都是只会给出第一次出现的匹配的值的位置for i in list:类似于ruby的list.each do ... endlist1 + list2相加list.sort排序list.sort(reverse=True)反向排序,list.sort(key=str.lower)利用关键词参数key可以设置排序方式为字典排序ruby:a.sort!
这里注意有一个ruby方法命名的约定, 就是方法命名的时候, 一般把会改变原来的对象的方法名称后面都有一个!表示要注意, 假如没有!, 只会产生一个排了序的副本.
- 列表切片:
list[startIndex:endIndex]ruby:a[start..end]
为什么要列表切片? 这是因为列表又一点像C里面的数组指针,
当a = list, 假如修改了a里面的元素,
list里面的元素也会随着发生变化.
列表和字符串
可以把字符串看作是一个列表
(在C中, 也确实是这样的. )
所以可以类似的这样访问字符串中的第几个字符: s[2]
但是不可以用来修改, 比如s[2] = "3"是不可以的.
因为字符串是不可变的对象?
(虽然在ruby里面是可以的)
元组
元组可以看成是不可以变的列表.
tuple = ('hello', 42, (1, 2, 3))
但是好像在ruby里面好像没怎么有类似的东西.
好像有冻结? 忘了.
类型转换
tuple(list), list(tuple)看就懂了.
字典
字典没有排序, 因为是靠key来访问的.
好像在ruby里面是靠hash值计算来访问的,
所以叫hash, 名字有点不一样.
dictionary = {
'key1': value1,
'key2': value2
}
dictionary['key1'] # => value1
for v in dictionary.values():
print(v) # => 输出value
for k in dictionary.keys():
# key
for i in dictionary.items():
# i = (key, value)
# 是一个键值对
ruby里面的hash是这样的:
hash = {
"key1" => value1,
"key2" => value2
}
hash['key1']
# ruby 还可以用Symbol来当key
hash = {
:key1 => value
}
value in dictionary, 等价于value in dictionary.values()key in dictionarydictionary.get(key, default)得到key对应的值, 假如没有就返回defaultdictionary.setdefault(key, value)检查key对应的值, 没有的话就把key的值设成value, 返回值就是key对应的值
字符串
和ruby一样, 单引号在python里面和双引号还是有那么大点区别,
坑爹的地方就是双引号里面支持字符转义, 单引号里不支持, 要注意…
因为字符串和列表很像, 所以有很多的类似的方法:
s = "abcdefghijklmn"
s[0] # => "a"
s[:4] # => "abcd"
s[7:] # => "hijklmn"
s[4:7] # => "efg"
"z" in s # => False
"c" not in s
s.upper() # 不会改变s
s.lower()
s.islower()
s.isupper()
s.startwith(string)
s.endwith(string)
虽然看起来很好用, 实际上鸡肋的很. 实际上还是直接正则表达式的感觉很好用的样子.
字符串和列表
", ".join(['a', 'b', 'c'])
# => a, b, c
"a, b, c".split(', ') # => 假如没有输入的话, 默认是空格
# => ['a', 'b', 'c']
ruby里面也有类似的函数
element.join(separator=$,)
# if element.kind_of?(Array)
"string".split(patten)
# 可以直接传入正则表达式来匹配
漂亮格式
"string".rjust(length) # 按长度length扩张字符串, 右对齐
"string".ljust(length) # 按长度length扩张字符串, 左对齐
"string".center(length) # 按长度length扩张字符串, 居中
# 上面的函数还可以添加第二个参数, 描述用来填充的字符
"string".center(10, '#') # => '##string##'
# 删除空白字符
" s a\n".strip() # 开头和末尾都没有空白字符"\n", " "等
" s a\n".lstrip() # left
" s a\n".rstrip() # right
# 还可以添加参数, 就会把参数里面的所有字符都当作是空白字符
ClipBoard
import pyperclip # pip install pyperclip
pyperclip.copy("string") # copy
pyperclip.paste() # paste
Advanced
Regexp
在ruby里面, 正则表达式是默认就开启的,
是一种内置的对象. 可惜python的没有.
正则表达式需要另外学, 感觉python的就有点麻烦.
import re
regexp = re.compile(r'regexp')
match = regexp.search('string') # 只找第一次
match = findall('string') # 全部找, 返回字符串的列表或者是元组的列表
match = regexp.sub('代替用字符串', '匹配用字符串') # 查找替换字符串
match.group(index)
# index = 0或者不输入: 返回匹配的全部文本
# index >= 1: 返回匹配组
在ruby里面的正则表达式写起来比较简单:
"to match words".match /\w+/
"to match words" =~ /\w+/
$~ # 返回最后一次的匹配结果
具体的我觉得ruby的文档写的足够详细了, 应该是够用了.
ruby3.0.2 regexp
FileIO
Basic
有一个很坑爹的地方:
在windows和linux或mac的文件路径名字不一样.
就是/和\的坑.
import os
os.path.join('usr', 'bin') # => 'usr/bin' linux
(实际上ruby里面的File类就直接支持这个,
File.join('usr', 'bin'). )
os.getcwd() # => 当前工作环境
os.chdir("path") # 打开文件夹, 打不开就FileNotFoundError
os.makedirs("path") # 新建文件夹
os.getlistdir("path") # 列出path里面的文件
os.path.getsize("path") # 文件大小
os.path.exists("path") # 是否存在
os.path.isdir("path") # 是否是文件夹
os.path.isfile("path") # 是否是文件
读取文件
f = open("path") # 打开文件
string = f.read() # 读取文件
l = f.readlines() # 读取行, 返回的是列表
f.write("string") # 写文件
f.close() # 关闭文件
保存数据的另外方法
import shelve
shelfFile = shelve.open('data') # 打开
shelfFile['valueName'] = value # 写入
shelfFile.close() # 关闭
# 或者用pprint.formant来输出.py
# 然后再import
A little bit handy
import os
import shutil # 用来复制文件和文件夹
import send2trash # 放到回收站 pip install send2trash
shutil.copy(source, destination) # 复制文件
shutil.move(source, destination) # 移动文件, 也可以用来重命名
os.unlink(path) # 删除文件
os.rmdir(path) # 删除空文件夹
shutil.rmtree(path) # 删除文件夹(包括内容)
send2trash.send2trash(path) # 放到回收站
for folderName, subfolders, filename in os.walk(path):
# 历遍文件树, 建议不要在里面删除文件, 还是新建一个列表然后再循环
Documents
ZIP
import zipfile # zip 文件访问
zipf = zipfile.ZipFile(path) # 读取文件
zipf.namelist() # 返回文件列表
zipf.getinfo(path).file_size # 文件大小
zipf.getinfo(path).compress_size # 压缩大小
zipf.extractall() # 把文件全部解压到当前文件夹
zipf.extract(path) # 解压文件到当前文件夹
zipf.extract(path, toPath) # 解压到toPath
zipf = zipfile.ZipFile(path, 'w')# 新建文件夹
zipf.write(path, compress_type=zipfile.ZIP_DEFLATED)
# 把path地方的文件压缩到zip文件里
zipf.close
Excel
Picture
Debug
raise Exception('error message')
# 报错, 报错类型是Exception, 错误信息是error message
try:
# ...
except Exception as err:
print(str(err))
# str(err)就是文件的报错信息
断言 assert
##############2021.11.17 先停一下 下次继续################
assert condition, "massage"
# 当condition不成立的时候就抛出message然后退出程序
# 可以不用加上message
# assert没法用try和except来处理
# 在用-O选项启动的时候就会跳过assert
日志
import logging
目前好像没有什么会用到日志的需求, 所以就不再学下去了.
调试器
可以设置断点和查看代码中的变量值. 目前还不是很会.
Command Line
系统调用传入的参数在python
import sys
sys.argv # 一个包含参数的列表
Web
不愧是流行的语言, python在这些方面真的是很完善.
爬虫的框架真的超级多:
webbrowserrequestsBeautiful SoupseleniumHTTP
之所以用
http这个标题, 是因为我觉得上面的这些框架都和ruby的net/http很像.
(虽然python的这些框架都很便利. )
webbrowser
import webbrowser
webbrowser.open("url")
request
import request
res = request.get("url") # 获得网页
res.raise_for_status() # 检查下载的文件
# 假如有问题的话就会抛出异常, 否则就什么也不做
# 比如会放出requests.exceptioins.HTTPError
# 书里面建议在get后面都加上这一句话
# 在ruby里面的open-uri好像是只要有问题, 直接就爆炸(报错)
# 下载的文件要保存到电脑中时, 就要用二进制写入的模式
# 和ruby不同的地方是, ruby的open-uri在小文件的时候会返回String类,
# 里面包含网页文件的数据, 在大文件的时候, 则会返回IO对象
file = open(path, 'wb')
# file.write(res)
for buff in res.iter_content(size):
file.write(buff)
file.close
据说这里有一个老梗,
大概是因为python的urllib写得实在是太复杂了,
所以虽然它一直在更新, 但是还是挡不住广大的群众使用urllib.
(悲惨的是, ruby里面几乎也没什么好的,
有一个比较早的open-uri, 现在几乎都没更新了,
也没有很好的功能, 要访问的话还是用net\http厉害,
但是我觉得open-uri在简单使用的话还是可以接受的. )
BeautifulSoup
(我知道了解一点HTML语言和javascript等的东西很重要,
但是我目前遇到的爬虫往往是静态网页, 所以暂时没有动态网页的需要,
假如遇到了的话再说吧, 现在就用三脚猫功夫来糊弄一下先. :p)
import bs4
# 假如有一个res = requests.get(url)
p = bs4.BeautifulSoup(res) # 处理
e = p.select("div") # CSS选择器
str(e) # 输出
e.get('id') # tag上的标志attr
e.attrs # attr的一个字典
实际上这个模块和ruby中的nokogiri是很像的,
虽然在ruby cookbook里面提供了一个HTML的库,
但是那个库太旧了, 并且也不好用.
(哦, 其实如果正则表达式很强的话, 可以直接用正则表达式来, 当然, 一般是用来处理很小的或者是一点点的匹配任务. )
selenium
好像是一种通过调用游览器内部提供的接口, 进行自动化遥控游览器来操作网页, 实际上很值得学习.
(我记得好像有无头版本的…)
##############2021.11.18 再停一下 去搞ruby################