第七章 更加抽象(对象)
1、几个概念
多态:对不同类的对象使用同样的操作。
封装:对外部世界隐藏对象的工作细节。
继承:以普通那的类为基础建立专门的类对象。
多态例子:
>>> 'abc'.count('a')
1
>>> [1,2,'a'].count('a')
1
repr(obj):得到obj的表示字符串,可以利用这个字符串用eval函数重建该对象的一个拷贝
eval(str):str是一个字符串,表示合法的python表达式,返回这个表达式
>>> def length_message(x):
print("The lenght of", repr(x), "is", len(x))
>>> length_message('Fnord')
The lenght of 'Fnord' is 5
>>> length_message([1,2,3])
The lenght of [1, 2, 3] is 3
2、新式类
在模块或者脚本开始的地方放置赋值语句 __metaclass__ = type
>>> __metaclass__ = type
>>> class Person:
def setName(self,name):
self.name = name
def getName(self):
return self.name
def greet(self):
print("Hello,world! I'm %s. " % self.name)
>>> foo = Person()
>>> bar = Person()
>>> foo.setName('jack wang')
>>> bar.setName('leng leng')
>>> foo.greet()
Hello,world! I'm jack wang.
>>> bar.greet()
Hello,world! I'm leng leng.
>>>
>>> foo.name
'jack wang'
>>> bar.name = 'Yoda' #特性可以在外部访问的
>>> bar.greet()
Hello,world! I'm Yoda.
3、特性、函数和方法
将属性绑定到一个函数上
>>> class Class:
def method(self):
print('I have a self!')
>>> def function():
print("I don't...")
>>> instance = Class()
>>> instance.method()
I have a self!
>>> instance.method()
I have a self!
>>> instance.method = function #将属性绑定到普通函数
>>> instance.method()
I don't...
self参数引用同一个方法的其他变量
>>> class Bird:
song = 'Squaawk!'
def sing(self):
print(self.song)
>>> bird = Bird()
>>> bird.sing()
Squaawk!
>>> birdsong = bird.sing
>>> birdsong()
Squaawk!
私有属性、方法——Python并没有真正的私有化支持,但可用下划线得到伪私有
尽量避免定义以下划线开头的变量
(1)_xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象(即类实例)和子类对象自己能访问到这些变量,需通过类提供的接口进行访问;不能用'from module import *'导入
(2)__xxx 类中的私有变量/方法名 (Python的函数也是对象,所以成员方法称为成员变量也行得通。)," 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
(3)__xxx__ 系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。
__开头的本来就是表示private,private是不可继承的
为了让方法或者特性变为私有(从外部无法访问),只要在它的名字前面加上双下划线即可:
def __inaccessible(self): #双下划线表示私有方法
print("Bet you can't see me...")
def accessible(self):
print("The secret message is: ")
self.__inaccessible()
>>> s = Secretive() #类实例化对象需要用()
>>> s.__inaccessible() #不能访问私有方法
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
s.__inaccessible()
AttributeError: 'Secretive' object has no attribute '__inaccessible'
>>> s.accessible()
The secret message is:
Bet you can't see me...
>>> s._Secretive__inaccessible() #虽然私有,仍能调用,伪私有机制
Bet you can't see me...
如不需要使用这种方法但又想让其他对象不需要访问内部数据,可以使用单下划线
4、类的命名空间---代码都在特殊的命名空间中执行,这个命名空间可由类内所有成员访问。
类定义其实就是执行代码块
>>> class C:
print('Class C being defined...') #在类的定义区并不只限使用def语句
Class C being defined...
以下代码中类作用域内定义了一个可供所有成员(实例)访问的变量,用来计算类的成员数量
>>> class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
>>> m1 = MemberCounter()
>>> m1.init()
>>> MemberCounter.members
1
>>> m2 = MemberCounter()
>>> m2.init()
>>> MemberCounter.members
2
# 类作用域内的变量也可以被所有实例访问
>>> m1.members
2
>>> m2.members
2
>>> m1.members = 'Two' #在实例中重绑定members特性
>>> m1.members
'Two'
>>> m2.members
2
5、指定超类---将其他类名写在class语句后的圆()内可以指定超类
>>> 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): #继承Filter
def init(self): #重写Filter父类中的init方法
self.blocked = ['SPAM']
>>> f = Filter()
>>> f.init()
>>> f.filter([1,2,3])
[1, 2, 3]
>>> s = SPAMFilter()
>>> s.init
<bound method SPAMFilter.init of <__main__.SPAMFilter object at 0x013D0590>>
>>> s.init()
>>> s.filter(['SPAM','SPAM','SPAM','SPAM','eggs','bacon','SPAM']) #可以将SPAM过滤出去
['eggs', 'bacon']
6、调用继承
内建issubclass函数:查看一个类是否是另一个的子类
>>> issubclass(SPAMFilter,Filter)
True
>>> issubclass(Filter,SPAMFilter)
False
想知道已知类的基类(们),使用它的特殊特性__bases__
>>> SPAMFilter.__bases__
(<class '__main__.Filter'>,)
>>> Filter.__bases__
(<class 'object'>,)
isinstance():检查一个对象是否是一个类的实例
>>> s = SPAMFilter()
>>> isinstance(s,SPAMFilter) #s是SPAMFilter类的直接成员
True
>>> isinstance(s,Filter) #s是Filter类的间接成员
True
>>> isinstance(s,str)
False
对象属于哪个类,使用__class__特性
>>> s.__class__
<class '__main__.SPAMFilter'>
7、多个超类 (多重继承)
>>> 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') #子类调用超类的 calculate()方法
>>> tc.talk() #子类调用超类的 talk()方法
hi,my value is 7
注意超类顺序,先继承的类中的方法会重写后继承的类中的方法
假设C继承A和B,而A和B中有同名方法,如method
class C(A, B):,A中的method重写B中的method
class C(B, A):,B中的method重写A中的method,所以如果想使用B中的method方法,则将B放在前面
8、接口和内省----——公开的方法和属性
检查所需方法(特性)是否存在
>>> hasattr(tc, 'talk') #对象tc有talk特性
True
>>> hasattr(tc, 'fnord') #对象tc没有fnord特性
False
检查方法是否可调用
>>> hasattr(getattr(tc,'talk',None),'__call__')
True
>>> hasattr(getattr(tc,'fnord',None),'__call__')
False
getattr()允许提供默认值,以便当方法不存在时使用。
与getattr相对应的是setattr,可以用来设置对象的特性;
>>> setattr(tc,'name','Jack') #设置对象的特性
>>> tc.name
'Jack'
查看对象内所有存储的值,可以使用__dict__特性
>>> tc.__dict__
{'name': 'Jack', 'value': 7}
总结:
对象:对象包括特性和方法,特性只是作为对象的一部分变量,方法则是存储在对象内的函数
(绑定)方法和其他函数的区别在于方法总是将对象作为自己的第一个参数,这个参数一般称为self
类:类代表对象的集合(或一类对象),每个对象(实例)都有一个类,类的主要任务是定义任务是定义它的实例会用到的方法。
多态:多态是实现将不同类型和类的对象进行同样对待的特性---不需要知道对象属于哪个类就能调用方法。
封装:对性可以将它们的内部状态隐藏起来。
继承:一个类可以是一个或多个类的子类。