面向对象之,基础衍生

By admin in 4858.com on 2019年4月13日

周末多码文,前天中午1篇,明天再来1篇:

 

 

 

在线编制程序:

周一多码文,明天深夜1篇,今日再来一篇:

正文适应人群:C# or Python3 基础巩固

代码裤子:

在线预览:http://github.lesschina.com/python/base/oop/三.非凡相关.html

在线编制程序:

代码裤子:

在线编制程序:https://mybinder.org/v2/gh/lotapp/BaseCode/master
在线预览:http://github.lesschina.com/python/base/oop/贰.后续与多态.html

代码裤子:

在线预览:http://github.lesschina.com/python/base/oop/三.极度相关.html

在线编制程序:

2.继承 ¶

 

代码裤子:

在线预览:http://github.lesschina.com/python/base/ext/基础衍生.html

2.1.单继承 ¶

在OOP中,当大家定义多少个Class的时候,能够从某些现有的Class继承

新的Class称为子类,而被持续的class称为 基类 也许 父类

Python的接续格式 ==> xxx(base_class)

小明神采飞扬的听着教授开新课,不1会就映入眼帘了3个示范德姆o:

In [1]:

class Animal(object):
    def eat(self):
        print("动物会吃")

class Cat(Animal):
    # 注意一下Python的继承格式
    pass

class Dog(Animal):
    pass

def main():
    cat = Cat()
    dog = Dog()
    cat.eat()
    dog.eat()

if __name__ == "__main__":
    main()

 

动物会吃
动物会吃

 

当听见导师说:“ 私有的属性方法 不会被子类继承
”的时候,小明心里壹颤,联想到事先讲的 类属性实例属性
实例方法类方法静态方法,于是赶紧写个德姆o验证一下:

In [2]:

class Animal(object):
    # 类属性
    name = '动物'

    def __init__(self):
        # 实例属性
        self.age = 1

    def __bug(self):
        """实例私有方法"""
        print("我是动物类身上的私有方法:bug")

    def eat(self):
        """实例方法"""
        print("我是实例方法,动物会吃哦~")

    @classmethod
    def call(cls):
        """类方法"""
        print("我是类方法,动物会叫哦")

    @staticmethod
    def play():
        """静态方法"""
        print("我是静态方法,动物会玩耍哦")


class Dog(Animal):
    pass


def main():
    dog = Dog()
    # 实例属性
    print(dog.age)
    # 实例方法
    dog.eat()

    # 类属性
    print(dog.name)
    # 类方法
    dog.call()
    Dog.call()
    Animal.call()

    # 静态方法
    dog.play()
    Dog.play()
    Animal.play()


if __name__ == '__main__':
    main()

 

1
我是实例方法,动物会吃哦~
动物
我是类方法,动物会叫哦
我是类方法,动物会叫哦
我是类方法,动物会叫哦
我是静态方法,动物会玩耍哦
我是静态方法,动物会玩耍哦
我是静态方法,动物会玩耍哦

 

来张图就懂了,不是 私有的 都能访问:

4858.com 1

那时候,小明老洋洋得意了,单回头一想 ==>
不正确啊,dog应该有其对应的点子呢,C#有
虚方法重写,Python怎么搞?在 子类里面又 怎么调用父类方法呢?

对此小明的晋升老师很欣喜,于是点名小潘来写二个子类调用父类的demo(老师今日从窗户里看见小潘有预习):

In [3]:

# 调用父类的方法
class Father(object):
    def eat(self):
        print("文雅的吃饭")


class Son(Father):
    def eat(self):
        # 调用父类方法第1种(super().方法)
        super().eat()


class GrandSon(Son):
    def eat(self):
        # 调用父类方法第2种(记得传self)
        Son.eat(self)


def main():
    xiaoming = Son()
    xiaoming.eat()

    xiaoli = GrandSon()
    xiaoli.eat()


if __name__ == '__main__':
    main()

 

文雅的吃饭
文雅的吃饭

 

诚如大家应用 super().方法来调用父类方法

第二种情势 类名.方法(self)千万别忘记传self哦

对了,C#是用base关键词,别搞混了

小明那时候可不喜气洋洋了,风头怎么能被小潘全体拼抢呢,赶紧问问旁边同样预习的伟哥

不1会儿淡定的发了份重写父类方法的demo给老师:

In [4]:

# 重写父类方法==>子类和父类有同名方法
class Father(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print("%s喜欢文雅的吃饭" % self.name)


class Son(Father):
    def __init__(self, name):
        super().__init__(name)

    def eat(self):
        print("%s喜欢大口吃饭大口喝酒" % self.name)


def main():
    xiaoming = Father("小明")
    xiaoming.eat()

    xiaopan = Son("小潘")
    xiaopan.eat()


if __name__ == "__main__":
    main()

 

小明喜欢文雅的吃饭
小潘喜欢大口吃饭大口喝酒

 

教员职员和工人半喜半忧的说道:“小明同学啊,你也年轻了,怎么跟孩子无异啊?案例不错,可是怎么能人身攻击人家小潘了?”

当子类和父类都设有一样的 eat()方法时,我们说,子类的
eat()覆盖了父类的 eat()

在代码运转的时候,总是会调用子类的 eat()
那样,大家就获得了继承的另一个益处: 多态

1.异常¶

1.异常¶

立马快期末考试了,老师蜜月也回到了,于是有了一场跨季度的复习讲课了:

2.2.多继承 ¶

在讲 多态事先,大家先引进一下Python的 多继承 对,你未有听错

Java、C#都以单继承,多达成。Python和C++1样,能够多再三再四,先不用作弄,
正规使用事实上很便利的

来个案例看看:

In [5]:

# 多继承引入
class Father(object):
    def eat(self):
        print("文雅的吃饭")


class Mom(object):
    def run(self):
        print("小碎步")


class Son(Father, Mom):
    pass


def main():
    son = Son()
    son.eat()
    son.run()


if __name__ == '__main__':
    main()

 

文雅的吃饭
小碎步

 

此起彼伏能够把父类的保有机能都一向拿过来,那样就不用重0初步写代码,子类只须要新增本长逝意的办法,也能够把父类不合乎的点子覆盖重写

小心3个情况,假如父类里面有同名方法怎么做了?到底调哪个吧?

使用 子类名.__mro__能够看在调方法的时候搜索顺序

相似同名方法都是 先看自个儿有未有,然后看后续顺序,比如那边
先看Mom再看Father

In [6]:

# 如果父类里面有同名方法怎么知道调哪个?
class Father(object):
    def eat(self):
        print("文雅的吃饭")


class Mom(object):
    def eat(self):
        print("开心的吃饭")


class Son(Mom, Father):
    pass


def main():
    son = Son()
    son.eat()
    print(Son.__mro__)  # 一般同名方法都是先看自己有没有,然后看继承顺序,比如这边先看Mom再看Father


if __name__ == '__main__':
    main()

 

开心的吃饭
(<class '__main__.Son'>, <class '__main__.Mom'>, <class '__main__.Father'>, <class 'object'>)

 

Python的多继承最棒是当C#大概Java里面包车型大巴接口使用,那样结构不会混杂(
万分处境除了)

