Pyhton-类(2)
·类(2)
@ 继承(inheritance)
什么是继承:
B继承A:A是父类(超类),B是子类(基类)。继承可以实现代码重复利用,实现属性和方法继承。
继承可以使子类拥有父类的属性和方法,也可以重新定义某些属性、重写某些方法,即覆盖父类原有的属性和方法,使其获得父类不同的功能。当然,也可以在子类中新设置属性和方法。从技术上看,OOP里继承最主要的用途是实现多态,对于多态而言,最重要的是接口的继承性(属性和方法是否存在继承性),这是不一定的。继承也不是全为了代码的重复利用,而是为了理顺关系。
对于 Python 中的继承,前面一直在使用,那就是我们写的类都是新式类,所有新式类都是继承自 object 类。不要忘记,新式类的一种写法:
class NewStyle(object):
pass
这就是典型的继承。
继承的基本概念:
class Person:
def __init__(self,name):
self.name = name def get_name(self):
print ("hello,{}!".format(self.name)) def setHeight(self, n):
self.length = n def breast(self, n):
print ("My breast is: ",n) class Boy(Person):
def setHeight(self):
print ("The height is:1.80m .") j = Boy('jimmy')
j.get_name()
j.setHeight()
j.breast(90)
打印结果:
hello,jimmy!
The height is:1.80m .
My breast is: 90
首先,定义了一个父类 Person,定义一个子类 Boy,Boy类的括号中是Person,这就意味着 Boy 继承了 Person,Boy 是 Person 的子类,Person 是 Boy 的父类。那么 Boy 就全部拥有了 Person 中的方法和属性。
如果 Boy 里面有一个和 Person 同样名称的方法,那么就把 Person 中的同一个方法遮盖住了,显示的是 Boy 中的方法,这叫做方法的重写。实例化类 Boy之后,执行实例方法 j.setHeight(),由于在类 Boy中重写了 setHeight 方法,那么 Person 中的那个方法就不显作用了,在这个实例方法中执行的是类 Boy 中的方法。
虽然在类 Boy 中没有看到 get_name() 方法,但是因为它继承了 Person,所以 j.get_name() 就执行类 Person 中的方法。同理 j.breast(90) ,它们就好像是在类 Boy 里面已经写了这两个方法一样。既然继承了,就可以使用。
多重继承:
子类继承多个父类:
class Person:
def eye(self):
print("two eyss")
def breast(self,n):
print("the breast is:",n)
class Girl:
age = 18
def color(self):
print("the girl is white.")
class HotGirl(Person,Girl):
pass
在类的名字后面的括号中把所继承的两个类的名字写上,HotGirl 就继承了Person 和 Girl这两个类。实例化类 HotGirl,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。在类 Girl 中, age = 28,在对 HotGirl 实例化之后,因为继承的原因,这个类属性也被继承到 HotGirl 中,因此通过实例得到它。
继承的特点,即将父类的方法和属性全部承接到子类中;如果子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。
多重继承的顺序:
如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
class K1(object):
def foo(self):
print("K1-foo")
class K2(object):
def foo(self):
print("K2-foo")
def bar(self):
print("K2-bar")
class J1(K1, K2):
pass
class J2(K1, K2):
def bar(self):
print("J2-bar")
class C(J1, J2):
pass print(C.__mro__)
m = C()
m.foo()
m.bar()
打印结果:
(<class '__main__.C'>, <class '__main__.J1'>, <class '__main__.J2'>, <class '__main__.K1'>, <class '__main__.K2'>, <class 'object'>)
K1-foo
J2-bar
print C.__mro__打印出类的继承顺序。
从上面清晰看出来了,如果要执行 foo() 方法,首先看 J1,没有,看 J2,还没有,看 J1 里面的 K1,有了,即 C(没有)==>J1(没有)==>J2(没有)==>K1(找到了);bar() 也是按照这个顺序,在 J2 中就找到了一个。
这种对继承属性和方法搜索的顺序称之为“广度优先”。新式类用以及 Python3.x 中都是按照此顺序原则搜寻属性和方法的。
但是,在旧式类中,是按照“深度优先”的顺序的。因为后面读者也基本不用旧式类,所以不举例。
@ super函数
对于初始化函数的继承,跟一般方法的继承不同:
class Person:
def __init__(self):
self.height = 160
def about(self, name):
print("{} is about {}".format(name, self.height))
class Girl(Person):
def __init__(self):
self.breast = 90
def about(self, name):
print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)) cang = Girl()
cang.about("wangguniang")
打印结果:
Traceback (most recent call last):
File "test1.py", line 14, in <module>
cang.about("wangguniang")
File "test1.py", line 11, in about
print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast))
AttributeError: 'Girl' object has no attribute 'height'
在上面这段程序中,类 Girl 继承了类 Person。在类 Girl 中,初始化设置了 self.breast = 90,由于继承了 Person,按照前面的经验,Person 的初始化函数中的 self.height = 160 也应该被 Girl 所继承过来。然后在重写的 about 方法中,就是用 self.height。
实例化类 Girl,并执行 cang.about("wangguniang"),试图打印出一句话 wangguniang is a hot girl, she is about 160, and her bereast is 90。保存程序,运行报错!
信息显示 self.height 是不存在的。也就是说类 Girl 没有从 Person 中继承过来这个属性。
在 Girl中发现, about 方法重写了,__init__方法,也被重写了。它跟类 Person 中的__init__重名了,也同样是重写了那个初始化函数。这是因为在子类中重写了某个方法之后,父类中同样的方法被遮盖了。
使用super 函数:
class Person:
def __init__(self):
self.height = 160
def about(self, name):
print("{} is about {}".format(name, self.height))
class Girl(Person):
def __init__(self):
super().__init__()
self.breast = 90
def about(self, name):
print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)) cang = Girl()
cang.about("wangguniang")
打印结果:
wangguniang is a hot girl, she is about 160, and her breast is 90
在子类中,__init__方法重写了,为了调用父类同方法,使用 super(Girl, self).__init__()的方式。super 函数的参数,第一个是当前子类的类名字,第二个是 self,然后是点号,点号后面是所要调用的父类的方法。同样在子类重写的 about 方法中,也可以调用父类的 about 方法。
最后要提醒注意:super 函数仅仅适用于新式类。
@ 绑定方法与非绑定方法
要通过实例来调用类的方法(函数),经常要将类实例化。方法是类内部定义函数,只不过这个函数的第一个参数是 self。(可以认为方法是类属性,但不是实例属性)。必须将类实例化之后,才能通过实例调用该类的方法。调用的时候在方法后面要跟括号(括号中默认有 self 参数,可以不写出来)。通过实例调用方法,称这个方法绑定在实例上。
class Person(object):
def foo(self):
pass
pp = Person() #实例化
print(pp.foo()) #调用方法
这样就实现了方法和实例的绑定,于是通过 pp.foo() 即可调用该方法。
调用非绑定方法:
class Person:
def __init__(self):
self.height = 160
def about(self, name):
print("{} is about {}".format(name, self.height))
class Girl(Person):
def __init__(self):
super().__init__()
self.breast = 90
def about(self, name):
print("{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)) cang = Girl()
cang.about("wangguniang")
打印结果:
wangguniang is a hot girl, she is about 160, and her breast is 90
在子类 Girl 中,因为重写了父类的__init__方法,如果要调用父类该方法,在上节中不得不使用 super().__init__()调用父类中因为子类方法重写而被遮蔽的同名方法。
其实,非绑定方法,因为在子类中,没有建立父类的实例,却要是用父类的方法。对于这种非绑定方法的调用,还有一种方式。不过这种方式现在已经较少是用了,因为有了 super 函数。为了方便读者看其它有关代码,还是要简要说明。
例如在上面代码中,在类 Girl 中想调用父类 Person 的初始化函数,则需要在子类中,写上这么一行:Person.__init__(self)
这不是通过实例调用的,而是通过类 Person 实现了对__init__(self)的调用。这就是调用非绑定方法的用途。但是,这种方法已经被 super 函数取代,所以,如果在编程中遇到类似情况,推荐使用 super 函数。
@ 静态方法和类方法
已知,类的方法第一个参数必须是 self,并且如果要调用类的方法,必须将通过类的实例,即方法绑定实例后才能由实例调用。如果不绑定,一般在继承关系的类之间,可以用 super 函数等方法调用。
这里再介绍一种方法,这种方法的调用方式跟上述的都不同,这就是:静态方法和类方法。
class StaticMethod:
@staticmethod
def foo():
print("This is static method foo().") class ClassMethod:
@classmethod
def bar(cls): #类方法中要有cls参数
print("This is class method bar().")
print("bar() is part of class:", cls.__name__) static_foo = StaticMethod() #实例化
static_foo.foo() #实例调用静态方法
StaticMethod.foo() #通过类来调用静态方法
print("********")
class_bar = ClassMethod()
class_bar.bar()
ClassMethod.bar()
打印结果:
This is static method foo().
This is static method foo().
********
This is class method bar().
bar() is part of class: ClassMethod
This is class method bar().
bar() is part of class: ClassMethod
在 Python 中:
@staticmethod表示静态方法
@classmethod表示类方法
先看静态方法,虽然名为静态方法,但也是方法,所以,依然用 def 语句来定义。需要注意的是文件名后面的括号内,没有self,这和前面定义的类中的方法是不同的,也正是因着这个不同,才给它另外取了一个名字叫做静态方法。如果没有 self,那么也就无法访问实例变量、类和实例的属性了,因为它们都是借助 self 来传递数据的。
在看类方法,同样也具有一般方法的特点,区别也在参数上。类方法的参数也没有 self,但是必须有 cls 这个参数。在类方法中,能够访问类属性,但是不能访问实例属性。
简要明确两种方法。下面看调用方法。两种方法都可以通过实例调用,即绑定实例。也可以通过类来调用,即 StaticMethod.foo() 这样的形式,这也是区别一般方法的地方,一般方法必须用通过绑定实例调用。
Pyhton-类(2)的更多相关文章
- pyhton类集成
class SchoolMember: def __init__(self,name,age): self.name = name self.age = age print ...
- Java类的继承与多态特性-入门笔记
相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...
- Python爬虫从入门到放弃(十六)之 Scrapy框架中Item Pipeline用法
当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的python类,负责接收到item并通过它执行一些行为, ...
- 6-----Scrapy框架中Item Pipeline用法
当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的python类,负责接收到item并通过它执行一些行为, ...
- scrapy框架中Item Pipeline用法
scrapy框架中item pipeline用法 当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的pyt ...
- 爬虫(十三):scrapy中pipeline的用法
当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的python类,负责接收到item并通过它执行一些行为, ...
- Python之爬虫(十八) Scrapy框架中Item Pipeline用法
当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的python类,负责接收到item并通过它执行一些行为, ...
- Python逆向爬虫之scrapy框架,非常详细
爬虫系列目录 目录 Python逆向爬虫之scrapy框架,非常详细 一.爬虫入门 1.1 定义需求 1.2 需求分析 1.2.1 下载某个页面上所有的图片 1.2.2 分页 1.2.3 进行下载图片 ...
- 《Pyhton语言程序设计》_第7章_对象和类
#7.2.1_定义类 一个类的功能:数据域.定义方法.初始化程序 初始化程序总是被命名为:_ _init_ _ (两个连续的下划线) #7.2.4_self参数 #self参数是指向对象本身的参数,那 ...
- day27 Pyhton 面向对象02 类和对象的命名空间
一.内容回顾 类:具有相同属性和方法的一类事务 # 描述一类事务轮廓的一个机制 #商品/用户/店铺 对象/实例: 对象(实例)就是类的实例化 # 对象就是类的一个具体的表现 #某一件特定的商品/某个人 ...
随机推荐
- Recursive functions and algorithms
http://en.wikipedia.org/wiki/Recursion_(computer_science)#Recursive_functions_and_algorithms A commo ...
- Linux动态链接库.so文件的创建与使用
1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个"程序函数库"简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可 ...
- vSan中见证组件witness详解
witness在vSan中作为见证组件其作用类似于WinServer中的仲裁磁盘,当Cluster中某一节点发生故障时,来判断该节点上的对象在哪一个新的节点上继续承载.此处需要强调的是,witness ...
- 第六次作业——Excel制作工资表
- ZT 设计模式六大原则(2):里氏替换原则
设计模式六大原则(2):里氏替换原则 分类: 设计模式 2012-02-22 08:46 23330人阅读 评论(41) 收藏 举报 设计模式class扩展string编程2010 肯定有不少人跟我刚 ...
- Scala模式匹配和样例类
Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句.类型检查等.并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配. 1.字符匹配 def mai ...
- 021.4 IO流——字节、字符桥梁(编码解码)
默认使用的就是gbk编码,这里的例子改成了utf8编码 写入—编码 private static void writeText() throws IOException { FileOutputStr ...
- [零基础学JAVA]Java SE面向对象部分.面向对象基础(05)
1.继承 2.多态 3.final 4.重载与覆写 5. this/super 6.抽象类 7.接口 java: class Person{ private String name; priva ...
- Spring Cloud(中文版)
原文链接:Spring Cloud I.云原生应用 Spring Cloud上下文:应用上下文服务 2.1.Bootstrap应用程序上下文 2.2.应用程序上下文层次结构 2.3.更改Bootstr ...
- 28、springboot整合RabbitMQ(2)
1.监听 1.1.监听队列 如订单系统和库存系统 订单系统下订单之后将消息存放在消息队列中 库存系统需要时刻进行监听消息队列的内容,有新的订单就需要进行库存相关的操作 此时模拟监听消息队列中的Bo ...