Python实战之自动化评论
最后更新于:2022-04-01 16:23:22
# Python实战之自动化评论
玩csdn博客一个多月了,渐渐发现了一些有意思的事,经常会有人用同样的评论到处刷,不知道是为了加没什么用的积分,还是纯粹为了表达楼主好人。那么问题来了,这种无聊的事情当然最好能够自动化咯,自己也来试了一把,纯属娱乐。
### 登陆
要评论当然要能够先进行登陆,采用 [requests](http://docs.python-requests.org/en/latest/) 库进行处理,尝试能否看到自己的消息列表:
~~~
msg_url ="http://msg.csdn.net/"
r = requests.get(msg_url, auth=('drfish', 'password'))
~~~
结果跳转到登陆界面,好的那看一下登陆界面是怎么登陆的,找到表单:
![csdn-login-form](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571879cd557af.jpg "")
发现还有一些隐藏的参数,如lt、excution等,好心的程序猿还写明了不能为什么不能直接认证的原因:缺少流水号,那就多访问一次来获取流水号好了,用 [BeautifulSoup](http://www.crummy.com/software/BeautifulSoup/bs4/doc/) 来分析页面内容抓取流水号,同时因为要跨不同的域来进行操作,所以引入session:
~~~
msg_url = "http://msg.csdn.net/"
login_url = "https://passport.csdn.net/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
session = requests.session()
session.headers.update(headers)
r = session.get(login_url)
page = BeautifulSoup(r.text, "lxml")
authentication = {
"username": "drfish",
"password": "password",
"lt": page.select("[name=lt]")[0]["value"],
"execution": page.select("[name=execution]")[0]["value"],
"_eventId": "submit",
}
r = session.post(login_url, authentication)
r2 = session.get(msg_url)
print(r2.text)
~~~
好了,现在能够得到我的消息信息了,说明已经成功解决登陆问题,那么自动化水军评论应该就近在眼前了。
### 自动评论
这次学乖了,随便找了篇文章直接查看评论框form:
![csdn-comment-form](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571879cd786e5.jpg "")
在上面登陆代码的基础上进行评论的提交:
~~~
blog_url = "http://blog.csdn.net/u013291394/comment/submit?id=50444369"
comment = {
"comment_content": "水军评论测试",
"comment_usrId":"531203"
}
r2 = session.post(blog_url, comment)
print(r2.text)
~~~
结果返回了 `{"result":0,"content":"评论内容没有填写!","callback":null,"data":null}` 这样的结果。有点意思,应该是在js中对参数进行了处理。那就把js拉出来看看,网页里搜了一下js文件,有个 [comment.js](http://static.blog.csdn.net/scripts/comment.js) ,就是它了。在上面的form中可以看到提交时调用了subform方法,查看方法如下:
~~~
function subform(e) {
if (c_doing) return false;
var content = $.trim($(editorId).val());
if (content == "") {
commentTip("评论内容没有填写!");
return false;
} else if (content.length > 1000) {
commentTip("评论内容太长了,不能超过1000个字符!");
return false;
}
var commentId = $("#commentId").val();
commentTip("正在发表评论...");
var beginTime = new Date();
$(editorId).attr("disabled", true);
$("button[type=submit]", e).attr("disabled", true);
c_doing = true;
$.ajax({
type: "POST",
url: $(e).attr("action"),
data: {
"commentid": commentId,
"content": content,
"replyId": $("#comment_replyId").val(),
"boleattohome": $("#boleattohome").val()
},
success: function (data) {
c_doing = false;
commentTip(data.content);
if (data.result) {
var rcommentid=$("#comment_replyId").val()
$(editorId).val('');
$("#comment_replyId,#comment_verifycode").val('');
commentscount++;
loadList(1, true);
$(editorId).attr("disabled", false);
$("button[type=submit]", e).attr("disabled", false);
commentTip("发表成功!评论耗时:" + (new Date() - beginTime) + "毫秒")
if (rcommentid!=undefined && rcommentid != "")
{
$("html,body").animate({ scrollTop: $("#comment_item_" + rcommentid).offset().top }, 1000);
}
}
}
});
return false;
}
~~~
可以清楚的看到最后POST提交的数据 `data` 改变了参数的名字,还有几个其他的参数通过看js文件可以看到不是空的就是定死的,就不用管他了。同时发现上的 `"comment_usrId"` 也是给死的?那就只要comment一个变量就搞定了。
~~~
blog_url = "http://blog.csdn.net/u013291394/comment/submit?id=50444369"
comment = {
"content": "水军评论测试",
}
r2 = session.post(blog_url, comment)
print(r2.text)
~~~
看一下效果:
![![csdn-auto-comment][]](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571879cda9521.jpg "")
### 自动化
当然上面最终的参数传递也可以自己手动评论并用抓包软件抓取,不过通过查看 `commetn.js` 文件也给我的自动化评论提供了方向,其中有一个 `load_comment_form()` 方法,是用来加载comment-form的,它给出了action的定义:
`action="/' + username + '/comment/submit?id=' + fileName + '"`
写的很明白了,我只要抓取到页面的作者名和文章的编号就可以尽情的水评论了,随便选个抓取文章的入口,如最新博客入口 [http://blog.csdn.net/?ref=toolbar_logo](http://blog.csdn.net/?ref=toolbar_logo) ,用BeautifulSoup抓取url并解析取到其中的username和filename来构成action并提价评论。
运行脚本试一下效果:
![csdn-comment-example](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571879cdbe3a9.jpg "")
打开评论管理看一下:
![example](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571879cdd4f90.jpg "")
自动化评论成功。
### 写在最后
写这篇文章只是为了证明一下自己的想法,不是用来也**不希望有人用来恶意刷评论**。
- 本文由 DRFish([http://www.drfish.me/](http://www.drfish.me/))原创,转载请写明原链接,谢谢。
需要参考源码请访问我的[Github](https://github.com/gavinfish/Awesome-Python/tree/master/HotBlog) ([https://github.com/gavinfish/Awesome-Python/tree/master/HotBlog](https://github.com/gavinfish/Awesome-Python/tree/master/HotBlog))。
每天学点Python之collections
最后更新于:2022-04-01 16:23:19
# 每天学点Python之collections
collections模块在内置数据类型([dict](http://blog.csdn.net/u013291394/article/details/50379798)、[list](http://blog.csdn.net/u013291394/article/details/50364856)、[set](http://blog.csdn.net/u013291394/article/details/50371760)、[tuple](http://blog.csdn.net/u013291394/article/details/50371783))的基础上,提供了几个额外的数据类型:ChainMap、Counter、deque、defaultdict、namedtuple和OrderedDict等。
### ChainMap
ChainMap是python3的新特性,它用来将多个map组成一个新的单元(原来的map结构仍然存在,类似于这些map被存在了一个list之中),这比新建一个map再将其他map用update加进来快得多。通过ChainMap可以来模拟嵌套的情景,而且多用于模板之中。
ChainMap支持普通map的所有操作,下面主要展示一下它的特性:
~~~
# 新建ChainMap及它的结构
In[2]: from collections import ChainMap
In[3]: m1 = {'color': 'red', 'user': 'guest'}
In[4]: m2 = {'name': 'drfish', 'age': '18'}
In[5]: chainMap = ChainMap(m1, m2)
In[6]: print(chainMap.items())
ItemsView(ChainMap({'user': 'guest', 'color': 'red'}, {'age': '18', 'name': 'drfish'}))
# 获取ChainMap中的元素
In[7]: print(chainMap.get('name'))
drfish
In[8]: print(chainMap.get('not'))
None
# 新增map
In[9]: m3 = {'data': '1-6'}
In[10]: chainMap = chainMap.new_child(m3)
In[11]: print(chainMap.items())
ItemsView(ChainMap({'data': '1-6'}, {'user': 'guest', 'color': 'red'}, {'age': '18', 'name': 'drfish'}))
# parents属性
In[12]: print(chainMap.parents)
ChainMap({'user': 'guest', 'color': 'red'}, {'age': '18', 'name': 'drfish'})
In[13]: print(chainMap.parents.parents)
ChainMap({'age': '18', 'name': 'drfish'})
In[14]: print(chainMap.parents.parents.parents)
ChainMap({})
# maps属性
In[15]: chainMap.maps
Out[15]:
[{'data': '1-6'},
{'color': 'red', 'user': 'guest'},
{'age': '18', 'name': 'drfish'}]
~~~
- 可以传入多个map来初始化ChainMap,如参数为空,会自动加入一个空的map
- 获取的key如果不存在,则返回None
- 可以通过net_child()方法来新增map,新的map添加在前面
- parents属性返回除去第一个map后的ChainMap实例。
### Counter
Counter是一个简单的计数器,使用起来非常方便。
**初始化**
Counter的初始化支持多种形式
~~~
In[18]: from collections import Counter
In[19]: c = Counter()
In[20]: c = Counter('hello')
In[21]: c = Counter({'a':3,'b':19})
In[22]: c = Counter(cats=2,dogs=1)
In[23]: c
Out[23]: Counter({'cats': 2, 'dogs': 1})
~~~
Counter对于不存在的元素会返回0,如果要删除则需要用到del:
~~~
In[23]: c
Out[23]: Counter({'cats': 2, 'dogs': 1})
In[24]: c['birds']
Out[24]: 0
In[25]: del c['cats']
In[26]: c
Out[26]: Counter({'dogs': 1})
~~~
elements()方法会返回所有的元素,有几个就返回几个;而most_common(n)方法可以返回数量排前n的元素及其数目:
~~~
In[29]: c = Counter(a=4, b=2, c=0, d=-2)
In[30]: list(c.elements())
Out[30]: ['a', 'a', 'a', 'a', 'b', 'b']
In[33]: c.most_common(1)
Out[33]: [('a', 3)]
~~~
不同的Counter之间还可以进行运算操作,subtract()方法进行减法后会影响调用方;`&`操作表示取两个中数目小的一个(如果只在一个Counter中存在,则结果集中也没有),`|`操作取数目大的。
~~~
In[46]: c = Counter(a=13, b=11)
In[47]: d = Counter(a=1, b=2)
In[48]: c.subtract(d)
In[49]: c
Out[49]: Counter({'a': 12, 'b': 9})
In[51]: c+d
Out[51]: Counter({'a': 13, 'b': 11})
In[52]: c-d
Out[52]: Counter({'a': 11, 'b': 7})
In[54]: c&d
Out[54]: Counter({'a': 1, 'b': 2})
In[55]: c|d
Out[55]: Counter({'a': 12, 'b': 9})
~~~
> 注:进行运算操作时,如果数目结果为负的会被直接忽略
### deque
deque就是一个双端队列,与list非常相似,不过可以同时在list的左边增删元素:
~~~
In[72]: dq = deque('abd')
In[73]: dq
Out[73]: deque(['a', 'b', 'd'])
In[74]: dq.append('1')
In[75]: dq.appendleft('-1')
In[76]: dq
Out[76]: deque(['-1', 'a', 'b', 'd', '1'])
In[77]: dq.popleft()
Out[77]: '-1'
In[78]: dq.extendleft("hello")
In[79]: dq
Out[79]: deque(['o', 'l', 'l', 'e', 'h', 'a', 'b', 'd', '1'])
~~~
注意extendleft(x)方法相当于先把x翻转后在添加到列表前端。然后比较好用的是rotate方法,可以使队列中的元素顺序前移或者后移:
~~~
In[82]: dq=deque("12345")
In[83]: dq
Out[83]: deque(['1', '2', '3', '4', '5'])
In[84]: dq.rotate(2)
In[85]: dq
Out[85]: deque(['4', '5', '1', '2', '3'])
In[86]: dq.rotate(-4)
In[87]: dq
Out[87]: deque(['3', '4', '5', '1', '2'])
~~~
### defaultdict
defaultdict在普通的dict之上添加了默认工厂,使得键不存在时会自动生成相应类型的值:
~~~
In[88]: from collections import defaultdict
In[89]: d = defaultdict(int)
In[90]: d['a']
Out[90]: 0
In[91]: d = defaultdict(dict)
In[92]: d['a']
Out[92]: {}
~~~
如果初始化时没有加入默认工厂,则同样会抛出KeyError错误:
~~~
In[93]: d = defaultdict()
In[94]: d['a']
Traceback (most recent call last):
d['a']
KeyError: 'a'
~~~
### namedtuple
namedtuple是tuple的加强版本,最大的作用就是给tuple的每个位置的值设置了别名,增加了程序的可读性:
~~~
In[95]: from collections import namedtuple
In[96]: Point = namedtuple("Point",['x','y'])
In[97]: p = Point(1,2)
In[98]: p.x
Out[98]: 1
In[99]: p.y
Out[99]: 2
~~~
由于有了别名,相当于形成了一个字典,namedtuple可以转化为下面要介绍的OrderedDict,同时也可以通过字典转化而来:
~~~
In[100]: p._asdict()
Out[100]: OrderedDict([('x', 1), ('y', 2)])
In[101]: d = {'x':11,'y':22}
In[102]: Point(**d)
Out[102]: Point(x=11, y=22)
~~~
namedtuple也提供了获取所有域及修改相应值的方法:
~~~
In[108]: p
Out[108]: Point(x=1, y=2)
In[109]: p._fields
Out[109]: ('x', 'y')
In[110]: p._replace(x=10)
Out[110]: Point(x=10, y=2)
~~~
### OrderedDict
dict是无序,但有时我们希望字典是有序的,OrderedDict提供了这项服务,OrderedDict中的键值对是按照他们加入时的顺序存储的:
~~~
In[130]: fruit=(('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1))
In[131]: d = dict(fruit)
In[132]: d
Out[132]: {'apple': 4, 'banana': 3, 'orange': 2, 'pear': 1}
In[135]: d.popitem()
Out[135]: ('apple', 4)
In[136]: d.popitem()
Out[136]: ('orange', 2)
In[137]: d.popitem()
Out[137]: ('banana', 3)
In[138]: d.popitem()
Out[138]: ('pear', 1)
In[133]: od = OrderedDict(fruit)
In[134]: od
Out[134]: OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
In[139]: od.popitem()
Out[139]: ('pear', 1)
In[140]: od.popitem()
Out[140]: ('orange', 2)
In[141]: od.popitem()
Out[141]: ('banana', 3)
In[142]: od.popitem()
Out[142]: ('apple', 4)
~~~
> 注:OrderedDict中popitem(last=True)函数如果last设置为False,则先加入的先弹出
可以通过move_to_end(key, last=True)函数来改变键值对的位置,True时移到末尾,False移到开头:
~~~
In[146]: od
Out[146]: OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
In[147]: od.move_to_end('apple')
In[148]: od
Out[148]: OrderedDict([('banana', 3), ('orange', 2), ('pear', 1), ('apple', 4)])
In[149]: od.move_to_end('pear',False)
In[150]: od
Out[150]: OrderedDict([('pear', 1), ('banana', 3), ('orange', 2), ('apple', 4)])
~~~
百度URL参数解析
最后更新于:2022-04-01 16:23:17
# 百度URL参数解析
在用Python爬取百度搜索的内容时,发现百度搜索的url非常的长,往往会跟一大段的参数,但其实很多参数都是没有必要的,如同样是搜索java关键字,可以通过 `http://www.baidu.com/s?wd=java` 如此简单的URL来获取,而下面这个超级复杂的URL也是同样进行了关键字java的搜索:
~~~
http://www.baidu.com/s?wd=java&rsv_spt=1&rsv_iqid=0xd3c8c51900052eb3&issp=1&f=8
&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&oq=python%20org&inputT=801
&rsv_t=8810tNAXi7Yc2PivScHthQ7bBz%2B4eIBHvrdmB59u%2FlLVYrhnyyTg1%2FYJzQM9EAEgSPn5
&rsv_pq=8f0a85f900051202&rsv_sug3=15&rsv_sug2=0&rsv_sug7=000&rsv_sug4=801&rsv_sug=2
~~~
那么后面的那么多的参数有什么用呢?
**wd**
查询关键字,就是你要搜索的内容。
**rn**
搜索结果页每页显示的数目,默认为10,最大可以设置为50
**pn**
显示结果的页数,缺省为0,其它页面需要每页递增rn,如当rn为默认值时,第三页的pn应为20。
**ie**
查询关键字的编码格式,默认为gb2312,即为简体中文
**tn**
提交的搜索请求的来源,我们经常可以看到很多网站上都有嵌入了百度的搜索框,这个参数可以确定当前的搜索是来自哪个网站的。如下面的URL就是通过www.hao123.com网站首页的百度搜索框搜索得到的:
`https://www.baidu.com/s?word=java&tn=sitehao123&ie=utf-8`
> 注:我们可以看到很多参数其实都是缩写,如wd用word也是可以的
**rsv_bp**
这是表示了是百度网页上的哪一个搜索框,如通过百度首页中间的搜索框进行搜索时,该值为0,在搜索结果页上面的搜索框进行搜索时为1。
**rsv_spt**
这个参数具体含义不是很清楚,经过测试可以看出来登录了百度账号且在首页进行搜索时会有这个参数,且值为1,如果没有登录或登录后在搜索结果页搜索时不会出现这个参数。网上查找了一些资料,感觉比较靠谱的是这表示首页搜索类型,1表示新版百度首页搜索(先要登录百度帐号),2表示百度实时热点搜索(先要登录百度帐号),3表示传统百度首页搜索。
**cl**
这个参数是提交的搜索类型,如搜索网页时为3,搜索新闻时为2
**oq**
这个关键词网上有些帖子说是搜索下拉栏相关的,但根据我的测试,这个参数现在好像就仅仅代表上次的搜索关键字。
还有很多参数如rsv_**这些参数的意义不是很明确,此外上面的参数测试可能也不是很全面,理解可能也有偏差,如有错误,欢迎交流。
每天学点Python之zip
最后更新于:2022-04-01 16:23:15
# 每天学点Python之zip
zip是Python中的一个内建函数,能够用来组合多个序列类型的数据。它会把传入的所有序列中下标相同的元素组成一个个元组,以最短的序列为基准。
### 压缩
所有的序列类型都可以进行压缩,最终的长度以最短的序列长度为准,不过字典在压缩时只会保存的它的键:
~~~
In[13]: a = [1,2,3]
In[14]: b = "abcde"
In[15]: c = {"one":1,"two":2}
In[16]: z = zip(a,b,c)
In[17]: print(z)
<zip object at 0x00000000041DCEC8>
In[18]: list(z)
Out[18]: [(1, 'a', 'one'), (2, 'b', 'two')]
~~~
如果只有一个序列压缩,那么同样会返回元组:
~~~
In[19]: a = [1,2,3]
In[20]: z = zip(a)
In[21]: list(z)
Out[21]: [(1,), (2,), (3,)]
~~~
### 解压
如果需要对压缩过的对象进行解压,只需要在之前添加一个星号*:
~~~
In[39]: z = zip(*zip("hello"))
In[40]: list(z)
Out[40]: [('h', 'e', 'l', 'l', 'o')]
~~~
### 示例
下面两小段代码是一个意思,都是将列表进行分段:
~~~
In[64]: list(zip(*[iter(seq)]*3))
Out[64]: [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
In[57]: x = iter(range(1, 10))
In[58]: list(zip(x,x,x))
Out[58]: [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
~~~
下面这个例子是将列表中的数据项进行复制扩展:
~~~
In[43]: x = [1, 2, 3]
In[44]: list(zip(*[x]*3))
Out[44]: [(1, 1, 1), (2, 2, 2), (3, 3, 3)]
~~~
下面这个例子是通过zip来进行字典的键值对翻转:
~~~
In[49]: m = {"a":1, "b":2, "c":3}
In[50]: r = dict(zip(m.values(),m.keys()))
In[51]: r
Out[51]: {1: 'a', 2: 'b', 3: 'c'}
~~~
每天学点Python之bytes
最后更新于:2022-04-01 16:23:13
# 每天学点Python之bytes
Python中的字节码用`b'xxx'`的形式表示。x可以用字符表示,也可以用ASCII编码形式`\xnn`表示,nn从00-ff(十六进制)共256种字符。
### 基本操作
下面列举一下字节的基本操作,可以看出来它和字符串还是非常相近的:
~~~
In[40]: b = b"abcd\x64"
In[41]: b
Out[41]: b'abcdd'
In[42]: type(b)
Out[42]: bytes
In[43]: len(b)
Out[43]: 5
In[44]: b[4]
Out[44]: 100 # 100用十六进制表示就是\x64
~~~
如果想要修改一个字节串中的某个字节,不能够直接修改,需要将其转化为bytearray后再进行修改:
~~~
In[46]: barr = bytearray(b)
In[47]: type(barr)
Out[47]: bytearray
In[48]: barr[0] = 110
In[49]: barr
Out[49]: bytearray(b'nbcdd')
~~~
### 字节与字符的关系
上面也提到字节跟字符很相近,其实它们是可以相互转化的。字节通过某种编码形式就可以转化为相应的字符。字节通过encode()方法传入编码方式就可以转化为字符,而字符通过decode()方法就可以转化为字节:
~~~
In[50]: s = "人生苦短,我用Python"
In[51]: b = s.encode('utf-8')
In[52]: b
Out[52]: b'\xe4\xba\xba\xe7\x94\x9f\xe8\x8b\xa6\xe7\x9f\xad\xef\xbc\x8c\xe6\x88\x91\xe7\x94\xa8Python'
In[53]: c = s.encode('gb18030')
In[54]: c
Out[54]: b'\xc8\xcb\xc9\xfa\xbf\xe0\xb6\xcc\xa3\xac\xce\xd2\xd3\xc3Python'
In[55]: b.decode('utf-8')
Out[55]: '人生苦短,我用Python'
In[56]: c.decode('gb18030')
Out[56]: '人生苦短,我用Python'
In[57]: c.decode('utf-8')
Traceback (most recent call last):
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-57-8b50aa70bce9>", line 1, in <module>
c.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 0: invalid continuation byte
In[58]: b.decode('gb18030')
Out[58]: '浜虹敓鑻︾煭锛屾垜鐢≒ython'
~~~
我们可以看到用不同的编码方式解析出来的字符和字节的方式是完全不同,如果编码和解码用了不同的编码方式,就会产生乱码,甚至转换失败。因为每种编码方式包含的字节种类数目不同,如上例中的`\xc8`就超出了utf-8的最大字符。
### 应用
举个最简单的例子,我要爬取一个网页的内容,现在来爬取用百度搜索Python时返回的页面,百度用的是utf-8编码格式,如果不对返回结果解码,那它就是一个超级长的字节串。而进行正确解码后就可以显示一个正常的html页面。
~~~
import urllib.request
url = "http://www.baidu.com/s?ie=utf-8&wd=python"
page = urllib.request.urlopen(url)
mybytes = page.read()
encoding = "utf-8"
print(mybytes.decode(encoding))
page.close()
~~~
每天学点Python之strings
最后更新于:2022-04-01 16:23:10
# 每天学点Python之strings
在Python3中所有的字符编码都是Unicode,所以不用再担心编码问题了。
### 基本操作
在Python中字符串可以用单引号或者双引号中包含字符来表示,下面列一下最最基本的操作,分别是赋值、求长度、特定位置的字符和字符串连接:
~~~
In[5]: s = "hello world"
In[6]: len(s)
Out[6]: 11
In[7]: s[0]
Out[7]: 'h'
In[8]: s + '!'
Out[8]: 'hello world!'
~~~
如果字符串很长,要跨越多行,可以用三引号将内容包含进来:
~~~
In[32]: s = '''a
... b
... c
... '''
In[33]: s
Out[33]: 'a\nb\nc\n'
~~~
> 注:命令前的In/Out[n]只是表示第几条命令,没有实际意义
### 格式化
Python的字符串格式化非常简单,在需要插入值的地方用{n}表示,直接调用format()函数并传入相应的参数即可,注意下标是从0开始的,而且传入的参数必须大于等于需要的参数数目(多传入的会被忽略):
~~~
In[10]: s = 'my name is {0}, my age is {1}'
In[11]: s.format('drfish',20)
Out[11]: 'my name is drfish, my age is 20'
In[12]: s.format('drfish')
Traceback (most recent call last):
File "<ipython-input-12-305d7c657a14>", line 1, in <module>
s.format('drfish')
IndexError: tuple index out of range
In[13]: s.format('drfish',20,22)
Out[13]: 'my name is drfish, my age is 20'
~~~
如果参数非常多,用数字来表示容易产生混乱,可以使用别名表示:
~~~
In[28]: '{name} is {age}. '.format(name="drfish", age=22)
Out[28]: 'drfish is 22. '
~~~
再来看复杂一点的,输如的参数不仅仅是简单的值替换,而能在字符串中对其进行后续处理,如传入一个字典,可以对其取某个键的值,同理还可以使用一些复杂的对象的方法属性:
~~~
In[22]: s = 'my name is {0[name]}, my age is {0[age]}'
In[23]: s.format({"name":"drfish","age":20})
Out[23]: 'my name is drfish, my age is 20'
~~~
此外还能对输出的格式进行规定:
~~~
# 保留小数点后4位
In[26]: '{0:.4} is a decimal. '.format(1/3)
Out[26]: '0.3333 is a decimal. '
# 用'_'补齐字符串
In[27]: '{0:_^11} is a 11 length. '.format("drfish")
Out[27]: '__drfish___ is a 11 length. '
# 指定宽度
In[30]: 'My name is {0:8}.'.format('drfish')
Out[30]: 'My name is drfish .'
~~~
### 常用方法
**大小写**
字符串可以直接进行大小写的判断与转换:
~~~
In[34]: 'hello'.upper()
Out[34]: 'HELLO'
In[35]: 'Hello'.lower()
Out[35]: 'hello'
In[36]: 'Hello'.isupper()
Out[36]: False
~~~
**分割**
分割函数str.split()可以接收两个参数,一个是分割符,另一个是进行分割的数目:
~~~
In[37]: 'a=1,b=2,c=3'.split('=',2)
Out[37]: ['a', '1,b', '2,c=3']
~~~
**计数**
统计一个字符串中的某字符串的数目:
~~~
In[38]: "ab c ab".count("ab")
Out[38]: 2
~~~
**截取**
截取操作与列表相同:
~~~
In[39]: "hello world"[3:8]
Out[39]: 'lo wo'
~~~
每天学点Python之comprehensions
最后更新于:2022-04-01 16:23:08
# 每天学点Python之comprehensions
推导式可以简化对数据的处理,让代码简洁的同时还具有很高的可读性,这在Python中非常常见。
### 列表推导式
通过列表推导式可以对列表中的所有元素都进行统一的操作来获得一个全新的列表(原列表不发生变化),形式如`[处理方式 for 元素 in 列表]`,其中的处理方式可以是任何操作:
~~~
>>> a=[1,2,3,4]
>>> [i*2 for i in a]
[2, 4, 6, 8]
>>> a
[1, 2, 3, 4]
>>> [(i*2,i+10) for i in a]
[(2, 11), (4, 12), (6, 13), (8, 14)]
~~~
可以通过加上if语句来过滤掉原列表中的一些元素:
~~~
>>> a=[1,2,3,4]
>>> [i*2 for i in a if i>2]
[6, 8]
~~~
### 字典推导式
我们可以通过推导式来创建一个字典,不过字典推导式的括号是花括号:
~~~
>>> a
[1, 2, 3, 4]
>>> { "str"+str(i):i for i in a }
{'str3': 3, 'str1': 1, 'str4': 4, 'str2': 2}
~~~
运用字典推导式有一个妙用,就是可以调换键和值的位置:
~~~
>>> a={'one':1,"two":2,"three":3}
>>> {value:key for key,value in a.items()}
{1: 'one', 2: 'two', 3: 'three'}
~~~
> 注:确保值也是不可变类型,例如字符串、元组等
### 集合推导式
集合推导式与字典推导式类似,不过只有一个值而不是键值对:
~~~
>>> a={1,2,3,4,5}
>>> {i**2 for i in a if i%2==1}
{1, 9, 25}
~~~
每天学点Python之Iterator
最后更新于:2022-04-01 16:23:06
# 每天学点Python之Iterator
我们经常需要遍历一个对象中的元素,在Python中这种功能是通过迭代器来实现的。
### 原理
每一个迭代器可以通过反复调用迭代器的__next__()方法来返回创建该迭代器的对象中的后继值。当没有可用数据时,产生一个StopInteration异常。此时,迭代器对象被耗尽,之后再调用 __next__()方法只会再次产生StopInteration异常。需要访问的对象要求包含一个__iter__()方法,用于返回迭代器对象,如果对象就实现了迭代器方法,就可以返回对象本身。
### 使用
我们可以通过调用iter()方法来返回对象的迭代器:
~~~
>>> i = iter("hello")
>>> i.__next__()
'h'
>>> next(i)
'e'
>>> next(i)
'l'
>>> next(i)
'l'
>>> next(i)
'o'
>>> next(i)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
~~~
对于Python中常见的一些数据类型,如元组、列表、字典等都已经自己实现了迭代器功能,这使得它们能在for循环中正常工作:
~~~
>>> for i in (2,3,1):
... print(i)
...
2
3
1
~~~
### 自定义
如果我们要求自定义访问对象中的数据,那该如何做呢,我们需要实现__iter()__和__next()__方法,下面我们给出自己的对象,实现一个简易的计时器功能:
~~~
class CountDown:
def __init__(self, start):
self.count = start
def __iter__(self):
return self
def __next__(self):
if self.count <= 0:
raise StopIteration
r = self.count
self.count -= 1
return r
if __name__ == "__main__":
for time in CountDown(3):
print(time)
输出:3 2 1
~~~
每天学点Python之dict
最后更新于:2022-04-01 16:23:03
# 每天学点Python之dict
字典用来存储键值对,在Python中同一个字典中的键和值都可以有不同的类型。
### 字典的创建
创建一个空的字典有两种方法:
~~~
d = {}
d = dict()
~~~
而创建一个包含元素的字典方法比较多,下面操作结果相同:
~~~
>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
~~~
### 字典的查询
获取字典中的值只需通过dict[key]来获取,如果不存在该键,会抛出KeyError错误;也可用`dict.get(k[,default])`方法来获取,这个方法即使键不存在也不会抛出错误,也可以给一个默认的值,在键值对不存在时返回:
~~~
>>> a = dict(one=1, two=2, three=3)
>>> a['one']
1
>>> a['four']
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 'four'
>>> a.get('four')
>>> a.get('four',4)
4
~~~
### 字典的修改
要修改字典中的键对应的值,只需要取出来直接对它赋值就行,需要注意的是,如果修改的键原来不存在,就变成了向字典中增加了一个键值对:
~~~
>>> a = dict(one=1, two=2, three=3)
>>> a['one']=10
>>> a
{'two': 2, 'one': 10, 'three': 3}
>>> a['four']=4
>>> a
{'two': 2, 'four': 4, 'one': 10, 'three': 3}
~~~
而`dict.setdefault(key[,default])`在key存在时,不做修改返回该值,如果不存在则添加键值对(key, default),其中default默认为None:
~~~
>>> a = dict(one=1, two=2, three=3)
>>> a.setdefault('one')
1
>>> a
{'two': 2, 'one': 1, 'three': 3}
>>> a.setdefault('four')
>>> a
{'two': 2, 'four': None, 'one': 1, 'three': 3}
~~~
批量增加有`dict.update(p)`方法。
### 字典的删除
如果要删除一个键值对,直接用del方法,试图删除一个不存在的键值对会抛出KeyError错误:
~~~
>>> a
{'two': 2, 'four': 4, 'one': 10, 'three': 3}
>>> del a['four']
>>> a
{'two': 2, 'one': 10, 'three': 3}
>>> del a['four']
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 'four'
~~~
此外同样可以调用dict.clear()来清空字典。还有`dict.pop(key[,default])`和`dict.popitem()`,这两个一个是弹出特定键对应的键值对,另一个弹出任意的一个键值对:
~~~
>>> a
{'two': 2, 'one': 10, 'three': 3}
>>> a.pop("one")
10
>>> a
{'two': 2, 'three': 3}
>>> a.popitem()
('two', 2)
>>> a
{'three': 3}
~~~
### 字典的集合
字典可以分别返回它所有的键值对、键和值,它们的类型都是字典内置类型,可以通过list()转化为列表:
~~~
>>> a = dict(one=1, two=2, three=3)
>>> a
{'two': 2, 'one': 1, 'three': 3}
>>> a.items()
dict_items([('two', 2), ('one', 1), ('three', 3)])
>>> a.values()
dict_values([2, 1, 3])
>>> a.keys()
dict_keys(['two', 'one', 'three'])
>>> list(a.keys())
['two', 'one', 'three']
~~~
每天学点Python之tuple
最后更新于:2022-04-01 16:23:01
# 每天学点Python之tuple
元组就是一个增加了限制的列表,主要的区别就是元组一旦确定就不能再修改。它们可以通过各自的构造函数相互转化。
### 优势
元组与列表非常相似,但它有自己的优势:
- 元组比列表速度快,同样遍历一串数值,元组的速度比类表快
- 创建安全的变量,有些变量不想在创建后被修改
- 元组是可以当作字典的键和集合的值的,列表由于是变化的,哈希值不确定而不可以
### 元组的创建
创建一个空的元组有两种方法:
~~~
t = ()
t = tuple()
~~~
而创建一个包含元素的元组同样有两种方法,下面操作结果相同:
~~~
t = ("a", "b", "c")
t = tuple("abc")
~~~
需要注意的是,tuple方法最多只能有一个参数,也就是说不能将元素依次当做参数传入。它只接受可迭代的对象作为其参数。
> 注:只包含一个元素的元组用()定义时,要加逗号,如`(2,)`
### 元组的截取
元组的截取规则与列表相同,截取后的返回结果也是元组。具体请参看[列表](http://blog.csdn.net/u013291394/article/details/50364856)这一节。
### 元组的增加/删除
元组不支持增加与删除操作,会报AttributeError错误。
### 元组的查找
元组的查找操作也与列表相同。
### 多元赋值
在列表中忘记提这个特性了,Python支持多对多的赋值方式,左值的括号可以省略,但如果前后数目不等会抛出ValueError的错误:
~~~
>>> (x,y,z)=[2,3,4]
>>> x
2
>>> y
3
>>> z
4
>>> (x,y,z)=(2,3,4)
>>> x
2
>>> y
3
>>> x,y=(2,3,4)
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
~~~
每天学点Python之set
最后更新于:2022-04-01 16:22:59
# 每天学点Python之set
集合中包含一系列的元素,在Python中这些元素不需要是相同的类型,且这些元素在集合中是没有存储顺序的。
### 集合的赋值
集合的表示方法是花括号,这与字典是一样的,可以通过括号或构造函数来初始化一个集合,如果传入的参数有重复,会自动忽略:
~~~
>>> {1,2,"hi",2.23}
{2.23, 2, 'hi', 1}
>>> set("hello")
{'l', 'h', 'e', 'o'}
~~~
> 注:由于集合和字典都用`{}`表示,所以初始化空的集合只能通过`set()`操作,`{}`只是表示一个空的字典
### 集合的增加
集合元素的增加支持两种类型,单个元素的增加用add方法,对序列的增加用update方法。add的作用类似列表中的append,而update类似extend方法。update方法可以支持同时传入多个参数:
~~~
>>> a={1,2}
>>> a.update([3,4],[1,2,7])
>>> a
{1, 2, 3, 4, 7}
>>> a.update("hello")
>>> a
{1, 2, 3, 4, 7, 'h', 'e', 'l', 'o'}
>>> a.add("hello")
>>> a
{1, 2, 3, 4, 'hello', 7, 'h', 'e', 'l', 'o'}
~~~
> 注:增加已有的元素不会对集合产生影响,也不会抛出异常
### 集合的删除
集合删除单个元素有两种方法,两者的区别是在元素不在原集合中时是否会抛出异常,set.discard(x)不会,set.remove(x)会抛出KeyError错误:
~~~
>>> a={1,2,3,4}
>>> a.discard(1)
>>> a
{2, 3, 4}
>>> a.discard(1)
>>> a
{2, 3, 4}
>>> a.remove(1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 1
~~~
集合也支持pop()方法,不过由于集合是无序的,pop返回的结果不能确定,且当集合为空时调用pop会抛出KeyError错误,可以调用clear方法来清空集合:
~~~
>>> a={3,"a",2.1,1}
>>> a.pop()
1
>>> a.pop()
3
>>> a.clear()
>>> a
set()
>>> a.pop()
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 'pop from an empty set'
~~~
### 集合操作
- 并集:set.union(s),也可以用`a|b`计算
- 交集:set.intersection(s),也可以用`a&b`计算
- 差集:set.difference(s),也可以用`a-b`计算
需要注意的是Python提供了一个求对称差集的方法set.symmetric_difference(s),相当于两个集合互求差集后再求并集,其实就是返回两个集合中只出现一次的元素,也可以用`a^b`计算。
~~~
>>> a={1,2,3,4}
>>> b={3,4,5,6}
>>> a.symmetric_difference(b)
{1, 2, 5, 6}
~~~
set.update(s)操作相当于将两个集合求并集并赋值给原集合,其他几种集合操作也提供各自的update版本来改变原集合的值,形式如intersection_update(),也可以支持多参数形式。
### 包含关系
两个集合之间一般有三种关系,相交、包含、不相交。在Python中分别用下面的方法判断:
- set.isdisjoint(s):判断两个集合是不是不相交
- set.issuperset(s):判断集合是不是包含其他集合,等同于a>=b
- set.issubset(s):判断集合是不是被其他集合包含,等同于a<=b
如果要真包含关系,就用符号操作`>`和`<`。
### 不变集合
Python提供了不能改变元素的集合的实现版本,即不能增加或删除元素,类型名叫frozenset,使用方法如下:
~~~
>>> a = frozenset("hello")
>>> a
frozenset({'l', 'h', 'e', 'o'})
~~~
需要注意的是frozenset仍然可以进行集合操作,只是不能用带有update的方法。如果要一个有frozenset中的所有元素的普通集合,只需把它当作参数传入集合的构造函数中即可:
~~~
>>> a = frozenset("hello")
>>> a = set(a)
>>> a.add(12)
>>> a
{'l', 12, 'h', 'e', 'o'}
~~~
每天学点Python之数值类型
最后更新于:2022-04-01 16:22:57
# 每天学点Python之数值类型
Python中的数值类型包括int、float和complex三种类型。
> 注:以下内容只针对Python3
### int
Python中的int类型是无限精度的,这个特性给编程带来了很多便利。
### float
Python中的float底层是用c语言中double类型变量实现的,具体的精度与运行的计算机有关。可以通过变量`sys.float_info`查看,如我的计算机上的值:
~~~
>>> print(sys.float_info)
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
~~~
### complex
Python是支持虚数运算的,虚数的表示法为z=a+bj,其中a和b是float类型的数字。如果要单独获取a用z.real,单独获取b用z.imag。
### 混合运算
Python支持不同数值类型之间的运算,所有与complex型数值运算的结果都是complex,int型与float型运算结果为float型。如果需要对数值进行转型(可以从字符串转化),可以用int(),float()和complex()函数。int还支持将其他进制的字符串数值转为十进制:
~~~
>>> int("0213",8)
139
>>> int("0xa231",16)
41521
~~~
> 注:float()函数还支持nan,+inf,-inf作为参数,分别表示不是一个数字、正无穷和负无穷。
### 运算符
Python支持一般的加减乘除运算,需要注意的是除法运算返回的结果是float型的,即`2/1=2.0`。如果需要返回的是int型数值,需要使用`//`符号,这个符号相当于先做除法,再做floor()运算。以下再罗列一下特殊的运算符和函数:
**conjugate**
这是一个针对虚数的方法,用来求虚数的共轭虚数:
~~~
>>> (1+2j).conjugate()
(1-2j)
~~~
**divmod**
这个函数用来返回两个数的商和余数:
~~~
>>> divmod(7,3)
(2, 1)
~~~
**pow**
pow是用来求x的y次方的,在Python中还可以用**来实现相同的功能:
~~~
>>> pow(2,3)
8
>>> 2**3
8
~~~
> 注:在Python中0**0=1,只为了方便编写程序
**abs**
abs用来表示绝对值,但如果用在虚数上,则可以对虚数求模,获得一个float型的数值:
~~~
>>> abs(3-2j)
3.6055512754639896
~~~
### 数值精度
下面介绍Python用于数值精度方面的常用函数:
**math.trunc(x)**
保留x的整数部分,忽略小数点后的数。
**round(x[,n])**
对x进行四舍五入,保留n位小数。
**math.floor(x)**
小于等于x的最大整数。
**math.ceil(x)**
大于等于x的最小整数。
> 注:很多人会问trunc和floor的区别,其实对于正数,它们没什么区别,但对于负数请看:
~~~
>>> math.trunc(-2.9)
-2
>>> math.floor(-2.9)
-3
~~~
### 位移操作
针对int型的操作,没有什么特殊的,或操作(|)、异或操作(^)、且操作(&)、左移操作(<<)、右移操作(>>)、取反操作(~)。
说到位操作Python中有bin()函数可以将数字转为二进制。同时可以用int.bit_length()方法来获取二进制的长度:
~~~
>>> n = 16
>>> n.bit_length()
5
>>> bin(n)
'0b10000'
~~~
### float方法探究
下面罗列一下float中额外的一些方法:
**float.as_integer_ratio()**
将一个float用分数表示出来,返回的是一个二元元组。
**float.is_integer()**
判断一个float型数字是否是整数,返回布尔值。
**十六进制**
float与十六进制的转换是通过float.hex()和float.fromhex(s)实现的,具体看如下代码:
~~~
>>> float.hex(163.2)
'0x1.4666666666666p+7'
>>> float.fromhex('0x1.4666666666666p+7')
163.2
~~~
每天学点Python之list
最后更新于:2022-04-01 16:22:54
# 每天学点Python之list
Python中的列表对参数的类型没有要求,也就是说同一个列表可以包含多种不同类型的对象。
### 列表的创建
创建一个空的链表有两种方法:
~~~
l = []
l = list()
~~~
而创建一个包含元素的列表同样有两种方法,下面操作结果相同:
~~~
l = ["a", "b", "c"]
l = list("abc")
~~~
需要注意的是,list方法最多只能有一个参数,也就是说不能将元素依次当做参数传入。它只接受可迭代的对象作为其参数。
Python中对元素的编号也是从0开始的,比较方便的是Python支持便利地获取尾部的元素,如最后一个元素的编号可以用-1表示,可以理解为负数i会自动转化为length+i:
~~~
>>> a=[1,2,3,4,5]
>>> print(a[-1])
5
~~~
### 列表的截取
Python支持快速地获取连续的子列表操作list[a:b],截取a到b的部分作为新的列表。需要注意的是a的位置是包含的,而b位置的元素是不包含在内的。如果a省略,则从头开始,如果b省略,则一直包含到末尾:
~~~
>>> a
[1, 2, 3, 4, 5]
>>> a[1:3]
[2, 3]
>>> a[:3]
[1, 2, 3]
>>> a[3:]
[4, 5]
>>> a[:-1]
[1, 2, 3, 4]
>>> a[2:1]
[]
~~~
### 列表项的增加
- Python支持两个列表用+号操作表示将第二个列表中的元素加入第一个列表
- list.append(x)表示将元素加入列表中。list.insert(n,x)表示在位置n处插入一个元素x
- list.extend(iterable)将迭代器对象中的每个对象加入列表
~~~
>>> a=[1,2,3]
>>> a+[4,5]
[1, 2, 3, 4, 5]
>>> a.append("abc")
>>> a
[1, 2, 3, 'abc']
>>> a.extend("abc")
>>> a
[1, 2, 3, 'abc', 'a', 'b', 'c']
>>> a.insert(0,0)
>>> a
[0, 1, 2, 3, 'abc', 'a', 'b', 'c']
~~~
### 列表的查找
- list.count(x):返回元素x的数目
- list.index(x[,start,end]):返回元素x出现的下标,可以规定起始位置,如果有多个,只返回第一个的下标
- in:判断元素是否在列表中
~~~
>>> a=[1,2,3,2,1]
>>> a.count(1)
2
>>> a.index(1)
0
>>> a.index(1,2)
4
>>> 3 in a
True
~~~
### 列表的删除
- list.remove(x):删除一个元素,如果有多个,只删除第一个
- list.pop([n]):默认删除最后一个元素,如果有参数,则删除倒数n+1的元素
- del list[index]:删除一个元素
~~~
>>> a
[1, 2, 3, 2, 1]
>>> a.remove(1)
>>> a
[2, 3, 2, 1]
>>> a.pop(1)
3
>>> a
[2, 2, 1]
>>> del a[2]
>>> a
[2, 2]
~~~
Python2还是Python3
最后更新于:2022-04-01 16:22:52
# Python2还是Python3
相信很多新接触Python的人都会纠结这一个问题,学Python2还是Python3?
不像Java一样每个新版本基本都是基本兼容以前的版本的。Python2和Python3的差别是巨大的,可以说是脱胎换骨,要知道这对一门语言的发展是非常危险的。但Python还是这么做了,有点置于死地而后生的味道。
大家主要纠结的问题是Python中很多库都是只有Python2版本的,但现在的情况有了很大的改观,主流的库不是推出了Python3版本,就是被其他的库代替。所以能用Python3还是尽量用Python3吧。
但如果原来的工程是基于Python2的,需要对其进行维护和再开发等工作,考虑到迁移的代价,可能暂时只能继续使用Python2。
人生苦短,我用Python。
每天学点Python之布尔类型
最后更新于:2022-04-01 16:22:50
# 每天学点Python之布尔类型
Python中的布尔类型有两个常量True和False表示。
### 布尔值转化
Python中的布尔值是可以转化为数值的,True表示1,而False表示0,可以对其进行数值运算,但不建议这么做,会引起代码的混乱。
### 真值测试
在Python中所有的对象都可以进行真值测试,下面罗列一下判断为假的情况:
- None
- False
- 数值中的零,包括0,0.0,0j(虚数)
- 空序列,包括空字符串(”),空元组(()),空列表([])
- 空的字典{}
- 自定义的对象的实例,该对象的__bool__方法返回False或者__len__方法返回0
除了以上的情况外,所有的对象在if或者while语句中的表现都为真。
### 布尔操作
在Python中布尔值可以进行或、且、否三种操作,与很多语言不同的是,Python中不是用符号,而是用英文单词来表示,分别是or、and和not。
需要注意的是or和and都支持短路操作,如果or的左边返回True,则右边就不会判断;同理如果and左边返回False,右边也不会进行判断。
not的优先级很低,`not a == b`表示的是`not (a == b)`,而表达式`a == not b`会直接报错,需要加括号`a == (not b)`。
### 比较操作
通过比较操作会返回布尔类型的值。除了普通的比较操作外,Python还支持is操作来判断两个对象是否是同一个对象,下面是Python支持的所有的比较操作:
| 操作符 | 解释 |
|-----|-----|
| < | 小于 |
| <= | 小于等于 |
| > | 大于 |
| >= | 大于等于 |
| == | 等于 |
| != | 不等于 |
| is | 是相同对象 |
| is not | 是不同对象 |
**实例**
其他操作比较常见,给出一些is的用法示例:
~~~
a = None
b = None
# True,因为None只有唯一实例
r = a is b
a = "22"
b = "22"
# True,直接声明的相同字符串也会指向同一个实例
r = a is b
a = [1]
b = [1]
# False,相等但不是同一个实例
r = a is b
a = [1]
b = a
c = a
# True,指向同一个实例
r = b is c
~~~
### 操作符重载
在Python中是支持操作符重载的,可以通过重载操作符来改变一般意义上的比较操作,具体内容会在学习object时再整理。
前言
最后更新于:2022-04-01 16:22:48
> 原文出处:[Python大法好](http://blog.csdn.net/column/details/python-master.html)
作者:[u013291394](http://blog.csdn.net/u013291394)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# Python大法好
> 介绍Python编程基础,流行框架,编程技巧。