来个例证:

class Animal(object):
    pass

class Flyable(object):
    """飞的方法"""
    pass

class Runable(object):
    """跑的方法"""
    pass

class Dog(Animal, Runable):
    pass

class Cat(Animal, Runable):
    pass

class Bird(Animal, Flyable):
    pass

class Dack(Animal, Runable, Flyable):
    """鸭子会飞也会跑"""
    pass

和C#一样,Python的 父类构造函数不会被接续

实则从财富角度也不应当被接续,假若有壹w个子类,那每一种子类里面都有一个父类方法,想想这是何其浪费的1件事情?


1.1 try…except¶

又到了开新课的时候了,小明同学这一次提前预习了文化,乘着老师还没来就在黑板上写下了那段Code:

In [1]:

def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except ZeroDivisionError as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

division by zero

 

1.1 try…except¶

又到了开新课的时候了,小明同学此次提前预习了知识,乘着老师还没来就在黑板上写下了那段Code:

In [1]:

def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except ZeroDivisionError as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

division by zero

 

1.Python基础语法扩大¶

2.3.C#继承 ¶

下课后,小明认真想想计算,然后相比较Python写下了C#版的存在延续:

概念一个人类

public class Person
{
    public string Name { get; set; }
    public ushort Age { get; set; }

    public Person(string name, ushort age)
    {
        this.Name = name;
        this.Age = age;
    }
    public void Hi()//People
    {
        Console.WriteLine("Name: " + this.Name + " Age: " + this.Age);
    }
    public virtual void Show()//People
    {
        Console.WriteLine("Name: " + this.Name + " Age: " + this.Age);
    }
}

概念1个学童类

public class Student : Person
{
    #region 属性
    /// <summary>
    /// 学校
    /// </summary>
    public string School { get; set; }
    /// <summary>
    /// 班级
    /// </summary>
    public string StrClass { get; set; }
    /// <summary>
    /// 学号
    /// </summary>
    public string StrNum { get; set; }
    #endregion

    #region 构造函数
    /// <summary>
    /// 调用父类构造函数
    /// </summary>
    /// <param name="name"></param>
    /// <param name="age"></param>
    public Student(string name, ushort age) : base(name, age)
    {

    }
    public Student(string name, ushort age, string school, string strClass, string strNum) : this(name, age)
    {
        this.School = school;
        this.StrClass = strClass;
        this.StrNum = strNum;
    } 
    #endregion

    /// <summary>
    /// new-隐藏
    /// </summary>
    public new void Hi()//Student
    {
        Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum);
    }
    /// <summary>
    /// override-覆盖
    /// </summary>
    public override void Show()//Student
    {
        Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum);
    }
}

调用一下:

Person p = new Student("app", 10, "北京大学", "001", "01001");
p.Hi(); p.Show();

Console.WriteLine();

Student s = p as Student;
s.Hi(); s.Show();

结果:

Name: app Age: 10
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001
Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001

1.2 try…except…else…finally¶

小潘同学刚进入就映入眼帘了,自语道:“try...except破获卓殊什么人不会?就会这样屁点东西辛亏意思秀,切~
我给您把 格式补全”

于是乘着小明上厕所的时候,擦掉小明的Code,本人写了1段高大上的Code:

In [2]:

# 异常捕获全格式
def test(input_str):
    try:
        eval(input_str)
    except ZeroDivisionError as ex:
        print("except:", ex)
    else:
        print("else:没有异常就奖励100块~")
    finally:
        print("finally:小明是傻子~")


def main():
    test("1/0")
    print("-" * 10)
    test("print('小明啊小明你调坑里了~')")


if __name__ == '__main__':
    main()

 

except: division by zero
finally:小明是傻子~
----------
小明啊小明你调坑里了~
else:没有异常就奖励100块~
finally:小明是傻子~

 

此刻小明和助教1同进入了,同学们隐隐间都听见小明的自夸声:“老师,小编可好了,提前预习并且还写了个demo在黑板上呢~”

教员职员和工人壹进门望着黑板就笑了,同学们也笑成一片。小明心想,咦~难道自身写错了?定眼壹看黑板,气呼呼的回座位了

else能够不写,但是我们
基本上照旧会写的,毕竟能够精通是实在没错误,而不是遮挡了不当

1.2 try…except…else…finally¶

小潘同学刚进入就映入眼帘了,自语道:“try...except破获极度哪个人不会?就会这么屁点东西万幸意思秀,切~
作者给您把 格式补全”

于是乘着小明上洗手间的时候,擦掉小明的Code,自个儿写了壹段高大上的Code:

In [2]:

# 异常捕获全格式
def test(input_str):
    try:
        eval(input_str)
    except ZeroDivisionError as ex:
        print("except:", ex)
    else:
        print("else:没有异常就奖励100块~")
    finally:
        print("finally:小明是傻子~")


def main():
    test("1/0")
    print("-" * 10)
    test("print('小明啊小明你调坑里了~')")


