1 类
在python中类其实就是一种数据类型,和int,list等没有区别,如每一个list对象都有方法append()。
2.私有变量
属性的名称前加上两个下划线__,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。而外部要通过函数对私有变量进行访问,而此函数一般会对私有变量进行一定的保护,如:
class Student(object):
...
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
本代码中修改私有变量__score时有一个判断“0 <= score <= 100”,这保证了私有变量的安全。
有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”
3.多态
要理解多态,首先我们先看一段代码:
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
class Timer(object):
def run(self):
print('Start...')
def run_twice(animal):
animal.run()
animal.run()
run_twice(Animal()) ###1
run_twice(Cat()) ###2
run_twice(Timer()) ###3
多态:从###1和###2可以看出来,多态就是依赖Animal的对象作为参数的函数,可以输入Animal的子类的对象作为参数进行运行,而不需要修改函数中的代码。而Animal的子类中的方法run的实现细节可以千变万化,子类的实现可以千变万化这就是多态的功能。
多态的原因:子类的对象之所以可以作为参数输入到run_twice()中,是因为Animal中有的东西,子类Cat也有(子类继承父类的所有东西,并且部分可以进行重写)。而在python中函数run_twice的形参animal是不用说明数据类型的,所以任何有run方法的类的对象,都可以输入到run_twice中,如###3。Java中函数run_twice的形参animal是需要说明数据类型的,所以只能输入形参对应的类的对象或子类的对象。
Animal中的方法可以具体没有实现,只是return或print了适当的内容,具体的实现都留给了它的子类。
4.类与函数相比的优点
类的特点时封装、继承和多态。
封装:将一个事物的属性和方法定义在一个类里
继承:可以重写类中的方法,对方法的实现细节进行自定义或增加方法,如对数据库的读操作,就可以通过修改方法的实现细节从读取不同的数据库。
多态:以父类作为形参的函数,子类也可以作为这个函数的形参,虽然子类中方法的实现细节与父类可能有所不同。
5.与类相关的方法
- isinstance(h, Husky) # 判断对象h是否为类Husky。即用来判断类型是否正确
- 类中定义的类似“xxx”这样的函数,都是有特殊用途的,如
>>> class MyDog(object):
... def __len__(self):
... return 100
...
>>> dog = MyDog()
>>> dog.__len__() # 和len(dog)是等价的
100
>>> len(dog) # 在len()函数内部,它自动去调用该对象的__len__()方法
100
3.hasattr(fp, ‘read’) # 判断fp对象中是否有方法或属性‘read’
6.类变量
class Student(object):
name = 'Student'
name就是类变量
class Student(object):
def __init__(self, name):
self.name = name
s = Student()
s.age = 18 # 为对象s创建了一个变量age,而不是为类创建了一个变量age
self.name就是对象的变量。
7.类的高级用法
1.__slots__:允许实例添加的属性
class Student(object):
__slots__ = ('name', 'age') # 只允许对Student实例添加name和age属性。
__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用.除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
2.@property:给属性值的设置添加限制
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value): # 给属性值的设置添加限制.没有@score.setter时self._score就是只读变量
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
# 但是获取和设置属性值的时候用的是如下:
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
这样我们就既对属性值的设置做了限制,同时也没有让属性值的获取和设置变得困难.
3.元类