Python3 与 C# 扩展之~基础衍生
本文适应人群:C#
or Python3
基础巩固
代码裤子:
在线编程:
在线预览:
马上快期末考试了,老师蜜月也回来了,于是有了一场跨季度的复习讲课了:
1.Python基础语法扩展
1.1.if 判断条件相关
None、""、0、[]、{}
==> 假
1、" "、[None,""]、{"":None}
==> 真
小明可高兴了,前几天被打击的面目全非,这几天老师回来了,又可以大发神威了,于是抢先提交demo:
# None
if None:
print(True)
else:
print(False)
# 0为False
if 0:
print(True)
else:
print(False)
# 空字符串
if "":
print(True)
else:
print(False)
# 空列表为False
if []:
print(True)
else:
print(False)
# 空字典为False
if {}:
print(True)
else:
print(False)
# 1为True
if 1:
print(True)
else:
print(False)
# 含空格
if " ":
print(True)
else:
print(False)
if [None,""]:
print(True)
else:
print(False)
if {"":None}:
print(True)
else:
print(False)
老师微带笑容的看了小明一眼,然后接着讲if的扩展
1.2.三元表达符
eg:max = a if a > b else b
a, b = 1, 2
max = a if a > b else b
print(max)
a, b, c = 1, 3, 2
max = a if a > b else b
max = max if max > c else c
print(max)
# 上面的那个还有一种简写(不推荐)
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)
1.2.字符串和编码
在Python3.x
版本中,字符串是以Unicode
编码的
对于单个字符的编码,Python提供了ord()
函数获取字符的整数表示,chr()
函数把编码转换为对应的字符
小潘对这块有所研究,把小明按在桌上然后抢先提交demo:
ord('D')
ord('毒')
chr(68)
chr(27602)
print(ord('A'))
print(ord('Z'))
print(ord('a'))
print(ord('z'))
老师补充讲解道:
编码:encode()
解码:decode()
url相关的可以用:
urllib.parse.quote()
and urllib.parse.unquote()
urllib.parse.urlencode()
可以直接对一个key-value
进行url
编码
# encode() and decode()
name="毒逆天"
name_encode=name.encode("utf-8")
print(name_encode)
print(name_encode.decode("utf-8"))
# 需要导入urlib.parse
import urllib.parse
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))
# urlencode 可以直接对一个key-value进行编码
test_dict={"name":"毒逆天","age":23}
encode_str = urllib.parse.urlencode(test_dict)
print(encode_str)
print(urllib.parse.unquote(encode_str))
1.3.值判断和地址判断
小明不乐意了,你个小潘总是抢我的风头,看完标题就刷刷的在黑板上写下了如下知识点:
is 是比较两个引用是否指向了同一个对象(id()
得到的地址一样则相同)
== 是比较两个对象的值是否相等
在之前讲Dict的时候提了一下可变和不可变类型:
Func里面又系统的说了一下:
对于可变不可变系列就不去复述了,下面再来几个案例看看 值判断和 地址判断的概念
################ 可变类型 ################
a=[1,2,3]
b=[1,2,3]
# id不一样,那is肯定不一样了
print(id(a))
print(id(b))
# a和b是否指向同一个地址
a is b
# a和b的值是否相同
a == b
################ 开始变化了 ################
# 让a指向b的地址
a=b
# a和b的id一样了
print(id(a))
print(id(b))
# a和b是否指向同一个地址
a is b
# a和b的值是否相同
a == b
################ 不可变类型 ################
a=1
b=1
# id一样
print(id(a))
print(id(b))
a is b
a == b
# 但是你要注意,不是所有不可变类型都这样的
f1=1.2
f2=1.2
# 声明两个相同值的浮点型变量,查看它们的id,发现它们并不是指向同个内存地址(这点和int类型不同)
print(id(f1))
print(id(f2))
# 这个就不一样了
# 这方面涉及Python内存管理机制,Python对int类型和较短的字符串进行了缓存
# 无论声明多少个值相同的变量,实际上都指向同个内存地址,其他的就没这福利咯~
f1 is f2
f1 == f2
2.Python总结之for系列
老师徐徐道来:“之前说for总是零零散散的,现在基础都讲完了,来个小汇总:”
2.1.Base
能够被for循环遍历的,就是可迭代的
For基础系:
# 类似于for(int i=0;i<5;i++)
for i in range(5):
print(i)
i+=1
#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 ...')
# 你期望的结果是:i = 5
for i in range(10):
if i == 5:
print("i = %d" % i)
else:
print("没有找到")
# 当迭代的对象迭代完并为空时,位于else的子句将执行
# 而如果在for循环中含有break时则直接终止循环,并不会执行else子句
# 正确写法如下:
for i in range(10):
if i == 5:
print("i = %d" % i)
break
else:
print("没有找到")
# 遍历一个字典
test_dict={"Name":"小明","Age":23}
for k,v in test_dict.items():
print("key:%s,value:%s"%(k,v))
2.2.列表生成式
如果下面知识点还不熟悉的,看看之前讲的~列表生成式:
简写:list(range(1, 11))
全写:[x for x in range(1,11)]
list(range(1, 11))
[x for x in range(1,11)]
# 1~10的平方列表
[x*x for x in range(1,11)]
# 1~10之间的偶数
[x for x in range(1, 11) if x % 2 == 0]
# 数学里面的全排列
[x + y for x in 'ABC' for y in 'AB']
# 数学里面的坐标轴
[(x,y) for x in range(1,5) for y in range(1,4)]
# (x,y,z) 一般三个嵌套就上天了
[(x,y,z) for x in range(1,5) for y in range(1,4) for z in range(1,3)]
2.3.扩展
如果要对list实现类似C#或者java那样的下标循环怎么办?
这块小明又有预习,于是在提交Code的同时大声说道:
Python内置的enumerate
函数可以把一个list变成索引-元素
对,这样就可以在for循环中同时迭代索引和元素本身
for i, item in enumerate(['A', 'B', 'C']):
print(i, item)
3.Python中赋值、浅拷贝、深拷贝
看到标题小明和小潘就楞了,老师当时没讲解啊,然后两个人眼巴巴的看着老师讲解:
官方文档:
3.1.赋值
通过=
来实现,就是把地址拷贝了一份,比如 a = b
a=[1,2,2]
b = a
print(id(a))
print(id(b))
# 再验证
a.append(3)
# 都增加了一个3,说明的确指向同一个内存地址
print(a)
print(b)
3.2.深拷贝deepcopy
导入copy
模块,调用deepcopy
方法
如果有嵌套引用的情况,直接递归拷贝
import copy
a=[1,2,2]
b=copy.deepcopy(a)
# 指向了不同的内存地址
print(id(a))
print(id(b))
# 再验证一下
a.append(3)
# b不变,说明的确指向不同的内存地址
print(a)
print(b)
################ 开始变化了 ################
# 之前讲了嵌套列表,我们来验证一下
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]))
# 直观的验证一下
a.append(666)
# 深拷贝的确是深拷贝
print(b)
print(c)
3.3.浅拷贝copy
copy只是简单拷贝,如果拷贝内容里面还有引用之类的,他是不管的
import copy
a=[1,2,2]
b=copy.copy(a)
# 指向了不同的内存地址
print(id(a))
print(id(b))
################ 开始变化了 ################
# 之前讲了嵌套列表,我们来验证一下
a=[1,2,2]
b=[1,2,3,a]
c=copy.copy(b)
# 第一层地址不一样
print(id(b))
print(id(c))
# 验证一下
b.append(111)
# 第一层指向的不同地址
print(b)
print(c)
# 如果里面还有引用,那么就不管了
print(id(b[3]))
print(id(c[3]))
# 验证一下
a.append(666)
# 内部引用的确没copy新地址
print(b)
print(c)
3.4.知识扩展
如果拷贝的对象是不可变类型,不管深拷贝和浅拷贝以及赋值都是地址引用
需要注意的是:Python和Net对于值类型处理是不一样的(管理方式不一样导致的)
==>NET中值类型默认是深拷贝的,而对于引用类型,默认实现的是浅拷贝
a=(1,2,2)
b=a
print(id(a))
print(id(b))
a=(1,2,2)
b=copy.deepcopy(a)
print(id(a))
print(id(b))
a=(1,2,2)
b=copy.copy(a)
print(id(a))
print(id(b))
4.CSharp中赋值、浅拷贝、深拷贝
小明听懂了Python的深拷贝和浅拷贝后,本着学以致用的原则,写下了C#的实现:
先声明一下,本机环境是Ubuntu + NetCore,欢迎贴Code补充
4.1.赋值
Code:
赋值方法和Python
一样,直接赋值即可
var list1 = new List<int>() { 1, 2, 2 };
var list2 = list1;
%%script csharp
// Python一样,直接赋值即可
var list1 = new List<int>() { 1, 2, 2 };
var list2 = list1;
// 验证一下
list1.Add(3);//我们修改一下list1,list2也就跟着就改变了
foreach (var item in list1)
{
Console.Write(item + " ");
}
Console.WriteLine();
foreach (var item in list2)
{
Console.Write(item + " ");
}
4.2值类型默认深拷贝
NetCore深拷贝相关的 public void CopyTo (T[] array);
简单类型用最简单的方式就能实现深拷贝了:
官方的CopyTo在这里和这个效果一样,但是比较麻烦,这边就不贴了(Code里面贴了)
var list3 = new List<int>() { 1, 2, 2 };
var list4 = new List<int>(list3);
// 验证一下
list3.Add(3);
foreach (var item in list3)
{
Console.Write(item + " ");
}
Console.WriteLine();
foreach (var item in list4)
{
Console.Write(item + " ");
}
结果:
1 2 2 3 1 2 2
4.3.引用类型默认浅拷贝
对于List<T>
再复杂点的,上面的方式就变成浅拷贝了:(类似于Python的Copy.Copy)
官方的CopyTo在这里和这个效果一样,但是比较麻烦,这边就不贴了(Demo里面贴了)
定义一个Student
public partial class Student
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"Name:{Name},Age:{Age}";
}
}
浅拷贝Demo:
var list5 = new List<Student>(){
new Student { Name = "小张", Age = 22 },
new Student { Name = "小明", Age = 23 }
};
var p = new Student() { Name = "小潘", Age = 23 };
list5.Add(p);
// 浅拷贝一份
var list6 = new List<Student>(list5);
// 浅拷贝测试
// 我们修改一下list5,list6没有跟着改变,说明第一层的地址的确不一样
list5.Add(new Student() { Name = "小胖", Age = 24 });
// 当我们修改小潘同学的年龄时,大家都变了,说明真的只是浅拷贝
p.Age = 24;
foreach (var item in list5)
{
Console.WriteLine(item);
}
Console.WriteLine("=============");
foreach (var item in list6)
{
Console.WriteLine(item);
}
结果:
Name:小张,Age:22 Name:小明,Age:23 Name:小潘,Age:24 Name:小胖,Age:24 ============= Name:小张,Age:22 Name:小明,Age:23 Name:小潘,Age:24
4.4.简单方式实现深拷贝
对于List<T>
的深拷贝场景,其实项目中还是蛮常见的,那深拷贝怎么搞呢?
先来一个简单的实现方式,需要T
实现ICloneable
接口才行:
定义一个Person类
public partial class Person : ICloneable
{
public string Name { get; set; }
public int Age { get; set; }
//实现ICloneable的Clone方法
public object Clone()
{
return base.MemberwiseClone();//调用父类方法即可
}
public override string ToString()
{
return $"Name:{Name},Age:{Age}";
}
}
给List<T>
定义一个扩展方法:(温馨提醒:扩展方法所在的类必须是static Class哦)
public static partial class ListExt
{
// 只要T实现了ICloneable接口就可以了
public static IEnumerable<T> DeepCopy<T>(this IEnumerable<T> list) where T : ICloneable
{
return list.Select(item => (T)item.Clone()).ToList();
}
}
来个调用加验证:
#region 引用类型深拷贝-简单实现方式
var oldList = new List<Person>(){
new Person(){Name="小明",Age=23},
new Person(){Name="小张",Age=22},
};
var xiaoPan = new Person() { Name = "小潘", Age = 23 };
oldList.Add(xiaoPan);
var newList = oldList.DeepCopy();
//测试
oldList.Add(new Person() { Name = "小胖", Age = 23 });
xiaoPan.Age = 24;
foreach (var item in oldList)
{
Console.WriteLine(item);
}
Console.WriteLine("========");
foreach (var item in newList)
{
Console.WriteLine(item);
}
#endregion
结果:
Name:小明,Age:23 Name:小张,Age:22 Name:小潘,Age:24 Name:小胖,Age:23 ======== Name:小明,Age:23 Name:小张,Age:22 Name:小潘,Age:23
4.5.序列化方式实现深拷贝(常用)
利用System.Runtime.Serialization
序列化与反序列化实现深拷贝
先定义一个Teacher类(别忘记加 Serializable
的标签)
[Serializable]
public partial class Teacher
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"Name:{Name},Age:{Age}";
}
}
添加一个扩展方法:
public static partial class ListExt
{
// 利用System.Runtime.Serialization序列化与反序列化实现深拷贝
public static T DeepCopy2<T>(this T obj)
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
调用:
#region 引用类型深拷贝-序列化实现
var oldTestList = new List<Teacher>(){
new Teacher(){Name="小明",Age=23},
new Teacher(){Name="小张",Age=22},
};
var s = new Teacher() { Name = "小潘", Age = 23 };
oldTestList.Add(s);
var newTestList = oldTestList.DeepCopy2();
//测试
oldTestList.Add(new Teacher() { Name = "小胖", Age = 23 });
s.Age = 24;
foreach (var item in oldTestList)
{
Console.WriteLine(item);
}
Console.WriteLine("========");
foreach (var item in newTestList)
{
Console.WriteLine(item);
}
#endregion
结果:
Name:小明,Age:23 Name:小张,Age:22 Name:小潘,Age:24 Name:小胖,Age:23 ======== Name:小明,Age:23 Name:小张,Age:22 Name:小潘,Age:23
因为主要是说Python,Net只是简单提一下,这边就先到这里了
不尽兴可以看看,讲得还是挺全面的
我们接着来对比学习~
5.Python生成器
一看到标题小明又懵圈了,但是看到大家好像都知道的样子心想道:“我是不是又睡过一节课啊?”
,这边说说生成器
通过列表生成式,我们可以简单并直接的创建一个列表,但是当数据有一定的规律而且又很大的时候,使用列表就有点浪费资源了
如果列表元素可以按照某种算法推算出来,这样就不必创建完整的list,从而节省大量的资源
5.1.简单方式
在Python中,这种一边循环一边计算的机制,称为生成器:generator
先看一个简单的生成器案例:(只要把一个列表生成式的[]
改成()
,就创建了一个generator
了)
# 列表生成式
[x for x in range(10)]
# 生成器写法(Python2.x系列是用xrange)
(x for x in range(10))
遍历方式可以用之前的for
循环来遍历(推荐)
也可以用next()
或者__next__()
方法来遍历。【C#是用MoveNext
】
generator
保存的是算法,每次调用next(xxx)
或者__next__()
,就计算出下一个元素的值,直到计算到最后一个元素
当没有更多的元素时,抛出StopIteration
的异常
最新的Python3.7在这方面有所优化:
g=(x for x in range(10))
# for来遍历(推荐)
for i in g:
print(i)
g=(x for x in range(10))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(g.__next__()) #通过__next__也一样取下一个
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
5.2.yield方式
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现时,还可以用函数来实现
这时候就需要用到yield
了,像最经典的斐波拉契数列,这次用一波生成器来对比实现下:
# 递归方式:求第30个数是多少
# 1、1、2、3、5、8、13、21、34...
def fib(n):
if n == 1 or n == 2:
return 1
else:
return fib(n - 1) + fib(n - 2)
fib(30)
# 在讲yield方式之前先用循环实现一下
def fibona(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
fibona(30)
相关文章:
-
-
如何利用Python和深度神经网络锁定即将流失的客户?业绩过十万!
烦恼 作为一名数据分析师,你来到这家跨国银行工作已经半年了。 今天上午,老板把你叫到办公室,面色凝重。 你心里直打鼓,以为自己捅了什么篓子。幸好老板... [阅读全文] -
Python守护进程命令,为何被黑客钟意?整蛊、木马都用得上它!
考虑一下利用Python制作一个整蛊、木马软件,我提供思路。(清楚到没学过编程的人也理解) 1、首先一个黑客做一个整蛊或者木马软件,一定不会让你能够... [阅读全文] -
Python一键上传旅途照片生成展示网页!女友直呼太厉害了!
作为一个比较喜欢出去见识世界、看看自然风光的人,这几年有幸跑了一些地方,在祖国大地不同的地方见识了不同的人文风物,手机里也存了不少照片,想着如果以某... [阅读全文] -
一、正则表达式简介 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了re 模块... [阅读全文]
-
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论