if __name__ == '__main__':
    main()

 

except: division by zero
finally:小明是傻子~
----------
小明啊小明你调坑里了~
else:没有异常就奖励100块~
finally:小明是傻子~

 

那儿小明和先生共同进去了,同学们隐约间都听到小明的自夸声:“老师,笔者可好了,提前预习并且还写了个demo在黑板上呢~”

老师壹进门看着黑板就笑了,同学们也笑成一片。小明心想,咦~难道小编写错了?定眼壹看黑板,气呼呼的回座位了

else能够不写,但是大家
基本上依然会写的,究竟能够明白是确实没错误,而不是挡住了错误

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

 

师资微带笑容的看了小爱他美(Aptamil)眼,然后随着讲if的扩大

2.4C#接口的多达成 ¶

概念四个接口:

public interface IRun
{
    //什么都不用加
    void Run();
}

public interface IEat
{
    void Eat();
}

概念多个Dog类来促成三个接口,那样dog就有了run和eat的点子了

var dog = new Dog();
dog.Eat();
dog.Run();

结果:

狗狗吃
狗狗跑

壹.三 七个可怜处理¶

导师很安心,觉得那几个班真有意思,大家学习空前热情,为了照顾小明,老师反问道:“有何人知道
四个尤其怎么处理?”

小明神速的举手并把黑板上内容擦完,写下了之类代码:

In [3]:

# 多个异常捕获
def main():
    try:
        print(xiaopan)  # NameError: name 'xiaopan' is not defined
        1 / 0  # ZeroDivisionError: division by zero
    except NameError as ex:
        print(ex)
    except ZeroDivisionError as ex:
        print(ex)

if __name__ == '__main__':
    main()

 

name 'xiaopan' is not defined

 

教育工作者问了小澳优(Ausnutria Hyproca)声,有多少个出口?

小明骄傲的说道:“多个,笔者写了三个要命处理,当然都推行了”

校友们又笑了,小潘嘲讽的说了句:“1看就知道二零一八年C#没好好学,那不都相同嘛,相遇尤其上面代码还实好吗?用心血好好考虑”

当大家觉得有个别代码或然会出错开上下班时间,就足以用try来运行那段代码,尽管进行出错,则一而再代码不会继续执行,而是径直跳转至except语句块,执行完except后,如果有finally语句块,则执行finally语句块

小明又窘迫了。。。

一.三 五个分外处理¶

导师很安心,觉得那些班真有意思,大家学习空前热情,为了照看小明,老师反问道:“有什么人知道
三个11分怎么处理?”

小明火速的举手并把黑板上内容擦完,写下了如下代码:

In [3]:

# 多个异常捕获
def main():
    try:
        print(xiaopan)  # NameError: name 'xiaopan' is not defined
        1 / 0  # ZeroDivisionError: division by zero
    except NameError as ex:
        print(ex)
    except ZeroDivisionError as ex:
        print(ex)

if __name__ == '__main__':
    main()

 

name 'xiaopan' is not defined

 

师资问了小爱他美(Nutrilon)声,有多少个出口?

小明骄傲的说道:“七个,作者写了七个11分处理,当然都实施了”

同桌们又笑了,小潘调侃的说了句:“一看就知道二〇一八年C#没好好学,那不都未有差距嘛,欣逢特别上面代码还实行吗?用心血好好思量”

当大家认为有个别代码也许会出错开上下班时间,就足以用try来运营那段代码,假设进行出错,则一连代码不会继续执行,而是一向跳转至except语句块,执行完except后,如果有finally语句块,则执行finally语句块

小明又难堪了。。。

一.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

 

3 多态 ¶

一.4 多尤其简写¶

教育工小编再一次帮小明圆了个场:“已经很不简单了,正是终十分的小得意的时候口误了,那小明同学你驾驭Python里面多特别有个方便写法吗?”

小明赶紧拿起粉笔刷刷刷的写完,然后说道:“of course

In [4]:

# 多个异常捕获的简写(注意哦,是元组哦)
def main():
    try:
        print(xiaopan)  # NameError: name 'xiaopan' is not defined
        1 / 0  # ZeroDivisionError: division by zero
    except (NameError, ZeroDivisionError) as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

name 'xiaopan' is not defined

 

教育工小编赶紧夸了夸小明,心想,哎呦喂终于把这难缠的玩意弄回座位了。

小明走前还不忘说一句:“简写的时候注意格式哦,是 元组 不是逗号分隔”

教育工小编这堂课很轻松,大家都预习了并且内容也比较简单。

随后以咨询的不2秘诀问道:“小潘同学,你明白那三个的基类是何许呢?要是要捕获全体尤其该如何做吧?”

小潘站起来说道:“是BaseException

教师扩大道:“全部的不当类型都持续自BaseException,所以在应用except时索要注意的是,它不仅仅捕获该类型的失实,还把其子类也联合抓获了”

因而一般在破获分外的时候 把子类万分放在前方,父类放在前面

看如下代码:

In [5]:

def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except BaseException as ex:
        print("base:", ex)
    except ZeroDivisionError as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

base: division by zero

 

若果把父类放第一个,那么ZeroDivisionError永远也不会被执行了,其实您若是装了
代码规范提醒插件会唤醒您的

能够参见小编事先写的
vscode设置python三调节和测试环境的扩张多数

来个通用非常捕获的简写(官方不推荐使用简写):

In [6]:

# 直接except就行了
def main():
    try:
        1 / 0
        dnt += 1
    except:
        print("屏蔽错误")


if __name__ == '__main__':
    main()

 

屏蔽错误

 

教员职员和工人继续讲到,我们来看三个场地,未来众多在线编辑器,你在她们这几个编辑框里写下了代码也是有尤其抛出的,那是怎么处理的啊?

微软有开源代码编辑器相比受欢迎(VSCode的1局地):monaco-editor

唤醒一下,假使确实要做在线编辑器,记得怀恋一下fork炸弹,这么些其实也是很老的事物了,程序员基本上都应有接触过了

1.四 多尤其简写¶

