python import 类如何捕获clrt c_Python3 与 C# 扩展之~基础衍生
本文适应人群: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也就跟着就改变了
foreach (var item in list1)
{
Console.Write(item + " ");
}
Console.WriteLine();
foreach (var item in list2)
{
Console.Write(item + " ");
}
1 2 2 3
1 2 2 3
4.2值类型默认深拷贝¶
NetCore深拷贝相关的官方文档 public void CopyTo (T[] array);
简单类型用最简单的方式就能实现深拷贝了:
官方的CopyTo在这里和这个效果一样,但是比较麻烦,这边就不贴了(Code里面贴了)
var list3 = new List() { 1, 2, 2 };
var list4 = new List(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再复杂点的,上面的方式就变成浅拷贝了:(类似于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(){
new Student { Name = "小张", Age = 22 },
new Student { Name = "小明", Age = 23 }
};
var p = new Student() { Name = "小潘", Age = 23 };
list5.Add(p);
// 浅拷贝一份
var list6 = new List(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实现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定义一个扩展方法:(温馨提醒:扩展方法所在的类必须是static Class哦)
public static partial class ListExt
{
// 只要T实现了ICloneable接口就可以了
public static IEnumerable DeepCopy(this IEnumerable list) where T : ICloneable
{
return list.Select(item => (T)item.Clone()).ToList();
}
}
来个调用加验证:
#region 引用类型深拷贝-简单实现方式
var oldList = new List(){
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(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(){
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了)
In [69]:
# 列表生成式
[x for x in range(10)]
Out[69]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [70]:
# 生成器写法(Python2.x系列是用xrange)
(x for x in range(10))
Out[70]:
at 0x7f14c413cb48>
遍历方式可以用之前的for循环来遍历(推荐)
也可以用next()或者__next__()方法来遍历。【C#是用MoveNext】
generator保存的是算法,每次调用next(xxx)或者__next__(),就计算出下一个元素的值,直到计算到最后一个元素
当没有更多的元素时,抛出StopIteration的异常
In [71]:
g=(x for x in range(10))
# for来遍历(推荐)
for i in g:
print(i)
0
1
2
3
4
5
6
7
8
9
In [72]:
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))
0
1
2
3
4
5
6
7
8
9
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in ()
11 print(next(g))
12 print(next(g))
---> 13print(next(g))
14 print(next(g))
StopIteration:
5.2.yield方式¶
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现时,还可以用函数来实现
这时候就需要用到yield了,像最经典的斐波拉契数列,这次用一波生成器来对比实现下:
In [73]:
# 递归方式:求第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)
Out[73]:
832040
In [74]:
# 在讲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)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
In [75]:
# for循环实现
def fibona(n):
a, b = 0, 1
# [0,n)
for i in range(n):
print(b)
a, b = b, a + b
fibona(30)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
a, b = b, a + b 之前交换两数的时候提过
这个相当于==>
temp_tuple = (b, a + b)
a = temp_tuple[0]
b = temp_tuple[1]
要把fibona函数变成generator,只需要把print(b)改为yield b就可以了:
generator在执行过程中,遇到yield就中断,下次又继续执行到yield停下了,一直到最后
生成器的特点:
节约内存
迭代到下一次的调用时,所使用的参数都是第一次所保留下的(所有函数调用的参数都是第一次所调用时保留的,而不是新创建的)
In [76]:
# 改成生成器比较简单,直接换输出为yield
def fibona(n):
a, b = 0, 1
# [0,n)
for i in range(n):
yield b
a, b = b, a + b
In [77]:
# 看看是不是生成器
g = fibona(30)
g
Out[77]:
In [78]:
# 遍历输出(基本上都会用for来遍历)
for i in g:
print(i)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的循环的时候
小明总结如下:
在Python中,这种一边循环一边计算的机制称为生成器:generator
每一个生成器都是一个迭代器(迭代器不一定是生成器)
如果一个函数包含yield关键字,这个函数就会变为一个生成器
生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用
由于生成器也是一个迭代器,那么它就支持next用方法来获取下一个值(我们平时用for来遍历它)
推荐一篇文章,总结的很全了:(yield用法总结)
5.3.扩展之~send(msg)方法:¶
其实__next__()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去
而__next__()不 能传递特定的值。我们可以看做x.__next__() 和 x.send(None) 作用是一样的
In [79]:
# 来个案例:
def test_send(n):
for i in range(n):
tmp = yield i
print(tmp)
g = test_send(5)
g
Out[79]:
In [80]:
# 定义一个列表
test_list = []
# 把第一次yield的值放在列表中
test_list.append(g.__next__())
# 把list传给tmp并打印(可以理解为把表达式右边的 yield i 暂时换成了 test_list)
# out的内容是yield返回的值
g.send(test_list)
[0]
Out[80]:
1
In [81]:
# 以防你们看不懂,来个简单案例
# 你传啥print(tmp)就给你打印啥
g.send("你好啊")
你好啊
Out[81]:
2
注意一种情况,generator刚启动的时候,要么不传,要么只能传None
解决:要么一开始send(None)要么一开始先调用一下__next()__ or next()
In [82]:
# 注意一种情况,generator刚启动的时候,要么不传,要么只能传None
def test_send(n):
for i in range(n):
tmp = yield i
print(tmp)
g = test_send(5)
g.send("dog") # TypeError: can't send non-None value to a just-started generator
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
7
8 g = test_send(5)
----> 9g.send("dog") # TypeError: can't send non-None value to a just-started generator
TypeError: can't send non-None value to a just-started generator
In [83]:
# 解决:要么一开始send(None)要么一开始先调用一下__next()__ or next()
def test_send(n):
for i in range(n):
tmp = yield i
print(tmp)
g = test_send(5)
g.send(None)
Out[83]:
0
In [84]:
g.send("dog")
dog
Out[84]:
1
扩:C#在遍历generator的时候也是先调一下MoveNext方法
while (tmp.MoveNext())
{
Console.WriteLine(tmp.Current);
}
5.4.扩展之~return和break的说明¶
在一个generator函数中,如果没有return则默认执行至函数完毕
如果在执行过程中return或者break则直接抛出StopIteration终止迭代
In [85]:
# break案例
def test_send(n):
for i in range(n):
if i==2:
break
yield i
g = test_send(5)
for i in g:
print(i)
0
1
In [86]:
# return案例
def test_send(n):
for i in range(n):
if i==2:
return "i==2"
yield i
g = test_send(5)
for i in g:
print(i)
0
1
用for循环调用generator时,发现拿不到generator的return语句的返回值
如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中
In [87]:
# 上面return的返回值怎么拿呢?
g = test_send(5)
while True:
try:
tmp = g.__next__()
print(tmp)
except StopIteration as ex:
print(ex.value)
break # 一定要加break,别忘了你在死循环里呢
0
1
i==2
5.5.扩展之~协程yield实现多任务调度¶
这个场景还是很常见的,比如C#的单线程实现多任务用的就可以使用yield
再比如生产消费这个经典案例:(参考)
生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产
Python对协程的支持是通过generator实现的
在generator中,我们不但可以通过for循环来迭代,还可以不断调用__next__()获取由yield语句返回的下一个值。
因为Python的yield不但可以返回一个值,它还可以接收调用者发出的参数(通过send方法),所以就happy了
我们举个简单的demo来看看:
In [88]:
def consumer():
while True:
tmp = yield
# !None就变成真了
if not tmp:
return
print("消费者:",tmp)
In [89]:
# 创建消费者
c = consumer()
# 启动消费者
c.send(None)
# 生产数据,并提交给消费者
c.send("小明")
c.send("小潘")
# 生产结束,通知消费者结束,抛出StopIteration异常
c.send(None) # 使用c.close()可以避免异常
消费者: 小明
消费者: 小潘
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in ()
7 c.send("小潘")
8 # 生产结束,通知消费者结束,抛出StopIteration异常
----> 9c.send(None) # 使用c.close()可以避免异常
StopIteration:
执行流程:
创建协程对象(消费者)后,必须使用send(None)或__next__()启动
协程在执行yield后让出执行绪,等待消息
调用方发送send(msg)消息,协程恢复执行,将接收到的数据保存并执行后续流程
再次循环到yield,协程返回前面的处理结果,并再次让出执行绪
直到关闭或被引发异常
补全demo:
In [90]:
def consumer():
status = ""
while True:
tmp = yield status
if not tmp:
print("消费者已经睡觉了...")
return
print("消费者:获得商品%s号..." % tmp)
status = "ok"
def produce(c):
# 启动消费者
c.send(None)
for i in range(1, 3):
print("生产者:出产商品%s号..." % i)
# 生产商品,并提交给消费者
status = c.send(i)
print("生产者:生产者消费状态: %s" % status)
# c.send(None) 执行这个会引发StopIteration
c.close() # 使用close就可以避免了(手动关闭生成器函数,后面的调用会直接返回StopIteration异常)
# 创建消费者
c = consumer()
produce(c)
生产者:出产商品1号...
消费者:获得商品1号...
生产者:生产者消费状态: ok
生产者:出产商品2号...
消费者:获得商品2号...
生产者:生产者消费状态: ok
In [91]:
# 更多可以查看帮助文档
def test():
yield
help(test())
Help on generator object:
test = class generator(object)
| Methods defined here:
|
| __del__(...)
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
|
| __repr__(self, /)
| Return repr(self).
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| gi_code
|
| gi_frame
|
| gi_running
|
| gi_yieldfrom
| object being iterated by yield from, or None
6.Python迭代器¶
看到迭代器小明老高兴了,心想着一会写个C#版的觉得可以收获一大群眼球~
6.1.判断是否可迭代¶
在说迭代器前先说下可迭代(Iterable)(yield基础点我):
在Python中,能通过for循环遍历的都是可以迭代的,比如 str、tuple、list、dict、set、生成器等等
也可以通过 isinstance(xxx,Iterable) 方法判断一下是否迭代:
In [92]:
from collections import Iterable
In [93]:
isinstance("mmd",Iterable)
Out[93]:
True
In [94]:
isinstance((1,2),Iterable)
Out[94]:
True
In [95]:
isinstance([],Iterable)
Out[95]:
True
In [96]:
isinstance({},Iterable)
Out[96]:
True
In [97]:
isinstance((x for x in range(10)),Iterable)
Out[97]:
True
In [98]:
isinstance(1,Iterable)
Out[98]:
False
6.2.判断是否是迭代器¶
迭代器是一定可以迭代的,怎么判断是迭代器呢?
可以使用next方法的或者通过isinstance(xxx,Iterator)
In [99]:
a=[1,2,3]
next(a)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
1 a=[1,2,3]
2
----> 3next(a)
TypeError: 'list' object is not an iterator
In [100]:
from collections import Iterator
In [101]:
isinstance([],Iterator)
Out[101]:
False
In [102]:
isinstance((x for x in range(10)),Iterator)
Out[102]:
True
6.3.Iterable 转 Iterator¶
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
In [103]:
iter(a)
Out[103]:
In [104]:
isinstance(iter([]),Iterator)
Out[104]:
True
In [105]:
isinstance(iter({}),Iterator)
Out[105]:
True
Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()or__next__()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,而list等则不行
小明总结了一下老师讲解的知识点:
可以for循环的对象都是Iterable类型
可以使用next()or__next__()函数的对象都是Iterator类型
集合数据类型如list、dict、str等是Iterable,可以通过iter()函数获得一个Iterator对象
7.CSharp迭代器¶
乘着下课的时间,小明跑到黑板前,心想:“又到了C#的时候了,看我来收播一大群眼球~”,然后开始了他的个人秀:
其实迭代器(iterator)就是为了更简单的创建枚举器(enumerator)和可枚举类型(enumerator type)的方式
7.1.IEnumerator 和 IEnumerable¶
通俗话讲:
能不能foreach就看你遍历对象有没有实现IEnumerable,就说明你是不是一个可枚举类型(enumerator type)
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
是不是个枚举器(enumerator)就看你实现了IEnumerator接口没
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
最明显的区别:它们两个遍历方式不一样
// 枚举器遍历
var tmp = FibonaByIEnumerator(30);
while (tmp.MoveNext())
{
Console.WriteLine(tmp.Current);
}
// 可枚举类型遍历
foreach (var item in FibonaByIEnumerable(30))
{
Console.WriteLine(item);
}
这个我们在2年前就说过,这边简单提一下(官方文档)(Demo)
MyEnumerator文件:
public class MyEnumerator : IEnumerator
{
///
/// 需要遍历的数组
///
private string[] array;
///
/// 有效数的个数
///
private int count;
public MyEnumerator(string[] array, int count)
{
this.array = array;
this.count = count;
}
///
/// 当前索引(线moveNext再获取index,用-1更妥)
///
private int index = -1;
public object Current
{
get
{
return array[index];
}
}
///
/// 移位
///
///
public bool MoveNext()
{
if (++index < count)
{
return true;
}
return false;
}
///
/// 重置
///
public void Reset()
{
index = -1;
}
}
MyArray.cs文件
public partial class MyArray
{
///
/// 数组容量
///
private string[] array = new string[4];
///
/// 数组元素个数
///
private int count = 0;
///
/// 当前数组的长度
///
public int Length
{
get
{
return count;
}
}
///
/// 添加元素
///
///
///
public MyArray Add(string str)
{
//要溢出的时候扩容
if (count == array.Length)
{
string[] newArray = new string[2 * array.Length];
array.CopyTo(newArray, 0);
array = newArray;//array重新指向
}
array[count++] = str;
return this;
}
///
/// 移除某一项
///
///
///
public MyArray RemoveAt(int i)
{
for (int j = i; j < count - 1; j++)
{
array[j] = array[j + 1];
}
count--;//少了一个元素所以--
return this;
}
///
/// 索引器
///
///
///
public string this[int index]
{
get
{
return array[index];
}
set
{
array[index] = value;
}
}
}
MyArrayExt.cs文件:
public partial class MyArray: IEnumerable
{
///
/// 枚举器方法
///
///
public IEnumerator GetEnumerator()
{
return new MyEnumerator(this.array, this.count);
}
}
调用:
static void Main(string[] args)
{
MyArray array = new MyArray();
array.Add("~").Add("这").Add("是").Add("一").Add("个").Add("测").Add("试").Add("。").RemoveAt(0).RemoveAt(3).RemoveAt(6);
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i]);
}
Console.WriteLine();
foreach (var item in array)
{
Console.Write(item);
}
}
结果:
这是一测试
这是一测试
7.2.yield方式¶
小明看着班里女生羡慕的眼神,得意的强调道:
注意一下,C#是用yield return xxx,Python是用yield xxx关键字
还记得开头说的那句话吗?(yield官方文档)
其实迭代器(iterator)就是为了更简单的创建枚举器(enumerator)和可枚举类型(enumerator type)的方式
如果枚举器和可枚举类型还是不理解(举个例子)就懂了:(从遍历方式就看出区别了)
定义一个斐波拉契函数,返回可枚举类型
///
/// 返回一个可枚举类型
///
public static IEnumerable FibonaByIEnumerable(int n)
{
int a = 0;
int b = 1;
for (int i = 0; i < n; i++)
{
yield return b;
(a, b) = (b, a + b);
}
}
调用:
foreach (var item in FibonaByIEnumerable(30))
{
Console.WriteLine(item);
}
定义一个斐波拉契函数,返回一个枚举器
///
/// 返回一个枚举器
///
public static IEnumerator FibonaByIEnumerator(int n)
{
int a = 0;
int b = 1;
for (int i = 0; i < n; i++)
{
yield return b;
(a, b) = (b, a + b);
}
}
调用一下:
var tmp = FibonaByIEnumerator(30);
while (tmp.MoveNext())
{
Console.WriteLine(tmp.Current);
}
利用yield轻轻松松就创建了枚举器和可枚举类型
以上面那个MyArray的案例来说,有了yield我们代码量大大简化:(Demo)
MyArray.cs
public partial class MyArray
{
///
/// 数组容量
///
private string[] array = new string[4];
///
/// 数组元素个数
///
private int count = 0;
///
/// 当前数组的长度
///
public int Length
{
get
{
return count;
}
}
///
/// 添加元素
///
///
///
public MyArray Add(string str)
{
//要溢出的时候扩容
if (count == array.Length)
{
string[] newArray = new string[2 * array.Length];
array.CopyTo(newArray, 0);
array = newArray;//array重新指向
}
array[count++] = str;
return this;
}
///
/// 移除某一项
///
///
///
public MyArray RemoveAt(int i)
{
for (int j = i; j < count - 1; j++)
{
array[j] = array[j + 1];
}
array[count - 1] = string.Empty;//add 干掉移除的数组
count--;//少了一个元素所以--
return this;
}
///
/// 索引器
///
///
///
public string this[int index]
{
get
{
return array[index];
}
set
{
array[index] = value;
}
}
}
MyArrayExt.cs
public partial class MyArray : IEnumerable
{
///
/// 枚举器方法
///
///
public IEnumerator GetEnumerator()
{
return MyEnumerator();
}
///
/// 通过yield快速实现
///
///
public IEnumerator MyEnumerator()
{
foreach (var item in this.array)
{
yield return item;
}
}
}
然后就行了,MyEnumerator都不用你实现了:
MyArray array = new MyArray();
array.Add("~").Add("这").Add("是").Add("一").Add("个").Add("测").Add("试").Add("。").RemoveAt(0).RemoveAt(3).RemoveAt(6);
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i]);
}
Console.WriteLine();
foreach (var item in array)
{
Console.Write(item);
}
结果:
这是一测试
这是一测试
扩充一下:Python退出迭代器用yield return 或者 yield break,C#使用yield break来退出迭代
做个 demo 测试下:
public static IEnumerable GetValue()
{
for (int i = 0; i < 5; i++)
{
yield return i;
if (i == 2)
{
yield break;
}
}
}
调用:
static void Main(string[] args)
{
foreach (var item in GetValue())
{
Console.WriteLine(item);
}
}
输出:
0
1
2
8.闭包¶
8.1.Python闭包¶
又到了上课时间,小明灰溜溜的跑回座位,听老师讲起了闭包的知识:
函数方面还有不懂的可以看之前讲的文档:Function Base
函数除了可以接受函数作为参数外,还可以把函数作为结果值返回(有点类似于C++里面的函数指针了)
来看一个可变参数求和的例子:
In [1]:
def slow_sum(*args):
def get_sum():
sum = 0
for i in args:
sum += i
return sum
return get_sum # 返回函数引用地址(不加括号)
a = slow_sum(1, 2, 3, 4, 5)# 返回get_sum函数的引用
print(a)# 看看引用地址
print(a())# a() 这时候才是调用get_sum()函数
.get_sum at 0x7f57783b6268>
15
其实上面一个案例就是闭包(Closure)了,来个定义:
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量(参数或者局部变量),那么将这个函数以及用到的一些变量称之为闭包
通俗点说就是:内部函数使用了外部函数作用域里的变量了,那这个内部函数和它用到的变量就是个闭包
注意:当我们调用slow_sum()时,每次调用都会返回一个新的函数(相同的参数也一样)
In [2]:
a = slow_sum(1, 2, 3, 4)
b = slow_sum(1, 2, 3, 4)
a is b
# a()和b()的调用结果互不影响
Out[2]:
False
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,所以也容易消耗内存
so ==> 除非你真正需要它,否则不要使用闭包
返回函数尽量不要引用任何循环变量,或者后续会发生变化的变量(容易出错)
看着小明一脸懵圈的样子,老师说道:
新讲的知识点一般都不太容易快速消化,我们再来看个闭包的好处就理解了:
比如现在我们要根据公式来求解,以y=ax+b为例,传统方法解决:
In [3]:
# 定义一个y=ax+b的函数公式
def get_value(a, b, x):
return a * x + b
In [4]:
# 每次调用都得传 a,b
print(get_value(2, 1, 1))
print(get_value(2, 1, 2))
print(get_value(2, 1, 3))
print(get_value(2, 1, 4))
3
5
7
9
每次调用都得额外传a、b的值
就算使用偏函数来简化也不合适(毕竟已经是一个新的函数了):
In [5]:
from functools import partial
new_get_value = partial(get_value, 2, 1)
print(new_get_value(1))
print(new_get_value(2))
print(new_get_value(3))
print(new_get_value(4))
print(new_get_value(5))
3
5
7
9
11
简单总结functools.partial的作用就是:
把一个函数的某些参数设置默认值,返回一个新的函数,然后调用新函数就免得你再输入重复参数了
而这时候使用闭包就比较合适了,而且真的是封装了一个通用公式了
a,b的值你可以任意变来生成新的公式,而且公式之间还不干扰,以 y=ax²+bx+c为例:
In [6]:
def quadratic_func(a, b, c):
"""y=ax²+bx+c"""
def get_value(x):
return a * x * x + b * x + c
return get_value
In [7]:
# 来个简单的:x^2+1
f1 = quadratic_func(1, 0, 1)
print(f1(0))
print(f1(1))
print(f1(2))
print(f1(3))
print(f1(4))
print(f1(5))
1
2
5
10
17
26
In [8]:
# 可能不太形象,我们画个图看看:
import matplotlib.pyplot as plt # 导入matplotlib的pyplot模块
In [9]:
# 生成x和y的值
x_list = list(range(-10, 11))
y_list = [x * x + 1 for x in x_list]
print(x_list)
print(y_list)
# 画图
plt.plot(x_list, y_list)
# 显示图片
plt.show()
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[101, 82, 65, 50, 37, 26, 17, 10, 5, 2, 1, 2, 5, 10, 17, 26, 37, 50, 65, 82, 101]
aaarticlea/png;base64,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
" alt="" />
In [10]:
# 再来个简单的:x^2-1
f2 = quadratic_func(1, 0, -1) # 相互之间不干扰
print(f2(0))
print(f2(1))
print(f2(2))
print(f2(3))
print(f2(4))
print(f2(5))
-1
0
3
8
15
24
8.2.CSharp闭包¶
听完闭包老师就下课了,说什么明天接着闭包讲啥装饰器的。
小明一愣一愣的,然后就屁颠的跑黑板前讲起了C#版本的闭包:
先看看怎么定义一个闭包,和Python一样,用个求和函数举例:(返回一个匿名函数)
// 有返回值就用Func,没有就用Action
public static Func SlowSum(params int[] args)
{
return () =>
{
int sum = 0;
foreach (var item in args)
{
sum += item;
}
return sum;
};
}
调用:
static void Main(string[] args)
{
var f1 = SlowSum(1, 2, 3, 4, 5);
Console.WriteLine(f1);
Console.WriteLine(f1());
}
结果:(从结果可以看到,f1是一个函数,等你调用f1()才会求和)
System.Func`1[System.Int32]
15
接着讲 ~ 以上面的 y=ax²+bx+c为例,C#实现:
// 以上面的 y=ax²+bx+c 为例,C#实现:
public static Func QuadraticFunc(double a, double b, double c)
{
return x => a * x * x + b * x + c; // 返回一个匿名函数
}
调用:
static void Main(string[] args)
{
var func = QuadraticFunc(1, 0, 1);
Console.WriteLine(func(0));
Console.WriteLine(func(1));
Console.WriteLine(func(2));
Console.WriteLine(func(3));
Console.WriteLine(func(4));
Console.WriteLine(func(5));
}
结果:
1
2
5
10
17
26
Func不理解就看看定义就懂了:public delegate TResult Func(T arg);
这部分不是很难,简单提一下知识点即可。如果你想深究可以==>
在收获满满一箩筐眼球后,小明拍拍屁股去了新开的饭店大吃一顿了...
写在最后:还有一些内容没写,估计过几天又有一篇叫 “基础拓展” 的文章了,为啥不一起写完呢?
其实逆天也想写完,真写完文章又被叫做长篇大论一百页了 #^_^# 行了,听取大家意见,不写那么长的文章,下次见~
在TypeScript中扩展JavaScript基础对象的功能
最近工作中用到,记录一下:假设我们需要一个功能,把一个数字比如10000输出为下面的字符串格式“10,000”,一般是写一个方法,那么我希望更方便一点,直接向Number类型添加一个格式化方法,比如叫 ...
了解Java密码扩展的基础
了解Java密码扩展的基础 Java密码扩展(The Java Cryptography Extension),是JDK1.4的一个重要部分,基本上,他是由一些包构成的,这些包形成了一个框 ...
Python3 与 C# 扩展之~基础拓展
上次知识回顾:https://www.cnblogs.com/dotnetcrazy/p/9278573.html 代码裤子:https://github.com/lotapp/BaseCode ...
Python3 与 C# 扩展之~模块专栏
代码裤子:https://github.com/lotapp/BaseCode/tree/maste 在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode ...
一起来做chrome扩展《基础介绍》
首先说明,chrome的扩展并不它的插件,网上很多说写插件,其实都是说的扩展.写扩展并不复杂,只要根据chrome提供的一系列的API进行就可以实现很多的功能.只是对API的学习是有代价的,加上国内访 ...
python3.x 学习笔记1(基础知识)
1.python模块: 标准库和第三方库,第三方库需要下载安装 2.模块sys: 命令 功能 sys.stdin 标准输入流sys.stdout 标准输出流sys.stderr ...
python3 速查参考- python基础 8 ->; 面向对象基础:类的创建与基础使用,类属性,property、类方法、静态方法、常用知识点概念(封装、继承等等见下一章)
基础概念 1.速查笔记: #-- 最普通的类 class C1(C2, C3): spam = 42 # 数据属性 def __init__(self, name): # 函数属性:构造函数 self ...
Python3学习(一)-基础、数据类型、变量、字符串和编码、list&;tuple、if、for、while、dict、set、函数与参数
##廖雪峰py3笔记 ## '//'这是获得相除后的整数部分 ##a = 10//3 ##print (a) ## '/'获得相除后的结果,为浮点数,结果能整除也也是浮点数 ##b = 10/3 ## ...
【python3 自动化之mysql操作】python3下的mysql入门基础
1.所需资源:pycharm,python3.6,module:pymysql 2.pycharm配置mysql: 新添加一个mysql数据库 ip:192.168.112.54 端口:3306 ...
随机推荐
深入理解CSS3 Animation 帧动画
CSS3我在5年之前就有用了,包括公司项目都一直在很前沿的技术. 最近在写慕课网的七夕主题,用了大量的CSS3动画,但是真的沉淀下来仔细的去深入CSS3动画的各个属性发现还是很深的,这里就写下关于帧动 ...
C/S端开发问题汇总
0.先推荐几款工具,连接远程客户端DameWare Mini Remote Control,搜索本地文件Everything,以及sysinternals的系列工具: FileMon-监视所有文件修改 ...
chkconfig : No such file or directory
sys_version:12.04LTS For example: #chkconfig --level mysql on /sbin/insserv:No such file or director ...
OAuth 2.0 开发完全详解
--------------------------基础篇------------------------------- I:OAuth 2.0 概述 首先大家来看看国内新浪跟腾讯这两大头对OAuth ...
一大坨GoogleAPI的学习笔记之一(oAuth2.0)
官方文档地址:https://developers.google.com/accounts/docs/OAuth2InstalledApp 最近Ubuntu下VGA接口无端的不能用了,木有心情翻译了, ...
链接脚本之LMA VMA解释
链接脚本中的LMA和VMA是什么意思.这个问题纠结了一段时间,今天在看时,豁然开朗,写下自己的认识.分享例如以下: LMA:载入地址 位于存储器中的地址 LOAD ...
转delphi中 formclose的事件 action:=cafree form:=nil分别是什么意思?
转自:http://www.cnblogs.com/jshchg/articles/1929894.html MDI子窗体关闭时用到的(以下摘自Delphi的帮助)caNone The form i ...
挖洞姿势:特殊的上传技巧,绕过PHP图片转换实现远程代码执行(RCE)
我使用了一个特殊的图片上传技巧,绕过PHP GD库对图片的转换处理,最终成功实现了远程代码执行. 事情是这样的.当时我正在测试该网站上是否存在sql注入漏洞,不经意间我在网站个人页面发现了一个用于上传 ...
6.Solr4.10.3API使用(CURD)
转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.在工程中引入solr-solrj-4.10.3.jar
八.linux系统文件属性知识
1.文件属性权限是12位,现在只看9位,其中每3个一组,为:属主权限.属组权限.其他权限,其中r可读,w可写,x可执行,如图: 2.文件属性之软硬链接 linux系统中有两种链接,为硬链接(ln) ...
python import 类如何捕获clrt c_Python3 与 C# 扩展之~基础衍生相关推荐
- python import 类如何捕获clrt c_PEP8 python规范神器
一.Jupyter notebook 篇 Jupyter notebook的代码要想写得规范,推荐用Code prettify插件. 1.安装插件Nbextensions 1 pip install ...
- python import 类 继承_python学习之类的继承
面向对象中一个重要的特性就是继承,继承的好处就是提高代码的重用率,减少不必要的代码.继承是父类与子类的关系,当子类继承了父类后,就具有了父类的所有变量和方法.在python中定义继承的语法是:clas ...
- python日志类logging的使用
python日志类logging的使用 文章目录 python日志类logging的使用 1.简单使用 2.设置日志级别 3.格式化输出日志 4.一个常用的例子和handler的使用 5 捕获 Tra ...
- python定义类()中写object和不写的区别
python定义类()中写object和不写的区别 这里需要说明一下: python3中,类定义默认继承object,所以写不写没有区别 但在python2中,并不是这样 所以此内容是针对python ...
- python import from class_Python: import vs from (module) import function(class) 的理解
Python: Import vs From (module) import function(class) 本文涉及的 Python 基本概念: Module Class import from . ...
- Python -- dict 类
Python dict类常用方法: class dict(object): def clear(self): #清除字典中所有元素形成空字典,del是删除整个字典: >>> tes ...
- Python动态类和动态方法的创建和调用
借助于python的动态语言特性,很容易对对象进行添加方法或者属性,这也是python的灵活之一. 动态生成类的属性及其方法 在某些情况可能要根据不同的参数来动态生成不同的实例方法.静态方法.类方法. ...
- import的用法python_Python导入模块,Python import用法(超级详细)
Python导入模块,Python import用法(超级详细) 使用 Python 进行编程时,有些功能没必须自己实现,可以借助 Python 现有的标准库或者其他人提供的第三方库.比如说,在前面章 ...
- python数据库连接类写其他类调用报超时_python面向对象,类,以及连接数据库
## 面向对象 ### 1.面向对象三大特性: 封装,继承,多态 ### 1.1.封装 1.在类中对数据的赋值.内部调用对外部用户是透明的 2.这使类变成了一个胶囊或容器,里面包含着类的数据和方法 3 ...
最新文章
- 插值搜索——本质和二分无异,是利用数据分布的规律来定查找点,其基本假设是数据分布均匀...
- 『Python』VS2015编译源码注意事项
- Linux 访问文件的acl信息,linux文件权限管理与ACL访问控制列表
- 直播马上开始│走进腾讯云物联网
- SAP Spartacus ComponentData的提前subscription
- redis存储新闻列表_Redis对象——集合(Set)
- IOS开发之格式化日期时间的使用 编程中常见问题
- Django周总结一
- python爬虫案例——csdn数据采集
- 利用flashback database实现部分对象回滚
- MySQL数据以全量和增量方式,同步到ES搜索引擎
- 2020中兴捧月算法大赛 埃德加考特派 区域优胜奖源代码
- 应变式传感器的原理与优点
- 阿里云盘 WebDAV升级
- 网络运维中静态路由 三层交换技术 动态路由 OSPF协议的配置
- python ——时间间隔
- dmd oracle,【智能科技学院】TF-SWUFE Oracle Club DMD方向召开第五周核心成员分享会...
- 什么是MES生产制造执行系统?实施MES生产管理系统有哪些目标?
- 元宇宙,现实与虚拟交互的新一代互联网?
- 2011年3月《震痛•震恫•震动》
热门文章
- 日料美食海鲜精品海报PSD分层模板,美味势不可挡
- python能做页面加载动画吗_HTML+CSS实现页面加载(loading)动画效果
- C++ 虚析构函数作用
- Windows下消息队列优先级顺序(转载)
- JavaBean规范、EL、JSTL、
- Execution Environment for Non-64-bit Modes 和 64-bit Modes
- RAN adjusts schedule for 2nd wave of 5G specifications
- 2018.10.22 20:10
- 免费制作微信小程序开发关于旅游_教大家怎么一步步免费自己做微信小程序
- php7.2连接mysql8_兼容 php 7.2 及 mysql 8