本文适应人群:C# or Python3 基础巩固
马上快期末考试了,老师蜜月也回来了,于是有了一场跨季度的复习讲课了:
1.Python基础语法扩展¶
1.1.if 判断条件相关¶
None、""、0、[]、{} ==> 假
1、" "、[None,""]、{"":None} ==> 真
小明可高兴了,前几天被打击的面目全非,这几天老师回来了,又可以大发神威了,于是抢先提交demo:
In [1]:
# None
if None:
print(True)
else:
print(False)
False
In [2]:
# 0为False
if 0:
print(True)
else:
print(False)
False
In [3]:
# 空字符串
if "":
print(True)
else:
print(False)
False
In [4]:
# 空列表为False
if []:
print(True)
else:
print(False)
False
In [5]:
# 空字典为False
if {}:
print(True)
else:
print(False)
False
In [6]:
# 1为True
if 1:
print(True)
else:
print(False)
True
In [7]:
# 含空格
if " ":
print(True)
else:
print(False)
True
In [8]:
if [None,""]:
print(True)
else:
print(False)
True
In [9]:
if {"":None}:
print(True)
else:
print(False)
True
老师微带笑容的看了小明一眼,然后接着讲if的扩展
1.2.三元表达符¶
eg:max = a if a > b else b
In [10]:
a, b = 1, 2
max = a if a > b else b
print(max)
2
In [11]:
a, b, c = 1, 3, 2
max = a if a > b else b
max = max if max > c else c
print(max)
3
In [12]:
# 上面的那个还有一种简写(不推荐)
a, b, c = 1, 3, 2
max = (a if a > b else b) if (a if a > b else b) > c else c
print(max)
3
1.2.字符串和编码¶
在Python3.x版本中,字符串是以Unicode编码的
对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符
小潘对这块有所研究,把小明按在桌上然后抢先提交demo:
In [13]:
ord('D')
Out[13]:
68
In [14]:
ord('毒')
Out[14]:
27602
In [15]:
chr(68)
Out[15]:
'D'
In [16]:
chr(27602)
Out[16]:
'毒'
In [17]:
print(ord('A'))
print(ord('Z'))
print(ord('a'))
print(ord('z'))
65
90
97
122
老师补充讲解道:
编码:encode() 解码:decode()
url相关的可以用:
urllib.parse.quote() and urllib.parse.unquote()
urllib.parse.urlencode() 可以直接对一个key-value进行url编码
In [18]:
# encode() and decode()
name="毒逆天"
name_encode=name.encode("utf-8")
print(name_encode)
print(name_encode.decode("utf-8"))
b'\xe6\xaf\x92\xe9\x80\x86\xe5\xa4\xa9'
毒逆天
In [19]:
# 需要导入urlib.parse
import urllib.parse
In [20]:
test_str="淡定"
# 对字符串进行url编码和解码
test_str_enode = urllib.parse.quote(test_str)
print(test_str_enode)
# urllib.parse.quote() 解码
print(urllib.parse.unquote(test_str_enode))
%E6%B7%A1%E5%AE%9A
淡定
In [21]:
# urlencode 可以直接对一个key-value进行编码
test_dict={"name":"毒逆天","age":23}
encode_str = urllib.parse.urlencode(test_dict)
print(encode_str)
print(urllib.parse.unquote(encode_str))
name=%E6%AF%92%E9%80%86%E5%A4%A9&age=23
name=毒逆天&age=23
1.3.值判断和地址判断¶
小明不乐意了,你个小潘总是抢我的风头,看完标题就刷刷的在黑板上写下了如下知识点:
is 是比较两个引用是否指向了同一个对象(id()得到的地址一样则相同)
== 是比较两个对象的值是否相等
对于可变不可变系列就不去复述了,下面再来几个案例看看 值判断和 地址判断的概念
In [22]:
################ 可变类型 ################
In [23]:
a=[1,2,3]
b=[1,2,3]
# id不一样,那is肯定不一样了
print(id(a))
print(id(b))
139727165899464
139727165725256
In [24]:
# a和b是否指向同一个地址
a is b
Out[24]:
False
In [25]:
# a和b的值是否相同
a == b
Out[25]:
True
In [26]:
################ 开始变化了 ################
In [27]:
# 让a指向b的地址
a=b
# a和b的id一样了
print(id(a))
print(id(b))
139727165725256
139727165725256
In [28]:
# a和b是否指向同一个地址
a is b
Out[28]:
True
In [29]:
# a和b的值是否相同
a == b
Out[29]:
True
In [30]:
################ 不可变类型 ################
In [31]:
a=1
b=1
# id一样
print(id(a))
print(id(b))
94592578394656
94592578394656
In [32]:
a is b
Out[32]:
True
In [33]:
a == b
Out[33]:
True
In [34]:
# 但是你要注意,不是所有不可变类型都这样的
f1=1.2
f2=1.2
# 声明两个相同值的浮点型变量,查看它们的id,发现它们并不是指向同个内存地址(这点和int类型不同)
print(id(f1))
print(id(f2))
139727217917024
139727217917096
In [35]:
# 这个就不一样了
# 这方面涉及Python内存管理机制,Python对int类型和较短的字符串进行了缓存
# 无论声明多少个值相同的变量,实际上都指向同个内存地址,其他的就没这福利咯~
f1 is f2
Out[35]:
False
In [36]:
f1 == f2
Out[36]:
True
2.Python总结之for系列¶
老师徐徐道来:“之前说for总是零零散散的,现在基础都讲完了,来个小汇总:”
2.1.Base¶
能够被for循环遍历的,就是可迭代的
In [37]:
# 类似于for(int i=0;i<5;i++)
for i in range(5):
print(i)
0
1
2
3
4
In [38]:
#while循环一般通过数值是否满足来确定循环的条件
#for循环一般是对能保存多个数据的变量,进行遍历
name="https://pan.baidu.com/s/1weaF2DGsgDzAcniRzNqfyQ#mmd"
for i in name:
if i=='#':
break
print(i,end='')#另一种写法:print("%s"%i,end="")
print('\n end ...')
https://pan.baidu.com/s/1weaF2DGsgDzAcniRzNqfyQ
end ...
In [39]:
# 你期望的结果是:i = 5
for i in range(10):
if i == 5:
print("i = %d" % i)
else:
print("没有找到")
i = 5
没有找到
In [40]:
# 当迭代的对象迭代完并为空时,位于else的子句将执行
# 而如果在for循环中含有break时则直接终止循环,并不会执行else子句
# 正确写法如下:
for i in range(10):
if i == 5:
print("i = %d" % i)
break
else:
print("没有找到")
i = 5
In [41]:
# 遍历一个字典
test_dict={"Name":"小明","Age":23}
for k,v in test_dict.items():
print("key:%s,value:%s"%(k,v))
key:Name,value:小明
key:Age,value:23
2.2.列表生成式¶
简写:list(range(1, 11)) 全写:[x for x in range(1,11)]
In [42]:
list(range(1, 11))
Out[42]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [43]:
[x for x in range(1,11)]
Out[43]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [44]:
# 1~10的平方列表
[x*x for x in range(1,11)]
Out[44]:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
In [45]:
# 1~10之间的偶数
[x for x in range(1, 11) if x % 2 == 0]
Out[45]:
[2, 4, 6, 8, 10]
In [46]:
# 数学里面的全排列
[x + y for x in 'ABC' for y in 'AB']
Out[46]:
['AA', 'AB', 'BA', 'BB', 'CA', 'CB']
In [47]:
# 数学里面的坐标轴
[(x,y) for x in range(1,5) for y in range(1,4)]
Out[47]:
[(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3),
(4, 1),
(4, 2),
(4, 3)]
In [48]:
# (x,y,z) 一般三个嵌套就上天了
[(x,y,z) for x in range(1,5) for y in range(1,4) for z in range(1,3)]
Out[48]:
[(1, 1, 1),
(1, 1, 2),
(1, 2, 1),
(1, 2, 2),
(1, 3, 1),
(1, 3, 2),
(2, 1, 1),
(2, 1, 2),
(2, 2, 1),
(2, 2, 2),
(2, 3, 1),
(2, 3, 2),
(3, 1, 1),
(3, 1, 2),
(3, 2, 1),
(3, 2, 2),
(3, 3, 1),
(3, 3, 2),
(4, 1, 1),
(4, 1, 2),
(4, 2, 1),
(4, 2, 2),
(4, 3, 1),
(4, 3, 2)]
2.3.扩展¶
如果要对list实现类似C#或者java那样的下标循环怎么办?
这块小明又有预习,于是在提交Code的同时大声说道:
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
In [49]:
for i, item in enumerate(['A', 'B', 'C']):
print(i, item)
0 A
1 B
2 C
3.Python中赋值、浅拷贝、深拷贝¶
看到标题小明和小潘就楞了,老师当时没讲解啊,然后两个人眼巴巴的看着老师讲解:
3.1.赋值¶
通过=来实现,就是把地址拷贝了一份,比如 a = b
In [50]:
a=[1,2,2]
b = a
print(id(a))
print(id(b))
139727165518536
139727165518536
In [51]:
# 再验证
a.append(3)
# 都增加了一个3,说明的确指向同一个内存地址
print(a)
print(b)
[1, 2, 2, 3]
[1, 2, 2, 3]
3.2.深拷贝deepcopy¶
导入copy模块,调用deepcopy方法
如果有嵌套引用的情况,直接递归拷贝
In [52]:
import copy
a=[1,2,2]
In [53]:
b=copy.deepcopy(a)
# 指向了不同的内存地址
print(id(a))
print(id(b))
139727165899080
139727165900488
In [54]:
# 再验证一下
a.append(3)
# b不变,说明的确指向不同的内存地址
print(a)
print(b)
[1, 2, 2, 3]
[1, 2, 2]
In [55]:
################ 开始变化了 ################
In [56]:
# 之前讲了嵌套列表,我们来验证一下
a=[1,2,2]
b=[1,2,3,a]
c=copy.deepcopy(b)
# 发现地址都不一样
print(id(b))
print(id(c))
print(id(b[3]))
print(id(c[3]))
139727166586248
139727165899080
139727165725256
139727165899464
In [57]:
# 直观的验证一下
a.append(666)
# 深拷贝的确是深拷贝
print(b)
print(c)
[1, 2, 3, [1, 2, 2, 666]]
[1, 2, 3, [1, 2, 2]]
3.3.浅拷贝copy¶
copy只是简单拷贝,如果拷贝内容里面还有引用之类的,他是不管的
In [58]:
import copy
a=[1,2,2]
In [59]:
b=copy.copy(a)
# 指向了不同的内存地址
print(id(a))
print(id(b))
139727165902088
139727165850952
In [60]:
################ 开始变化了 ################
In [61]:
# 之前讲了嵌套列表,我们来验证一下
a=[1,2,2]
b=[1,2,3,a]
c=copy.copy(b)
# 第一层地址不一样
print(id(b))
print(id(c))
139727165519432
139727165902088
In [62]:
# 验证一下
b.append(111)
# 第一层指向的不同地址
print(b)
print(c)
[1, 2, 3, [1, 2, 2], 111]
[1, 2, 3, [1, 2, 2]]
In [63]:
# 如果里面还有引用,那么就不管了
print(id(b[3]))
print(id(c[3]))
139727165725576
139727165725576
In [64]:
# 验证一下
a.append(666)
# 内部引用的确没copy新地址
print(b)
print(c)
[1, 2, 3, [1, 2, 2, 666], 111]
[1, 2, 3, [1, 2, 2, 666]]
3.4.知识扩展¶
如果拷贝的对象是不可变类型,不管深拷贝和浅拷贝以及赋值都是地址引用。但当拷贝的不可变对象含有引用类型时,只有深拷贝(deepcopy)会递归复制
需要注意的是:Python和Net对于值类型处理是不一样的(管理方式不一样导致的)
==>NET中值类型默认是深拷贝的,而对于引用类型,默认实现的是浅拷贝
In [65]:
a=(1,2,2)
b=a
print(id(a))
print(id(b))
139727165526520
139727165526520
In [66]:
a=(1,2,2)
b=copy.deepcopy(a)
print(id(a))
print(id(b))
139727165846872
139727165846872
In [67]:
a=(1,2,2)
b=copy.copy(a)
print(id(a))
print(id(b))
139727165526520
139727165526520
扩:当拷贝的不可变对象含有引用类型时:赋值和浅拷贝不会copy,而深拷贝(deepcopy)会递归复制
PS:我们常用的切片相当于浅拷贝(copy.copy())
4.CSharp中赋值、浅拷贝、深拷贝¶
小明听懂了Python的深拷贝和浅拷贝后,本着学以致用的原则,写下了C#的实现:
先声明一下,本机环境是Ubuntu + NetCore,欢迎贴Code补充
4.1.赋值¶
赋值方法和Python一样,直接赋值即可
var list1 = new List() { 1, 2, 2 };
var list2 = list1;
In [68]:
%%script csharp
// Python一样,直接赋值即可
var list1 = new List() { 1, 2, 2 };
var list2 = list1;
// 验证一下
list1.Add(3);//我们修改一下list1,list2也就跟着就改变了