教育工我再次帮小明圆了个场:“已经很不不难了,正是终非常小得意的时候口误了,那小明同学你知道Python里面多万分有个方便人民群众写法吗?”

小明赶紧拿起粉笔刷刷刷的写完,然后说道:“of course

In [4]:

# 多个异常捕获的简写(注意哦,是元组哦)
def main():
    try:
        print(xiaopan)  # NameError: name 'xiaopan' is not defined
        1 / 0  # ZeroDivisionError: division by zero
    except (NameError, ZeroDivisionError) as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

name 'xiaopan' is not defined

 

教育工笔者赶紧夸了夸小明,心想,哎呦喂终于把那难缠的家伙弄回座位了。

小明走前还不忘说一句:“简写的时候注意格式哦,是 元组 不是逗号分隔”

教育工我这堂课很轻松,我们都预习了同时内容也比较简单。

接着以咨询的办法问道:“小潘同学,你驾驭那1个的基类是何许吧?纵然要捕获全数尤其该咋做啊?”

小潘站起来说道:“是BaseException

教授扩展道:“全体的一无所长类型都一而再自BaseException,所以在利用except时索要留意的是,它不但捕获该类型的荒谬,还把其子类也联合抓获了”

据此一般在破获至极的时候 把子类极度放在前方,父类放在后边

看如下代码:

In [5]:

def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except BaseException as ex:
        print("base:", ex)
    except ZeroDivisionError as ex:
        print(ex)


if __name__ == '__main__':
    main()

 

base: division by zero

 

万一把父类放第二个,那么ZeroDivisionError千古也不会被执行了,其实你一旦装了
代码规范提醒插件会唤起您的

能够参见笔者前边写的
vscode设置python3调剂环境的扩展部分

来个通用至极捕获的简写(官方不引入应用简写):

In [6]:

# 直接except就行了
def main():
    try:
        1 / 0
        dnt += 1
    except:
        print("屏蔽错误")


if __name__ == '__main__':
    main()

 

屏蔽错误

 

教员职员和工人继续讲到,我们来看1个地方,未来更仆难数在线编辑器,你在他们那个编辑框里写下了代码也是有格外抛出的,那是怎么处理的吗?

微软有开源代码编辑器相比较受欢迎(VSCode的一片段):monaco-editor

升迁一下,假设的确要做在线编辑器,记得记挂一下fork炸弹,这些实在也是很老的东西了,程序员基本上都应有接触过了

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

 

3.1.Python ¶

说多态从前说说类型判断,从前笔者们用 type() or isinstance()

判定二个变量和另一个变量是或不是是同二个品种==> type(a)==type(b)

判断二个变量是或不是是有些项目==> type(a)==A or isinstance(a,A)

In [7]:

# 判断一个变量是否是某个类型 ==> isinstance() or type
class Animal(object):
    pass


class Dog(Animal):
    pass


def main():
    dog = Dog()
    dog2 = Dog()
    print(type(dog) == Dog)
    print(type(dog) == type(dog2))
    print(type(dog))

    print(isinstance(dog, Dog))
    print(isinstance(dog, Animal))
    # arg 2 must be a type or tuple
    # print(isinstance(dog, dog2))


if __name__ == '__main__':
    main()

 

True
True
<class '__main__.Dog'>
True
True

 

小明老心花怒放了,终于讲解多态了,不禁问道:“ 多态的功利是啥?”

小潘瞥了壹眼小明~“废话,肯定为了
屏蔽子类差别用的哎,像简单工厂不就干的那几个事?”

小明楞了楞,眼Baba的望着教授继续上课。

设计形式我们会找个专题讲讲,以往给你们说的是Python的基本功。

Python是动态语言的“ 鸭子类型”,它并不必要严俊的接轨体系。

3个指标只要“看起来像鸭子,走起路来像鸭子”,那它就能够被看作是鸭子(最终会贴二个案例)

C#落实多态有那三个方法,比如虚方法,比如抽象类,比如接口等等…

小明迷迷糊糊的问道:“那 Python怎么落到实处多态呢?”

教员看了壹眼打断他上书的小明,然后继续协商~来个大致案例:

In [8]:

class People(object):
    def eat(self):
        print("人类会吃饭")

class Father(object):
    def eat(self):
        print("优雅的吃饭")

class Teacher(object):
    def eat(self):
        print("赶时间的吃饭")

# C# 或者 Java里面 写成 eat(People obj)
def eat(obj):
    obj.eat()

def main():
    teacher = Teacher()
    father = Father()
    eat(teacher)
    eat(father)

if __name__ == '__main__':
    main()

 

赶时间的吃饭
优雅的吃饭

 

多态的利益在于,倘使那时作者再来个Son子类,有eat()方法编写正确,不用管原来的代码是怎么调用的

本次小明懂了,为了装一下,说道:”老师老师,作者纪念C# 或许 Java里面是写成
eat(People obj) 的吗?“

导师欣慰的笑了一下,说道:”记得刚才说的
填鸭式呢?Python这么写有个便宜哦,大家来看个案例,然后您协调计算“

In [9]:

class People(object):
    def eat(self):
        print("人类会吃饭")

class Father(object):
    def eat(self):
        print("优雅的吃饭")

class Teacher(object):
    def eat(self):
        print("赶时间的吃饭")

class Dog(object):
    def eat(self):
        print("舔着吃")

def eat(obj):
    obj.eat()

def main():
    teacher = Teacher()
    father = Father()
    eat(teacher)
    eat(father)

    # 我们添加一个不是People子类的Dog类,只要有eat方法,参数一样就可以直接调
    dog = Dog()
    eat(dog)

if __name__ == '__main__':
    main()

 

赶时间的吃饭
优雅的吃饭
舔着吃

 

小明突然大声说道:”老师老师,作者驾驭了,Python那是吧类的三番五次和接口继承融合起来了啊,实现多态就一定于C#在那之中的接口完结多态啊!!!“

老师点评道:”你姑且能够这么清楚,这一个我们后边还会再三再四说的,那种填鸭式的手段刚开端确实会有点不便于,用着用着您就会以为挺方便的“


