bugstar

导航

Python类的进阶.md

属性绑定

  • 在python中可以给类对象动态的绑定属性
  • 但是由于这种特性,随意动态绑定也会带来麻烦,因此可用__slots__来限制可绑定的属性名称
  • __slots__的绑定对于子类是不生效的,只对当前类实例生效
#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'


class Man(object):
    def __init__(self, name):
        self.name = name

class Woman(object):
    #限制绑定的属性名称为name和age,除此之外均不可
    __slots__ = ('name', 'age')

class PrintInfo(object):
    def testMain():
        m = Man('zhangsan')
        #给m绑定name和age
        m.age = 20
        m.hight = 180
        print(m.age, m.hight)

        #给w绑定变量,但是hight在绑定列表之外,所以会报错
        w = Woman()
        w.name = 'lisi'
        w.age = 20
        w.hight = 180
        print(w.name, w.age, w.hight)


if __name__ == '__main__':
    PrintInfo.testMain()

属性@property

  • 使用@property来定义类的属性,可以对属性进行限制和检查:
#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'


class Man(object):
    #给age赋一个不可变的值
    _age = 20
    _name = ''

    #定义age的@property属性
    @property
    def age(self):
        #注意这里的写法
        return self._age

    #定义name的属性
    @property
    def name(self):
        return self._name

    #定义name的setter方法
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise ValueError('name must be a str')
        self._name = value

class PrintInfo(object):
    def testMain():
        m = Man()
        print(m.age)
        #这一句会报错,因为没有对age定义age的setter方法
        #m.age = 30

        print(m.name)
        m.name = 'wangwu'
        print(m.name)



if __name__ == '__main__':
    PrintInfo.testMain()

多继承和Mixin模式

python支持多继承,只需要将继承的类放到定定义中
但是在设计中一个类职责尽量单一,即使有需要增加其他功能,不要通过多重继承来实现。这样的话会增加代码的复杂度。在这里使用Mixin模式通过组合的形式来实现功能

#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'

#定义主类
class Aniaml(object):
    def isAnimal(self):
        print( 'i am an animal')


#定义不同的功能类,注意,这些功能类职责要单一
#这些类名统一的规则用Mixin作为后缀是为了方便维护和理解,一看就能知道使用了Mixin模式
class FlyMixin(object):
    def isFly(self):
        print( 'i can fly')

class RunMixin(object):
    def isRun(self):
        print( 'i can run')

class PrintInfo(object):
    def testMain():
        pass

#定义实现类,使用了Mixin模式,具备了各种功能
class Bird(Aniaml, RunMixin, FlyMixin):
    pass

#只继承了基类,所以不支持各种功能
class Man(Aniaml):
    pass

class PrintInfo(object):
    def testMain(self):
        print('Bird:')
        b = Bird()
        b.isAnimal()
        b.isFly()
        b.isRun()

        print('man:')
        m = Man()
        m.isRun()

if __name__ == '__main__':
    p = PrintInfo()
    p.testMain()


类的输出:str__和__repr

在日志或者调试中需要打印类的信息,可以重写__str__方法来实现:


#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'

#定义主类
class Aniaml(object):
    def isAnimal(self):
        print( 'i am an animal')

    #重写Animal类的打印信息,此方法用于输出,对用户
    def __str__(self):
        return "This is class Animal."

    #重写了__repr__方法,此方法用于调试输出
    def __repr__(self):
        return 'This is class Animal.'


class PrintInfo(object):
    def testMain(self):
        a = Aniaml()
        #调用了__str__方法
        print(a)

if __name__ == '__main__':
    p = PrintInfo()
    p.testMain()

类的迭代器__iter__

iter

Python中类可以在for循环中迭代,类中实现了__iter__()方法即可以在循环中返回迭代对象。和__iter__()方法匹配的还有__next__()方法,二者需要同时完成。

#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'

class AutoLoop(object):
    def __init__(self, maxNum):
        #这里定义了变量,所以后面变量都需要用self.var的形式
        self.maxNum = maxNum
        self._startNum = 0

    #定义这个类的迭代器,必须返回自己
    def __iter__(self):
        return self;

    #next方法也是必须实现的
    def __next__(self):
        #循环的执行体
        self._startNum += 1
        #循环退出的条件,必须有
        if self.maxNum < self._startNum:
            #退出循环,固定
            raise StopIteration()
        #每次循环的返回值
        return self._startNum


if __name__ == '__main__':
    #a = AutoLoop(6
    for n in AutoLoop(6):
        print(n)

类的迭代器-获取指定元素:getitem()

重写_getitem__()方法可以让刚才的例子像list一样通过下标获取指定位置元素的值:

#对于模块Animal.py的说明
'a demo of class type'
#作者
__author__  = 'liyue'

class AutoLoop(object):
    def __init__(self, maxNum):
        #这里定义了变量,所以后面变量都需要用self.var的形式
        self.maxNum = maxNum
        self._startNum = 0

    #定义这个类的迭代器,必须返回自己
    def __iter__(self):
        return self;

    #next方法也是必须实现的
    def __next__(self):
        #循环的执行体
        self._startNum += 1
        #循环退出的条件,必须有
        if self.maxNum < self._startNum:
            #退出循环,固定
            raise StopIteration()
        #每次循环的返回值
        return self._startNum

    #取第n个元素
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a

if __name__ == '__main__':
    #a = AutoLoop(6
    for n in AutoLoop(6):
        print(n)

    a = AutoLoop(8)
    print('取类中的第二个元素的值:%d' % a[2])

这里还可以实现list的切片方法:

#...
def __getitem__(self, n):
        if isinstance(n, int): # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice): # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L
#...

同理__getitem__()的参数检查还要继续完善,才是一个健壮的函数。对于类来说还有__setitem__()和__delitem__()方法可以实现。

枚举类

从Enum派生出我们自己的自定义类,并用@unqire关键字限制重复的枚举对象;

#导入枚举包
from enum import Enum, unique
'a enum class'

__author__ = 'liyue'

#unique关键字检查重复
@unique
class Wether(Enum):
    Sunny = 0
    Rain = 1
    Snow = 2


if __name__ == '__main__':
    w1 = Wether.Sunny
    print(w1)
    print(w1.value)

posted on 2017-12-13 16:31  bugstar  阅读(573)  评论(0)    收藏  举报