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.与类相关的方法

  1. isinstance(h, Husky) # 判断对象h是否为类Husky。即用来判断类型是否正确
  2. 类中定义的类似“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.元类