小明认真思虑总结,然后比较Python和小潘1起写下了 C#版的多态

壹.5 抛出11分¶

我们继续,像C#是用thorw抛出特别,那Python怎么 捕获异常后再抛出
呢?怎么自定义异常 呢?

继续往下看:

In [7]:

# 捕获异常后再丢出,eg:在线运行的用户Code
def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except ZeroDivisionError as ex:
        print(ex)  # 写个日志,回头出问题可以深究
        raise


if __name__ == '__main__':
    main()

 

division by zero

 

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-7-15f01346e2d8> in <module>()
      9 
     10 if __name__ == '__main__':
---> 11main()

<ipython-input-7-15f01346e2d8> in main()
      2 def main():
      3     try:
----> 41 / 0  # ZeroDivisionError: division by zero
      5     except ZeroDivisionError as ex:
      6         print(ex)  # 写个日志,回头出问题可以深究

ZeroDivisionError: division by zero

In [8]:

# 抛出自定义异常
class DntException(BaseException):
    pass


def get_age(num):
    if num <= 0:
        raise DntException("num must>0")
    else:
        print(num)


def main():
    get_age(-1)
    get_age(22)  # 程序崩了,这句话不会被执行了


if __name__ == '__main__':
    main()

 

---------------------------------------------------------------------------
DntException                              Traceback (most recent call last)
<ipython-input-8-7c9dec6ec225> in <module>()
     17 
     18 if __name__ == '__main__':
---> 19main()

<ipython-input-8-7c9dec6ec225> in main()
     12 
     13 def main():
---> 14get_age(-1)
     15     get_age(22)  # 程序崩了,这句话不会被执行了
     16 

<ipython-input-8-7c9dec6ec225> in get_age(num)
      6 def get_age(num):
      7     if num <= 0:
----> 8raise DntException("num must>0")
      9     else:
     10         print(num)

DntException: num must>0

 

尤其那壹块大致讲完了(logging模块前边会说)有怎么样补充的能够说的^_^

 

一.伍 抛出十三分¶

我们再而三,像C#是用thorw抛出尤其,那Python怎么 捕获异常后再抛出
呢?怎么自定义异常 呢?

此起彼伏往下看:

In [7]:

# 捕获异常后再丢出,eg:在线运行的用户Code
def main():
    try:
        1 / 0  # ZeroDivisionError: division by zero
    except ZeroDivisionError as ex:
        print(ex)  # 写个日志,回头出问题可以深究
        raise


if __name__ == '__main__':
    main()

 

division by zero

 

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-7-15f01346e2d8> in <module>()
      9 
     10 if __name__ == '__main__':
---> 11main()

<ipython-input-7-15f01346e2d8> in main()
      2 def main():
      3     try:
----> 41 / 0  # ZeroDivisionError: division by zero
      5     except ZeroDivisionError as ex:
      6         print(ex)  # 写个日志,回头出问题可以深究

ZeroDivisionError: division by zero

In [8]:

# 抛出自定义异常
class DntException(BaseException):
    pass


def get_age(num):
    if num <= 0:
        raise DntException("num must>0")
    else:
        print(num)


def main():
    get_age(-1)
    get_age(22)  # 程序崩了,这句话不会被执行了


if __name__ == '__main__':
    main()

 

---------------------------------------------------------------------------
DntException                              Traceback (most recent call last)
<ipython-input-8-7c9dec6ec225> in <module>()
     17 
     18 if __name__ == '__main__':
---> 19main()

<ipython-input-8-7c9dec6ec225> in main()
     12 
     13 def main():
---> 14get_age(-1)
     15     get_age(22)  # 程序崩了,这句话不会被执行了
     16 

<ipython-input-8-7c9dec6ec225> in get_age(num)
      6 def get_age(num):
      7     if num <= 0:
----> 8raise DntException("num must>0")
      9     else:
     10         print(num)

DntException: num must>0

 

卓殊那一块大概讲完了(logging模块后边会说)有啥补充的可以说的^_^

 

壹.3.值论断和地方判断¶

小明不乐意了,你个小潘总是抢小编的事态,看完标题就刷刷的在黑板上写下了如下知识点:

is 是比较八个引用是不是对准了同叁个指标id()获得的地址一样则同样)

== 是比较八个对象的值是还是不是等于

在事先讲Dict的时候提了一下可变和不得变类型:https://www.cnblogs.com/dotnetcrazy/p/91553十.html\#五.2.充实和修改

Func里面又系统的说了一晃:https://www.cnblogs.com/dotnetcrazy/p/9175950.html\#肆.5.可变类型和不可变类型

对此可变不可变连串就不去复述了,上边再来多少个案例看看 值判断
地点判断的概念

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

 

3.2.C#虚方法完成多态 ¶

概念多少个生人:

public class Person
{
    #region 字段+属性
    /// <summary>
    /// 姓名
    /// </summary>
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }

        set
        {
            _name = value;
        }
    }
    /// <summary>
    /// 性别
    /// </summary>
    private bool _gender;
    public bool Gender
    {
        get
        {
            return _gender;
        }

        set
        {
            _gender = value;
        }
    }
    /// <summary>
    /// 年龄
    /// </summary>
    public short Age { get; set; }
    #endregion

    #region 构造函数
    public Person() { }
    public Person(string name, bool gender)
    {
        this.Name = name;
        this.Gender = gender;
    }
    public Person(string name, bool gender, short age) : this(name, gender)
    {
        this.Age = age;
    }
    #endregion

    #region 方法
    /// <summary>
    /// 打招呼
    /// </summary>
    public virtual void SaiHi()
    {
        Console.WriteLine("我是一个人类!");
    }
    #endregion
}

概念3个女孩类:

public class Gril : Person
{
    #region 构造函数
    public Gril() { }
    public Gril(string name, bool gender) : base(name, gender) { }
    public Gril(string name, bool gender, short age) : base(name, gender, age) { }
    #endregion

    /// <summary>
    /// 重写父类方法
    /// </summary>
    public override void SaiHi()
    {
        string genderStr = Gender == true ? "男孩" : "女孩";
        Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}");
    }
}

