Python学习8——面向对象
写在开头:
这部分学习总结本来应该是抽象的延续,但是我却不想用“抽象2”来给标题命名,我觉得这节的内容更适合称为“面向对象”。
创建自定义对象是Python的核心概念,Python可以同java语言一样,被视为是一种面向对象语言。在面向对象编程中,术语对象大致意味着一系列访问和操作这些数据的方法。
有一点java基础的同学应该都了解,面向对象的3个基本特征:封装,继承,多态。
多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常的运行。
你收到一个对象,却不知道它是如何实现的,它可能有很多种形态,但你可以访问它。
>>> 'abc'.count('a') 1 >>> [1,2,'a'].count('a') 1
上面的栗子,你不在乎这个变量是列表还是字符串,你都能调用count,只要你提供一个字符作为参数,它都能正常运行。
>>> def length_message(x): print('The length of',repr(x),'is',len(x)) >>> length_message('Fnord') The length of 'Fnord' is 5
repr()返回的是一个对象的string格式,可用于任何对象。
关于类 :
类是一种对象。
每个对象都属于特定的类,并被称为该类的实例。
例:头顶飞过一只鸟,这只鸟就是“鸟类”的一个实例。鸟类是一个抽象的类,它包含很多子类,飞过的那只鸟可能就属于子类“云雀”。此时你可把鸟类当作鸟的集合,而“云雀”就是其中的一个子集,也可以叫做“鸟类”的子类,而“鸟类”为“云雀”的超类。
创建自定义类:
>>> class Person: #Person是类的名称,首字母需大写;class语句创建独立的命名空间,用于在其中定义函数。 def set_name(self,name): self.name = name def get_name(self): return self.name def greet(self): print('Hello,world! I\'m {}'.format(self.name)) >>> foo = Person() >>> bar = Person() >>> foo.set_name('Luke Skywalker') >>> bar.set_name('Anakin Skywalker') >>> foo.greet() Hello,world! I'm Luke Skywalker >>> bar.greet() Hello,world! I'm Anakin Skywalker
对foo调用set_name和greet时,foo都会作为第一个参数自动传递给它们。所以参数self,指向对象本身。
封装:向外部隐藏不必要的细节。让你无需知道对象的构造就能使用它。
默认情况下,可从外部访问对象的属性。
>>> class Secretive: def __inaccessible(self): #名称以两个下划线打头,可以让方法成为私有的(外部不能访问) print('Bet you can\'t see me ...') def accessible(self): print('The secret message is:') self.__inaccessible() >>> s = Secretive() >>> s.__inaccessible() #外部无法访问__inaccessible Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> s.__inaccessible() AttributeError: 'Secretive' object has no attribute '__inaccessible' >>> s.accessible() #却可以直接访问到accessible中的__inaccessible The secret message is: Bet you can't see me ...
>>> s._Secretive__inaccessible() Bet you can't see me ...
在类定义中,对所有以两个下划线打头的名称都进行转换,即在开头加上一个下划线和类名。这种处理方法能从类外访问私有方法。
继承:可基于通用类创建出专用类。一个类可以是一个或多个类的子类,在这种情况下,子类将继承超类的所有方法。
>>> class Filter: #定义一个超类 def init(self): self.blocked = [] def filter(self,sequence): return [x for x in sequence if x not in self.blocked] >>> class SPAMFilter(Filter): #SPAMFilter是Filter的子类 def init(self): #重写超类Filter的方法init self.blocked = ['SPAM'] >>> s = SPAMFilter() >>> s.init() >>> s.filter(['SPAM','eggs','abc','SPAM','ccc','SPAM','SPAM']) ['eggs', 'abc', 'ccc']
SPAMFilter类从Filter类继承了方法filter的定义,因此不用再重写编写filter方法细节,便能直接使用。
判断一个类是否是另一个类的子类,可使用内置方法issubclass(object,class).
>>> issubclass(SPMFilter,Filter) True >>> SPMFilter.__bases__ #访问属性__bases__,可以知道1个类的基类 (<class '__main__.Filter'>,) >>> s = SPMFilter() >>> isinstance(s,Filter) #确定对象是否是特定类的实例,可使用isinstance True >>> isinstance(s,SPMFilter) True
>>> s.__class__ #使用属性__class__可以获取对象属于哪个类 <class '__main__.SPMFilter'>
多重继承
>>> class Calculator: def calculate(self,expression): self.value = eval(expression) >>> class Talker: def talk(self): print('Hi,my value is',self.value) >>> class TalkingCalculator(Calculator,Talker): pass >>> tc = TalkingCalculator() >>> tc.calculate('1+2*3') >>> tc.talk() Hi,my value is 7
hasattr(object, name)
判断一个对象里面是否有属性或者方法,返回BOOL值,有talk方法返回True, 否则返回False。
>>> hasattr(tc,'talk') True >>> hasattr(tc,'fnord') False
getattr(object, name[,default])
获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,下面的默认值是None。
>>> getattr(tc,'talk',None) #需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址 <bound method Talker.talk of <__main__.TalkingCalculator object at 0x0000000002B1D1D0>> >>> getattr(tc,'fnord',None) >>> getattr(tc,'fnord','None') 'None'
setattr(object, name, values)
给对象的属性赋值,若属性不存在,先创建再赋值。
>>> setattr(tc,'name','Mr.Gumby') >>> tc.name 'Mr.Gumby'
callable() 函数用于检查一个对象是否是可调用的。
>>> callable(getattr(tc,'talk',None)) True >>> callable(getattr(tc,'fnord',None)) False
__dict__属性可查看对象中存储的所有值
>>> tc.__dict__ {'value': 7, 'name': 'Mr.Gumby'}
抽象基类
抽象类是不能实例化的类,其职责是定义子类应实现的一组抽象方法。
>>> from abc import ABC,abstractmethod >>> class Talker(ABC): @abstractmethod #@abstractmethod将方法标记为抽象的 def talk(self): pass
>>> Talker() #抽象类不能实例化
Traceback (most recent call last):
File "<pyshell#104>", line 1, in <module>
Talker()
TypeError: Can't instantiate abstract class Talker with abstract methods talk
>>> class King(Talker): def talk(self): #重写方法talk print('Hi!') >>> k = King() >>> isinstance(k,Talker) #isinstance 检查对象是否是特定类的实例 True >>> k.talk() Hi!
确定需要哪些类以及这些类应包含哪些方法:
1.将有关问题的描述记录下来,给所有的名词,动词和形容词加上标记;
2.在名词中找出可能的类;
3.在动词中找出可能的方法;
4.在形容词中找出可能的属性;
5.将找出的方法和属性分配给各个类。