标签:市场 深度 工厂 import 接口设计 属性 print 计算 方式
class A:
pass
class B(A):
pass
在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或者超类,新建的类称为派生类或者子类
python中类的继承分为,单继承和多继承。
查看继承的方法B.__bases__
如果没有指定基类,python的类会默认集成object类,object是所有python类的基类。
继承是一种‘是’的关系:
人类、猪类、狗类都继承动物类,因而他们都是动物
抽象:抽取类似或者说比较相似的部分
老师是这样定义这个抽象的,并且还介绍了一个抽象类的概念abc
,但是这个抽象的意思翻译过来就是寻找对象的相似点,将对象根据特征进行归纳总结为类的过程。
在找到相似点(也就是“抽象”)之后,其实对象往往还有细分部分的一些特征,并且会有层级地可以划分类别
例如:
动物>>>
人/猪/狗>>>
奥巴马/梅西 // 麦兜/猪八戒 // 史努比/丁丁
由此将对象原本模糊的关注点隔离开,降低复杂度
继承:基于抽象的结果,通过编程语言去实现,经历抽象的过程,通过继承去表达出抽象的结构
class hero:
def __init__(self, name,aggressivity, life_value):
self.name = name
self.aggressivity = aggressivity
self.life_value = life_value
def attack(self,enemy):
print(‘hero attack‘)
class garen(hero):
def __init__(self,name,aggressivity,life_value,script):
hero.__init__(self, name,aggressivity, life_value)
self.script = script
这段代码中,我们就定义了一个英雄类,他的子类盖伦可以继承一些他定义的属性
hero.__init__(self, name,aggressivity, life_value)
这就节约了盖伦类定义的代码,并且给以后定义新的子类英雄提供了便利。
但实际上,这种调用方法跟继承并没有关系,这种类名.函数的调用方法其实可以调用所有其他类的方法。而且当子类修改父类之后,代码还要随之更改,非常麻烦,并不推荐这种方式。
这就是代码的重用
当然子类也可以有自己的属性,例如上面代码中的self.script = script
。
如果说子类自己定义的属性或者方法和父类中有重名,那么就以子类自己定义的为准。
上面使用hero.__init__(self, name,aggressivity, life_value)
就是在调用父类函数的方法作为子类定义函数的参数,在使用父类函数的时候,要记得不能再使用self
,而是跟上要调用的类的名称。
派生:
子类继承了父类的属性,然后衍生出自己新的属性,
如果子类衍生出的新的属性与父类的某个属性名字相同,
那么再调用子类的这个属性,就以子类自己这里的为准了
class A(object):
def test(self):
print(‘from A‘)
class B(A):
def test(self):
print(‘from B‘)
class C(A):
def test(self):
print(‘from C‘)
class D(B):
def test(self):
print(‘from D‘)
class E(C):
def test(self):
print(‘from E‘)
class F(D,E):
# def test(self):
# print(‘from F‘)
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
作业分析:
每定义一个泪,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表:
PyObject* tp_mro
Tuple containing the expanded set of base types, starting with the type itself and
ending with object, in Method Resolution Order.
以元组的形式返回所有基类的扩展的集合,从他本身的类开始,到object类结束
This field is not inherited; it is calculated fresh by PyType_Ready().
这个字段并不是通过继承得到的,而是通过by PyType_Ready()方法计算更新的
>>> class tsr:
… pass
…
>>> str.__mro__
(<class ‘str‘>, <class ‘object‘>)
>>> str.mro()
[<class ‘str‘>, <class ‘object‘>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
方法一:
父类名.父类方法()
不多说,参考上面的引用
方法二:
super()
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
思考题:
上图的代码以及运行结果已经放在图中,下面的代码使用的是纠正使用super()的代码:
class A(object):
def __init__(self):
print("enter A")
super(A, self).__init__() # new
print("leave A")
class B(object):
def __init__(self):
print("enter B")
super(B, self).__init__() # new
print("leave B")
class C(A):
def __init__(self):
print("enter C")
super(C, self).__init__()
print("leave C")
class D(A):
def __init__(self):
print("enter D")
super(D, self).__init__()
print("leave D")
class E(B, C):
def __init__(self):
print("enter E")
super(E, self).__init__() # change
print("leave E")
class F(E, D):
def __init__(self):
print("enter F")
super(F, self).__init__() # change
print ("leave F")
f = F()
小结:
组合对比继承来说,也是用来重用代码,但是组合描述的是一种“有”的关系
老师有课程
学生有成绩
学生有课程
学校有老师
学校有学生
#定义课程类
class Course:
def __init__(self,name,price,period):
self.name=name
self.price=price
self.period=period
#定义老师类
class Teacher:
def __init__(name,course):
self.name=name
self.course=course
#定义学生类
class Student:
def __init__(name,course):
self.name=name
self.course=course
#学生类和老师类中,都有关联到课程这个属性
#所以实例化一项课程
python=Course(‘python‘,15800,‘7m‘)
#在实例化学生和老师的时候, 将实例化后的课程作为参数传入
t1=Teacher(‘egon‘,python)
s1=Student(‘alex‘,python)
#这样学生和老师就获得了课程实例的参数,并且可以引用
print(s1.course.name)
print(s1.course.period)
上述代码就表示了一个“组合”的过程。类之间通过实例化传参的过程,来互相获取一些需要的数据,并且建立关系。
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
=================第一部分:Java 语言中的接口很好的展现了接口的含义: IAnimal.java
/*
* Java的Interface很好的体现了我们前面分析的接口的特征:
* 1)是一组功能的集合,而不是一个功能
* 2)接口的功能用于交互,所有的功能都是public,即别的对象可操作
* 3)接口只定义函数,但不涉及函数实现
* 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了 */
package com.oo.demo;
public interface IAnimal {
public void eat();
public void run();
public void sleep();
public void speak();
}
=================第二部分:Pig.java:猪”的类设计,实现了IAnnimal接口
package com.oo.demo;
public class Pig implements IAnimal{ //如下每个函数都需要详细实现
public void eat(){
System.out.println("Pig like to eat grass");
}
public void run(){
System.out.println("Pig run: front legs, back legs");
}
public void sleep(){
System.out.println("Pig sleep 16 hours every day");
}
public void speak(){
System.out.println("Pig can not speak"); }
}
=================第三部分:Person2.java
/*
*实现了IAnimal的“人”,有几点说明一下:
* 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样
* 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */
package com.oo.demo;
public class Person2 implements IAnimal {
public void eat(){
System.out.println("Person like to eat meat");
}
public void run(){
System.out.println("Person run: left leg, right leg");
}
public void sleep(){
System.out.println("Person sleep 8 hours every dat");
}
public void speak(){
System.out.println("Hellow world, I am a person");
}
}
=================第四部分:Tester03.java
package com.oo.demo;
public class Tester03 {
public static void main(String[] args) {
System.out.println("===This is a person===");
IAnimal person = new Person2();
person.eat();
person.run();
person.sleep();
person.speak();
System.out.println("\n===This is a pig===");
IAnimal pig = new Pig();
pig.eat();
pig.run();
pig.sleep();
pig.speak();
}
}
java中的interface
这里有一篇解释接口的文章,其中关于什么时候使用继承,什么时候用(组合)接口的方面,我看的模模糊糊。但是说不定以后能看懂:http://blog.csdn.net/xiaoxiongli/article/details/2791853
其中有一段解释说的很好,用来描述接口的概念真的妙到毫颤,特意摘下来整理,留作以后装逼用:
一马平川 19:58:54
接口是对类的抽象,我如果直接跟你说接口编程,你一定不理解,或者说很难理解,因为接口本身是很抽象的东西,现在我举例跟你说:
“电源插座就是接口”:
比方说,插座有两孔的,有三孔的,不同的插头需要不同的插座。
接口就描述了能适应的插头范围现在有一种插座是三孔的,但既可以插三孔的,也可插两孔的,知道么?
那么,我们可以说,这个插座设计的好,因为他能适用更广的范围。
当然,这个范围不能超出电源插座这个概念。
如果是用来插笔,做笔筒用,那也不适合。
如果电源插座不但能适用两孔和三孔的插头,还能适用笔的话,那么我们可以肯定的说,这个接口设计的太差了。因为接口(插座)的设计应该是对某一类事物的抽象。而且,接口(插座)实现以后,实现该接口的类(插头)必须符合接口的定义(插座和插口匹配),而且需要完全符合,一点不符合都不行。
所以实现某个接口的类,必须重写接口中定义的所有方法。如果你觉得该方法不需要实现,你可以留空,但必须重写。
看我这句话:“接口只定义了方法的原型,即参数和方法名以及返回值,集成接口的类需要实现它。”
而且,接口(插座)实现以后,实现该接口的类(插头)必须符合接口的定义(插座和插口匹配)。其实,你会发现插座生产出来后,如果某电器的插头和插座不匹配,那么就无法使用该电器了。实际上,你在设计一个接口的时候,很难想到要怎么去设计,尽管你知道集成这个接口的类是怎么样的。就像如果你开一个工厂生产插线板,你在不知道电器,或不完全知道电器的插头如何设计的时候,你是很难生产出能用的插线板的。
那么,如何设计插线板呢?或者说如何设计接口呢?
先看看插线板厂商是如何生产的吧。
某天,有人生产一个电器是4个孔的,那就用不了了。这时候,插线板厂商为了生产出一种插线板,能适用于目前的大部分电器,也能适用于将来的电器,他找到了一个机构。机构是专门指定规则的,专门制定协议的。机构叫来了大部分的重要电器厂商的头头,和插线板老板一起开了个会。大家为了共同的利益,决定了一份协议。
协议是这样的:电器厂商以后生产的电器的插头,只能生产三孔的,但为了兼容目前市场上已有的电器,也能生产两孔的,但是尽量生产三孔的。而且孔的大小和之间的距离有明确的规定。插线板厂商的插线板也只能有两孔的和三孔的,而且孔的大小和之间的距离也必须按照协议来生产。
于是问题解决了,而且插线板厂商老板很聪明,他发现可以生产出既可以插两孔,又可以插三孔的插口,于是他的插线板大卖,他发财了。优秀的接口设计,给他带来了大大的好处,但他很聪明,他没忘记如果没有规范协议的机构,一切都是空白。
再补充几句吧,不然你还是难以理解。
当你想设计一个接口的时候,你最好先写几个将要继承这个几口的类,写几个只有框架而无实际内容的类,看看他们之间的共性,找到写接口的点,这就正如找电器老板来开会。写接口的时候,你需要在之前对接口进行说明,说明接口的适用范围,以及继承该接口的注意事项,这就好比请机构来制定协议规范。有了这些以后,你的接口在被使用的时候就不会错用,在写继承该接口的类的时候,也会按照规范完全的匹配接口。
最后一句话,即使你理解了我今晚所讲的每一句话,你还是不会写接口,因为你需要实践,实践才会出真知。最后这句话才是至理名言,我说的基本都是空话(在你学会了写接口后)。
第一次写接口时,第一个感觉就是,写接口跟没写一样。定义一个接口,马上去写实现类!其实此时就是用着面向过程的思路写程序,然后挂了个羊头,说起来怎么也有个接口了!
今天看了一位老兄写的对于接口的心得体会,真是太有同感了!
不要为了接口而接口,当你把自己不当做是个程序员来思考时,就能把用人的思想来思考了,你不会写程序,就不会考虑细节的实现了!此时你所关注的问题就是比较抽象的了,你看这不正符合面向对象的原则吗?当年张三丰教张无忌打太极就是要把招式全忘了,你要定义接口前就先忘了自己是个程序员吧!
当然不可能有100%的抽象,最终你还是要回到实现细节上来的,可此时你已是学会了太极的张无忌了!
单纯为了代码重用的继承,在实际的使用中很容易造成“高耦合”的问题。
而接口继承,根据接口的概念“给使用接口的对象一个很好的抽象”,将对象的一些特征进行归一化处理,使外部调用者无需关心细节,可以一视同仁地处理特定接口的所有对象。
但是在python中没有interface的概念。在python中定义接口,仅仅是看起来像接口:
第一次写接口时,第一个感觉就是,写接口跟没写一样。定义一个接口,马上去写实现类!其实此时就是用着面向过程的思路写程序,然后挂了个羊头,说起来怎么也有个接口了!
接口提取了一群类共同的函数,可以把接口当做一个函数的集合。
然后让子类去实现接口中的函数。
这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
定义:
抽象类是一个特殊的类,他的特殊之处在于:只能被继承,不能被实例化
为什么要有抽象类
类是对相似的对象进行一个总结
抽象类就是对有共同点的类的一种抽取总结(不完全说是总结,是因为类和类之间一定存在不同,不能完全统一总结成一类,真的是总结关系的话,应该就是子类和父类的关系了)。
从实现的角度来看,抽象类与普通类的不同在于:
抽象类只能有抽象方法(没有实现功能),这类不能被实例化,只能被继承,而且子类必须实现方法
从以上描述来看,抽象类非常类似接口,但是仍然是有差别的。
#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
#一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type=‘file‘
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
‘子类必须定义读功能‘ #如果子类不实现,就会报出此错误,以此来实现类似接口的功能
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
‘子类必须定义写功能‘
pass
# class Txt(All_file):
# pass
#
# t1=Txt() #报错,子类没有定义抽象方法
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print(‘文本数据的读取方法‘)
def write(self):
print(‘文本数据的读取方法‘)
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print(‘硬盘数据的读取方法‘)
def write(self):
print(‘硬盘数据的读取方法‘)
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print(‘进程数据的读取方法‘)
def write(self):
print(‘进程数据的读取方法‘)
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
由上面的代码可以看出,抽象类基本上实现了接口的功能,但是抽象类的本质还是一个类。指的是一组泪的相似性,包括数据属性和函数属性,而接口只强调函数属性的相似性。
所以,抽象类是一个介于类和接口之ijede一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。
标签:市场 深度 工厂 import 接口设计 属性 print 计算 方式
原文地址:http://www.cnblogs.com/scott-lv/p/7468949.html