概念1个男孩类:

public class Boy : Person
{
    #region 构造函数
    public Boy() { }
    public Boy(string name, bool gender) : base(name, gender) { }
    public Boy(string name, bool gender, short age) : base(name, gender, age) { }
    #endregion

    //public void SaiHi()
    public override void SaiHi()
    {
        string genderStr = Gender == true ? "男孩" : "女孩";
        Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}");
    }
}

调用:

static void Main(string[] args)
{
    Person[] persons = { new Person(), new Boy("铁锅", true, 13), new Gril("妞妞", false, 22) };
    foreach (var item in persons)
    {
        //看看item里面到底放的是什么
        Console.WriteLine(item.ToString());
        item.SaiHi();
        Console.WriteLine();
    }
}

结果:

Polymorphism1.Person
我是一个人类!
Polymorphism1.Boy
你好,我叫铁锅,今年13岁了,我是一个腼腆的小男孩
Polymorphism1.Gril
你好,我叫妞妞,今年22岁了,我是一个腼腆的小女孩

 


1.6 C#异常¶

小明又举办了C#的代码转换,怎么看都觉着依旧C#简短啊,根本无须说吗,代码一贴就秒懂了。。。

In [1]:

%%script csharp
try
{
    Convert.ToInt32("mmd");
}
catch (Exception ex)
{
    // Input string was not in a correct format
    Console.WriteLine(ex.Message);
}

 

Input string was not in a correct format.

In [2]:

%%script csharp
//抛出自定义异常
try
{
    throw new Exception("出错了啊");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

 

出错了啊

 

你能够自定义十二分类,继承Exception即可,对了C#其间也是有finally的

try
{
    throw new Exception("出错了啊");
    //Convert.ToInt32("mmd");
}
catch (Exception ex)
{
    // Input string was not in a correct format
    Console.WriteLine(ex.Message);
}
finally
{
    Console.WriteLine("finally");
}

先天部分供给finally的地点大多都被using(){}接管了,所以一定情景会利用

先这么了

1.6 C#异常¶

小明又拓展了C#的代码转换,怎么看都是为依旧C#简单啊,根本不用说吗,代码1贴就秒懂了。。。

In [1]:

%%script csharp
try
{
    Convert.ToInt32("mmd");
}
catch (Exception ex)
{
    // Input string was not in a correct format
    Console.WriteLine(ex.Message);
}

 

Input string was not in a correct format.

In [2]:

%%script csharp
//抛出自定义异常
try
{
    throw new Exception("出错了啊");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

 

出错了啊

 

您能够自定义非常类,继承Exception即可,对了C#当中也是有finally的

try
{
    throw new Exception("出错了啊");
    //Convert.ToInt32("mmd");
}
catch (Exception ex)
{
    // Input string was not in a correct format
    Console.WriteLine(ex.Message);
}
finally
{
    Console.WriteLine("finally");
}

明天部分索要finally的地点大多都被using(){}接管了,所以一定情景会使用

先那样了

2.Python总结之for系列¶

师资徐徐道来:“以前说for总是零零散散的,未来基础都讲完了,来个小汇总:”

3.3.C#抽象类完结多态 ¶

概念三个动物类:

public abstract class Animal
{
    /// <summary>
    /// 抽象类中可以有正常的方法
    /// </summary>
    public void Action()
    {
        Console.WriteLine("动物可以动");
    }

    /// <summary>
    /// 抽象方法必须在抽象类中
    /// </summary>
    public abstract void Call();
}

概念多少个猫科动物类(子类必须落成父类抽象方法,假使不兑现,那么该类也亟须是抽象类)

/// <summary>
/// 猫科动物---子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类
/// </summary>
public abstract class Feline : Animal
{
}

概念贰个猫类

public class Cat : Feline
{
    /// <summary>
    /// 子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类
    /// </summary>
    public override void Call()
    {
        Console.WriteLine("喵喵叫~~~");
    }
}

概念1个狗类

public class Dog : Animal
{
    /// <summary>
    /// 子类必须实现抽象类中的抽象方法
    /// </summary>
    public override void Call()
    {
        Console.WriteLine("汪汪叫~~~");
    }
}

调用:

Animal[] animals = { new Dog(), new Cat() };
foreach (var item in animals)
{
    item.Call();
}

结果:

汪汪叫~~~
喵喵叫~~~

 


2.1.Base¶

可见被for循环遍历的,正是可迭代的

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

 

3.4.C#接口达成多态 ¶

概念2个跑的接口:

public interface IRun
{
    /// <summary>
    /// 接口中可以声明属性,方法,索引器等
    /// </summary>
    //string Name { get; set; }

    void Runing();
}

概念1个猫类:

public class Cat : IRun
{
    public void Runing()
    {
        Console.WriteLine("飞快的跑着上树");
    }
}

概念八个上学的小孩子类:

public class Student : IRun
{
    public void Runing()
    {
        Console.WriteLine("飞快的跑着去上课");
    }
}

调用:

IRun[] objs = { new Student(), new Cat() };
foreach (var item in objs)
{
    item.Runing();
}

结果:

飞快的跑着去上课
飞快的跑着上树

二.二.列表生成式¶

要是上面知识点还面生的,看看前边讲的~列表生成式:https://www.cnblogs.com/dotnetcrazy/p/91553拾.html\#一.玖.列表生成式

简写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函数能够把1个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.赋值¶

通过=来促成,就是把地点拷贝了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]4858.com ,:

# 再验证一下

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]]

 

三.肆.文化增加¶

假若拷贝的目的是不行变类型,不管深拷贝和浅拷贝以及赋值都是地方引用

内需专注的是: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

 

4.CSharp中赋值、浅拷贝、深拷贝¶

小明听懂了Python的深拷贝和浅拷贝后,本着学以致用的条件,写下了C#的实现:

先声澳优下,本机环境是Ubuntu + NetCore,欢迎贴Code补充

4.1.赋值¶

Code:

赋值方法和Python无差距于,间接赋值即可

