Python3 与 C# 面向对象之~继承与多态
2.继承¶
代码裤子:https://github.com/lotapp/BaseCode
在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode/master
在线预览:http://github.lesschina.com/python/base/oop/2.继承与多态.html
2.1.单继承¶
在OOP中,当我们定义一个Class的时候,可以从某个现有的Class继承
新的Class称为子类,而被继承的class称为 基类 或者 父类
Python的继承格式 ==> xxx(base_class)
小明兴高采烈的听着老师开新课,不一会就看见了一个演示Demo:
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()
动物会吃
动物会吃
当听到老师说:“私有的属性方法 不会被子类继承 ”的时候,小明心里一颤,联想到之前讲的 类属性、实例属性、实例方法、类方法、静态方法,于是赶紧写个Demo验证一下:
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
我是实例方法,动物会吃哦~
动物
我是类方法,动物会叫哦
我是类方法,动物会叫哦
我是类方法,动物会叫哦
我是静态方法,动物会玩耍哦
我是静态方法,动物会玩耍哦
我是静态方法,动物会玩耍哦
来张图就懂了,不是 私有的 都能访问:
这时候,小明老高兴了,单回头一想 ==> 不科学啊,dog应该有其对应的方法吧,C#有虚方法重写,Python怎么搞?在子类里面又怎么调用父类方法呢?
对于小明的提示老师很高兴,于是点名小潘来写一个子类调用父类的demo(老师昨天从窗户里看见小潘有预习):
# 调用父类的方法
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关键词,别搞混了
小明这时候可不高兴了,风头怎么能被小潘全部抢走呢,赶紧问问旁边同样预习的伟哥
不一会儿淡定的发了份重写父类方法的demo给老师:
# 重写父类方法==>子类和父类有同名方法
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()
这样,我们就获得了继承的另一个好处:多态
2.2.多继承¶
在讲多态
之前,我们先引入一下Python的 多继承 对,你没有听错
Java、C#都是单继承,多实现。Python和C++一样,可以多继承,先不要吐槽,规范使用其实很方便的
来个案例看看:
# 多继承引入
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开始写代码,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写
注意一个情况,如果父类里面有同名方法咋办了?到底调哪个呢?
使用子类名.__mro__
可以看在调方法的时候搜索顺序
一般同名方法都是 先看自己有没有,然后看继承顺序,比如这边 先看Mom再看Father
# 如果父类里面有同名方法怎么知道调哪个?
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的 父类构造函数不会被继承
其实从资源角度也不应该被继承,如果有1w个子类,那每个子类里面都有一个父类方法,想想这是多么浪费的一件事情?
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);
}
}
定义一个学生类
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
2.4C#接口的多实现¶
定义两个接口:
public interface IRun
{
//什么都不用加
void Run();
} public interface IEat
{
void Eat();
}
定义一个Dog类来实现两个接口,这样dog就有了run和eat的方法了
var dog = new Dog();
dog.Eat();
dog.Run();
结果:
狗狗吃
狗狗跑
3 多态¶
3.1.Python¶
说多态之前说说类型判断,以前我们用type()
or isinstance()
判断一个变量和另一个变量是否是同一个类型==> type(a)==type(b)
判断一个变量是否是某个类型==> type(a)==A
or isinstance(a,A)
# 判断一个变量是否是某个类型 ==> 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
小明老高兴了,终于讲解多态了,不禁问道:“多态的好处是啥?”
小潘瞥了一眼小明~“废话,肯定为了 屏蔽子类差异用的啊,像简单工厂不就干的这个事?"
小明楞了楞,眼巴巴的看着老师继续讲课。
设计模式我们会找个专题讲讲,现在给你们说的是Python的基础。
Python是动态语言的“鸭子类型”,它并不要求严格的继承体系。
一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子(最后会贴一个案例)
C#实现多态有很多方式,比如虚方法,比如抽象类,比如接口等等...
小明迷迷糊糊的问道:“那 Python怎么实现多态呢?”
老师看了一眼打断他讲课的小明,然后继续说道~来个简单案例:
class People(object):
def eat(self):
print("人类会吃饭") class Father(People):
def eat(self):
print("优雅的吃饭") class Teacher(People):
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这么写有个好处哦,我们来看个案例,然后你自己总结“
class People(object):
def eat(self):
print("人类会吃饭") class Father(People):
def eat(self):
print("优雅的吃饭") class Teacher(People):
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()
赶时间的吃饭
优雅的吃饭
舔着吃
小明赶紧结合之前学的内容写了个小案例:
class People(object):
def eat(self):
print("人类会吃饭") class Father(People):
def eat(self):
print("优雅的吃饭") class Dog(object):
def eat(self):
print("舔着吃饭") class Factory(object):
@classmethod
def eat(cls, obj):
if hasattr(obj, "eat"):
obj.eat()
else:
raise Exception("该类没有eat()方法!") def main():
people = People()
father = Father()
dog = Dog() Factory.eat(people)
Factory.eat(father)
Factory.eat(dog) if __name__ == '__main__':
main()
人类会吃饭
优雅的吃饭
舔着吃饭
小明突然大声说道:”老师老师,我知道了,Python这是吧类的继承和接口继承融合起来了啊,实现多态就相当于C#里面的接口实现多态啊!!!“
老师点评道:”你姑且可以这么理解,这些我们后面还会继续说的,这种填鸭式的手段刚开始的确会有点不方便,用着用着你就会觉得挺方便的“
小明认真思考总结,然后对照Python和小潘一起写下了 C#版的多态:
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
}
定义一个女孩类:
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}");
}
}
定义一个男孩类:
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岁了,我是一个腼腆的小女孩
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("喵喵叫~~~");
}
}
定义一个狗类
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();
}
结果:
汪汪叫~~~
喵喵叫~~~
3.4.C#接口实现多态¶
定义一个跑的接口:
public interface IRun
{
/// <summary>
/// 接口中可以声明属性,方法,索引器等
/// </summary>
//string Name { get; set; } void Runing();
}
定义一个猫类:
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();
}
结果:
飞快的跑着去上课
飞快的跑着上树
Python3 与 C# 面向对象之~继承与多态的更多相关文章
- Python 面向对象编程 继承 和多态
Python 面向对象编程 继承 和多态 一:多继承性 对于java我们熟悉的是一个类只能继承一个父类:但是对于C++ 一个子类可以有多个父亲,同样对于 Python一个类也可以有多个父亲 格式: c ...
- Day7 初识面向对象,面向对象之继承、多态和封装
一.面向对象引言 一.面向对象的程序设计的由来 详述见:http://www.cnblogs.com/linhaifeng/articles/6428835.html 二.面向对象引子 写一个简单程序 ...
- javascript面向对象:继承、多态
继承 js中同样可以实现类的继承这一面向对象特性,继承父类中的所有成员(变量和属性),同时可扩展自己的成员,下面介绍几种js中实现继承的方式: 1,对象模仿:通过动态的改变 this 指针的指向,实现 ...
- python学习第十五天 -面向对象之继承和多态
大家都知道面向对象的三大特性:封装,继承,多态.封装特性在上一章节已经讲解过.这一章节主要讲解继承和多态. 继承: 当定义一个类的时候,可以从现有的类进行继承.那么新定义的类可以称为子类,被继承的现有 ...
- php 面向对象之继承、多态和静态方法
<?php //继承:子类可以继承父类的一切 //特点:单继承 //父类 class Ren { public $name; public $sex; public $yuyan; functi ...
- Python面向对象:继承和多态
继承与多态简介: 继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写. 动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的. ...
- Java:[面向对象:继承,多态]
本文内容: 继承 多态 首发时期:2018-03-23 继承: 介绍: 如果多个类中存在相同的属性和行为,可以将这些内容抽取到单独一个类中,那么多个类(子类)无需再定义这些属性和行为,只要继承那个类( ...
- Python 面向对象编程——继承和多态
<基本定义> 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超 ...
- python 面向对象(三)--继承和多态
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.Supe ...
- python 面向对象四 继承和多态
一.继承 class Animal(object): def run(self): print('Animal is running...') class Dog(Animal): def run(s ...
随机推荐
- Cookie-parser
let express = require('express'); let app =new express(); // 引入cookie-parser; let cookieParser = req ...
- java对象的四种引用:强引用、软引用、弱引用和虚引用
在JDK1.2之前,创建的对象只有在处于可触及(reachable)的状态下,才能被程序使用.也就是说,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.垃圾回收器一旦发现这些无用对象,就会对 ...
- 【面试】MySQL的事务和索引
MySQL事务 MySQL事务主要用于处理操作量大,复杂度高的数据. 比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这些数据库操作 ...
- Unit 1.前端基础之html
一.什么是html 定义:全称是超文本标记语言(HyperText Markup Language),它是一种用于创建网页的标记语言.标记语言是一种将文本(Text)以及文本相关的其他信息结合起来,展 ...
- Ionic1.x项目中的Installing npm packages问题
与npm远程源有关,可以通过cnpm来解决: 一.ionic start myApp blank --skip-npm(跳过Installing npm packages会产生的问题): 二.然后进入 ...
- spring boot和swagger 整合
本文来源:https://blog.csdn.net/saytime/article/details/74937664 一.依赖 <dependency> <groupId>i ...
- Hibernate 连接不同数据库的方言
RDBMS 方言 DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB2 OS3 ...
- Lodop删除语句Deleted只能内嵌设计维护可用
有些人想用类似如下的语句删除打印项,或判断后把不需要的打印项删除,这种删除语句只能在打印设计或打印维护内嵌的时候使用,打印预览内嵌也不能使用.LODOP.SET_PRINT_STYLEA(2,'Del ...
- 常用css样式处理
1:如何设置html的input框的高度和宽度! 用style来设置,<input style="width:111px;height:111px">
- 2.docker的网络模式
本篇文章使用nginx:apline 镜像进行编辑. docker 版本基于 [root@master song]# docker version Client: Version: API vers ...