about class

slots

  • __slots__ 用于限制实例对象可以添加的属性
  • 当子类没有定义__slots__时, 父类的__slots__对子类无约束, 当子类也定义了__slots__时, 子类的__slots__会继承父类的__slots__
In [1]:
class Student():
    __slots__ = ('name', 'age')
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return 'Student(name={0}, age={1})'.format(self.name, self.age);

s = Student('jack', 20)
print(s)
try:
    s.sex = 'boy' ## 由于__slots__的约束, Student对象不能有除name, age之外的属性, 
except Exception as e:
    print(e)
Student(name=jack, age=20)
'Student' object has no attribute 'sex'
In [2]:
# Student2继承自 Student 没有定义__slots__, 因此可以动态绑定任意属性
class Student2(Student): 
    def __init__(self,name, age):
        self.name = name
        self.age = age

s2 = Student2('bob', 22)
print(s2)
s2.sex = 'boy'
print('s2.name = ', s2.name)
print('s2.age = ', s2.age)
print('s2.sex = ', s2.sex)
Student(name=bob, age=22)
s2.name =  bob
s2.age =  22
s2.sex =  boy
In [3]:
# Student3继承自Student, 且定义了__slots__, 因此将继承父类的__slots__
class Student3(Student):
    __slots__ = ()
    def __init__(self, name, age):
        self.name = name
        self.age = age
s3 = Student3('jack', 23)
print(s3)
try:
    s3.sex = 'boy'  # Student3继承了Student的__slots__, 因此也只能定义 name 和 age属性
    print('s2.name = ', s2.name)
    print('s2.age = ', s2.age)
    print('s2.sex = ', s2.sex)
except Exception as e:
    print(e)
Student(name=jack, age=23)
'Student3' object has no attribute 'sex'

给类和对象绑定方法

  • 给对象绑定一个方法时, 其他对象不会自动拥有该方法
  • 给类绑定一个方法时, 该类的所有对象将自动拥有该方法
In [5]:
# 给上述 s2 对象绑定 set_sex() 方法
from types import MethodType

def set_sex(self, sex):
    self.sex = sex
    
print('s2.sex = ', s2.sex)
s2.set_sex = MethodType(set_sex, s2)
s2.set_sex('girl')
print('s2.sex = ', s2.sex)

st1 = Student2('zhangsan', 18)
try:
    st1.set_sex('boy')  # set_sex() 只绑定到了s2对象上, 其他对象没有这个方法
except Exception as e:
    print(e)
s2.sex =  girl
s2.sex =  girl
'Student2' object has no attribute 'set_sex'
In [9]:
# 给 Student2 类绑定 set_sex()方法
Student2.set_sex = set_sex  # 注意不要加括号 (), 否则是在调用函数

st2 = Student2('lisi', 20)
try:
    print('st2.sex = ', st2.sex)
except Exception as e:
    print(e)
st2.set_sex('boy')
print('st2.sex = ', st2.sex)
'Student2' object has no attribute 'sex'
st2.sex =  boy

@property

@property 装饰器可以使得方法可以像属性一样使用, 这点跟C#中的属性如出一辙

In [11]:
class Student4():
    def __init__(self, name, birth):
        self.name = name
        self.birth = birth
        self.__score = 0
    
    # score 装饰成为可读可写属性
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be integer')
        if not 0 <= value <= 100 :
            raise ValueError('score must between 0 and 100')
        self.__score = value
    
    # 定义 age 属性, 该属性为只读属性
    @property
    def age(self):
        return 2018 - self.birth
In [14]:
jack = Student4('jack', 2000)
print('jack.birth = ', jack.birth)
print('jack.age = ', jack.age)
jack.birth = 2002
print('jack.age = ', jack.age)      # 通过属性读取 age
print('jack.score = ', jack.score)  # 通过属性读取 score
jack.score = 50                     # 通过属性修改 score
print('jack.score = ', jack.score)
try:
    jack.score = 150
except Exception as e:
    print(e)
print('jack.score = ', jack.score)
jack.birth =  2000
jack.age =  18
jack.age =  16
jack.score =  0
jack.score =  50
score must between 0 and 100
jack.score =  50

多重继承

python支持多重继承, 但多重继承容易使继承体系很快变得十分复杂, 采用MixIn的设计原则, 可以避免这个问题. 主要思路就是每个类只继承自一条主干, 而通过继承自其它的MixIn类来增加功能和实现代码复用. MixIn类类似与java中的interface,java中使用interface来设计接口, python中使用MixIn这种类来设计接口.

In [20]:
class RunnableMixIn():
    def run(self):
        print(self.name, 'is running...')
        
class FlyableMixIn():
    def fly(self):
        print(self.name, 'is flying...')


class Animal():
    def __init__(self, name):
        self.name = name

class Bird(Animal):
    pass
class Mammal(Animal):
    pass

class Dog(Mammal, RunnableMixIn):
    pass

class Bat(Mammal, FlyableMixIn):
    pass

dog = Dog('hasky')   # Dog类继承了 RunnableMixIn, 所以有run()方法
dog.run()
bat = Bat('bat man') # Bat类继承了 FlyableMixIn, 所以有fly()方法
bat.fly()
hasky is running...
bat man is flying...