var list1 = new List<int>() { 1, 2, 2 };
var list2 = list1;

In [68]:

%%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 + " ");
}

 

1 2 2 3 
1 2 2 3 

 

4.二值类型暗许深拷贝¶

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

四.三.引用类型私下认可浅拷贝¶

对于List<T>再复杂点的,上面的措施就改成浅拷贝了:(类似于Python的Copy.Copy)

合法的CopyTo在此处和这一个功能一样,不过正如费心,那边就不贴了(德姆o里面贴了)

概念1个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

 

四.肆.简单形式完成深拷贝¶

对于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

 

肆.5.种类化情势贯彻深拷贝(常用)¶

利用System.Runtime.Serialization种类化与反体系化达成深拷贝

先定义3个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生成器¶

1来看标题小明又懵圈了,不过看看大家就像是都清楚的典范心想道:“作者是或不是又睡过壹节课啊?”

前边有讲列表生成式,那边说说生成器

通过列表生成式,我们得以不难并向来的开创2个列表,不过当数码有自然的原理而且又相当的大的时候,使用列表就有点浪费能源了

只要列表成分得以根据某种算法推算出来,那样就不用创造完整的list,从而节省多量的财富

5.一.容易格局¶

在Python中,这种单方面循环一边盘算的编写制定,称为生成器:generator

先看3个不难的生成器案例:(比方把贰个列表生成式的[]改成()
,就创办了3个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]:

<generator object <genexpr> at 0x7f14c413cb48>

 

遍历格局能够用事先的for循环来遍历(推荐)

也足以用next()或者__next__()措施来遍历。【C#是用MoveNext

generator保留的是算法,每回调用next(xxx)或者__next__(),就总括出下二个要素的值,直到总计到结尾二个成分

当未有更多的成分时,抛出StopIteration的异常

最新的Python叁.7在那下边具有优化:

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)
<ipython-input-72-9897a9148994> in <module>()
     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终止了,从来到最终

生成器的风味:

  1. 节本省部存款和储蓄器
  2. 迭代到下贰回的调用时,所采纳的参数都以第1回所保留下的(全体函数调用的参数都以首先次所调用时保留的,而不是新成立的)

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]:

<generator object fibona at 0x7f14c40efd58>

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的巡回的时候

小明总计如下:

  1. 在Python中,那种单方面循环1边盘算的体制称为生成器:generator

  2. 每二个生成器都以一个迭代器(迭代器不肯定是生成器)

  3. 假若三个函数包括yield关键字,这一个函数就会化为三个生成器

  4. 生成器并不会一回回到全部结果,而是每便蒙受yield关键字后归来相应结果,并保留函数当前的运维状态,等待下叁遍的调用

  5. 由于生成器也是二个迭代器,那么它就援救next用艺术来赢得下三个值(大家平常用for来遍历它)

引入一篇著作,总计的很全了:(yield用法总计)

5.3.扩展之~send(msg)方法:¶%E6%96%B9%E6%B3%95%EF%BC%9A)

其实__next__()send()在肯定意义上效益是相似的,不相同是send()能够传递yield表明式的值进去

__next__()不 能传递特定的值。咱们得以当作x.__next__()
x.send(None) 效率是1样的

In [79]:

# 来个案例:
def test_send(n):
    for i in range(n):
        tmp = yield i
        print(tmp)


g = test_send(5)

g

Out[79]:

<generator object test_send at 0x7f14c40efdb0>

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

斩草除根:要么1先导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)
<ipython-input-82-2e891aa5dd81> in <module>()
      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.扩展之~returnbreak的说明¶

在一个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时,发现拿不到generatorreturn讲话的重临值

借使想要得到重返值,必须捕获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)
<ipython-input-89-bcc0083d4089> in <module>()
      7 c.send("小潘")
      8 # 生产结束,通知消费者结束,抛出StopIteration异常
----> 9c.send(None) # 使用c.close()可以避免异常

StopIteration: 

 

施行流程

  1. 始建筑协会程对象(消费者)后,必须使用send(None)__next__()启动
  2. 协程在执行yield后让出执行绪,等待音讯
  3. 调用方发送send(msg)新闻,协程复苏执行,将吸纳到的数据保存并施行后续流程
  4. 再次循环到yield,协程再次来到后面包车型地铁处理结果,并再度让出执行绪
  5. 直到关闭或被掀起那一个

补全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#版的觉得能够获得一大群眼球~

陆.一.论断是或不是可迭代¶

