类和实例
1、通过class关键字创建一个类
class Student(object):
pass
(object)表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用object类,这是所有类都会继承的类。
2、创建实例是通过类名+()实现的。如果类有必须绑定的属性,则在类内需要定义一个特殊的__init__方法(这个方法名不能改成其他的,前后各两条横线)。
比如学生类必须有姓名和分数属性:
class Student(object):
def __init__(self, name, score):
#self指向正在被创建的对象本身
self.name = name
self.score = score
有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去
>>> Bart = Student('Bart Simpson', 59)
要在类里面定义一个方法,除了第一个参数是self外,其他和普通函数一样。
要调用类里面一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入。
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
>>> Bart.print_score()
Bart Simpson: 59
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量。
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
此时已经无法从外部访问实例变量.__name和实例变量.__score了。
如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法。
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:
class Student(object):
...
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
3、如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.score = 99 # 绑定属性'score'
(出错了,没有score属性)
使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
继承和多态
1、一个名为Animal的class,有一个run()方法
class Animal(object):
def run(self):
print('Animal is running...')
编写Dog和Cat类时,就可以直接从Animal类继承:
class Dog(Animal):
pass
class Cat(Animal):
pass
可以对子类增加一些方法,比如Dog类:
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。
2、在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行。
3、多继承
class Parrot(Bird):
pass
class Ostrich(Bird):
pass
要给动物再加上Runnable和Flyable的功能,只需要先定义好Runnable和Flyable的类:
class Runnable(object):
def run(self):
print('Running...')
class Flyable(object):
def fly(self):
print('Flying...')
对于需要Runnable功能的动物,就多继承一个Runnable,例如Dog:
class Dog(Mammal, Runnable):
pass
对于需要Flyable功能的动物,就多继承一个Flyable,例如Bat:
class Bat(Mammal, Flyable):
pass
鸭子类型
1、对于静态语言来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则将无法调用run()方法。
2、对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了。
3、这就是动态语的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
class Quote():
def __init__(self, person, words):
self.person = person
self.words = words
def who(self):
return self.person
def says(self):
return self.words + '.'
class QuestionQuote(Quote):
def says(self):
return self.words + '?'
class ExclamationQuote(Quote):
def says(self):
return self.words + '!'
hunter = Quote('Elmer Fudd', "I'm hunting wabbits")
hunted1 = QuestionQuote('Bugs Bunny', "What's up, doc")
hunted2 = ExclamationQuote('Daffy Duck', "It's rabbit season")
print(hunter.who(), 'says:', hunter.says())
print(hunter1.who(), 'says:', hunter1.says())
print(hunter2.who(), 'says:', hunter2.says())
结果:
Elmer Fudd says: I'm hunting wabbits.
Bugs Bunny says: What's up, doc?
Daffy Duck says: It's rabbit season!
三个不同版本的says()为上面三种类提供了不同的响应方式,这是面向对象的语言中多态的传统形式。
Python中,无论对象的种类是什么,只要包含 who() 和says(),你便可以调用它。我们再来定义一个 BabblingBrook 类,它与我们之前的猎人猎物(Quote 类的后代)什么的没有任何关系:
class BabblingBrook():
def who(self):
return 'Brook'
def says(self):
return 'Babble'
def who_says(obj):
print(obj.who(), 'says', obj.says())
brook = BabblingBrook()
print(who_says(hunter))
print(who_says(hunter1))
print(who_says(hunter2))
print(who_says(brook ))
结果:
Elmer Fudd says I'm hunting wabbits.
Bugs Bunny says What's up, doc?
Daffy Duck says It's rabbit season!
Brook says Babble