在说迭代器前先说下可迭代(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

 

陆.2.论断是还是不是是迭代器¶

迭代器是毫无疑问能够迭代的,怎么判断是迭代器呢?

能够接纳next格局的要么经过isinstance(xxx,Iterator)

In [99]:

a=[1,2,3]

next(a)

 

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-99-f5f8ac9a8550> in <module>()
      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.IterableIterator

生成器都以Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator

list、dict、strIterable变成Iterator能够使用iter()函数:

In [103]:

iter(a)

Out[103]:

<list_iterator at 0x7f14c40a3da0>

In [104]:

isinstance(iter([]),Iterator)

Out[104]:

True

In [105]:

isinstance(iter({}),Iterator)

Out[105]:

True

 

Python的Iterator目的表示的是1个数据流,Iterator指标足以被next()or__next__()函数调用并不止返回下三个数码,直到未有数据时抛出StopIteration错误

能够把那几个数据流看做是二个平稳种类,但我们却不能够提前领略连串的尺寸,只可以不停经过next函数完毕按需计算下两个多少,所以Iterator的盘算是惰性的,唯有在急需回到下三个数目时它才会推断。

Iterator竟然能够象征多个最为大的数据流,而list等则充足

小明总计了一晃民间兴办教授讲解的知识点:

  1. 可以for循环的指标都是Iterable类型

  2. 能够运用next()or__next__()函数的指标都以Iterator类型

  3. 聚拢数据类型如list、dict、str等是Iterable,能够经过iter()函数得到2个Iterator对象

 

7.CSharp迭代器¶

乘着下课的时日,小明跑到黑板前,心想:“又到了C#的时候了,看本人来收播一大群眼球~”,然后早先了他的个人秀:

其实迭代器(iterator不畏为了更简明的创办枚举器(enumerator)和可枚举类型(enumerator type)的方式

7.1.IEnumeratorIEnumerable

起始话讲:

能不能foreach就看您遍历对象有未有落到实处IEnumerable,就印证您是还是不是2个可枚举类型enumerator type

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

是否个枚举器(enumerator)就看您兑现了IEnumerator接口没

public interface IEnumerator
{
    object Current { get; }

    bool MoveNext();

    void Reset();
}

最令人侧指标区别:它们八个遍历格局不1样

// 枚举器遍历
var tmp = FibonaByIEnumerator(30);
while (tmp.MoveNext())
{
    Console.WriteLine(tmp.Current);
}
// 可枚举类型遍历
foreach (var item in FibonaByIEnumerable(30))
{
    Console.WriteLine(item);
}

这几个大家在二年前就说过,那边简单提一下(法定文书档案)(Demo)

MyEnumerator文件:

public class MyEnumerator : IEnumerator
{
    /// <summary>
    /// 需要遍历的数组
    /// </summary>
    private string[] array;
    /// <summary>
    /// 有效数的个数
    /// </summary>
    private int count;
    public MyEnumerator(string[] array, int count)
    {
        this.array = array;
        this.count = count;
    }

    /// <summary>
    /// 当前索引(线moveNext再获取index,用-1更妥)
    /// </summary>
    private int index = -1;
    public object Current
    {
        get
        {
            return array[index];
        }
    }
    /// <summary>
    /// 移位
    /// </summary>
    /// <returns></returns>
    public bool MoveNext()
    {
        if (++index < count)
        {
            return true;
        }
        return false;
    }
    /// <summary>
    /// 重置
    /// </summary>
    public void Reset()
    {
        index = -1;
    }
}

MyArray.cs文件

public partial class MyArray
{
    /// <summary>
    /// 数组容量
    /// </summary>
    private string[] array = new string[4];
    /// <summary>
    /// 数组元素个数
    /// </summary>
    private int count = 0;
    /// <summary>
    /// 当前数组的长度
    /// </summary>
    public int Length
    {
        get
        {
            return count;
        }
    }

    /// <summary>
    /// 添加元素
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// 移除某一项
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public MyArray RemoveAt(int i)
    {
        for (int j = i; j < count - 1; j++)
        {
            array[j] = array[j + 1];
        }
        count--;//少了一个元素所以--
        return this;
    }

    /// <summary>
    /// 索引器
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public string this[int index]
    {
        get
        {
            return array[index];
        }
        set
        {
            array[index] = value;
        }
    }
}

MyArrayExt.cs文件:

public partial class MyArray: IEnumerable
{
    /// <summary>
    /// 枚举器方法
    /// </summary>
    /// <returns></returns>
    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)的措施

如果枚举器和可枚举类型仍然不知晓(举个例子)就懂了:(从遍历格局就阅览差距了)

概念一个斐波拉契函数,再次回到可枚举类型

/// <summary>
/// 返回一个可枚举类型
/// </summary>
public static IEnumerable<int> 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);
}

概念1个斐波拉契函数,重临3个枚举器

/// <summary>
/// 返回一个枚举器
/// </summary>
public static IEnumerator<int> 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
{
    /// <summary>
    /// 数组容量
    /// </summary>
    private string[] array = new string[4];
    /// <summary>
    /// 数组元素个数
    /// </summary>
    private int count = 0;
    /// <summary>
    /// 当前数组的长度
    /// </summary>
    public int Length
    {
        get
        {
            return count;
        }
    }

    /// <summary>
    /// 添加元素
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// 移除某一项
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// 索引器
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public string this[int index]
    {
        get
        {
            return array[index];
        }
        set
        {
            array[index] = value;
        }
    }
}

MyArrayExt.cs

public partial class MyArray : IEnumerable
{
    /// <summary>
    /// 枚举器方法
    /// </summary>
    /// <returns></returns>
    public IEnumerator GetEnumerator()
    {
        return MyEnumerator();
    }
    /// <summary>
    /// 通过yield快速实现
    /// </summary>
    /// <returns></returns>
    public IEnumerator<string> 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 breakC#使用yield break来退出迭代

做个
demo
测试下:

public static IEnumerable<int> 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()函数

 

<function slow_sum.<locals>.get_sum at 0x7f57783b6268>
15

 

其实上边1个案例就是闭包(Closure)了,来个概念:

在函数内部再定义3个函数,并且这么些函数用到了异地函数的变量(参数或者局部变量),那么将以此函数以及利用的有些变量称之为闭包

通俗点说正是:内部函数使用了外部函数作用域里的变量了,那这个内部函数和它用到的变量就是个闭包

专注:当大家调用slow_sum()时,每便调用都会回来二个新的函数(相同的参数也1如既往)

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的功效便是:

把一个函数的一点参数设置暗中认可值,重返1个新的函数,然后调用新函数就免得你再输入重复参数了

而此时使用闭包就相比较适合了,而且确实是包装了一个通用公式了

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]

 

4858.com 2

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<int> 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是2个函数,等你调用f1()才会求和)

System.Func`1[System.Int32]
15

随之讲 ~ 以地点的 y=ax²+bx+c为例,C#实现:

// 以上面的 y=ax²+bx+c 为例,C#实现:
public static Func<double, double> 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<double,double>不精晓就看看定义就懂了:public delegate TResult Func<in T, out TResult>(T arg);

那有的不是很难,不难提一下知识点即可。借使您想追究能够==>
(点

点)

在得到满满一箩筐眼珠后,小明拍拍臀部去了新开的饮食店大吃一顿了…


写在最终:还有壹部分内容没写,测度过几天又有壹篇叫 “基础进行”
的稿子了,为何差别台写完呢?

实则逆天也想写完,真写完文章又被称呼洋洋万言一百页了 #^_^#
行了,听取大家见识,不写那么长的小说,下次见~

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有