Python 面向对象高级编程 01 使用__slots__、使用@property、多重继承、定制类

1 使用__slots__

# 定义类
class Students(object):
    pass

# 给实例绑定属性和方法
s = Students()
s.name = "lisi"
print(s.name) # lisi

def set_age(self, age):
    self.age = age

from types import MethodType

s.set_age = MethodType(set_age, s)
s.set_age(25)
print(s.age) # 25

'''
注意:给一个实例绑定的方法,对另一个实例是不起作用的
     为了给所有实例都绑定方法,可以给class绑定方法
'''

def set_sex(self, sex):
    self.sex = sex

# 给class绑定方法
Students.set_sex = set_sex

s.set_sex('man')
print(s.sex)

# 定义另一个对象
s1 = Students()
s1.set_sex('woman')
print(s1.sex)


# 使用__slot__来限制给添加实例的属性
class Person(object):
    __slots__ = ('name', 'age')

p = Person()
p.name = 'zhangsan'
p.age = 18
p.sex = 'man'  # 出错

'''
注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
     除非在子类中也定义__slots__,这样子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
''' 

2 使用@property

# 使用@property

''' @property 装饰器负责把一个方法变成属性调用 '''

# 创建类
''' 把一个getter方法变成属性,只需要加上@property就可以,
    此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
'''
class Student(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        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
print(s.score)

3 多重继承

一个类可以继承多个父类,这样,一个子类就可以同时获得多个父类的所有功能。

MixIn:

在设计类的继承关系时,通常,主线都是单一继承下来的,如果要混入额外的功能,通过多重继承就可以实现。这种设计通常称之为MixIn。

4 定制类

4.1 __str__
# __str__

# 定义class
class Student(object):
    def __init__(self, name):
        self.name = name

# 打印对象
print(Student('lisi')) # <__main__.Student object at 0x104037630>

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

    def __str__(self):
        return 'student object (name: %s)' % self.name


print(Student('lisi')) # student object (name: lisi)
4.2 __iter__

如果一个类想被用于for循环,就必须实现一个__iter__()方法,该方法返回一个迭代对象。__next__()方法拿到循环的下一个值。

# __iter__

# 定义一个求斐波那契数列的类
class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self # 实例本身就是迭代对象,所以返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100:
            raise StopIteration()
        return self.a


for n in Fib():
    print(n)

# for循环结果
1 1 2 3 5 8 13 21 34 55 89
4.3 __getitem__

使用此方法可以像list那样按照下标取出元素。

# __getitem__
class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a

# 调用函数,获取结果
f=Fib()
print(f[1],f[2],f[3],f[4]) # 1 2 3 5

# 向函数传入切片
class Fib(object):
    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

# 调用函数,获取结果
f=Fib()
print(f[0:5]) # [1, 1, 2, 3, 5]
4.4 __getattr__

正常情况下,调用类的方法或属性时,如果不存在,就会报错,要避免这个错误,可以使用__getattr__()方法,动态返回一个属性。

# __getattr__

# 返回属性
class Student(object):

    def __init__(self):
        self.name = 'lisi'

    def __getattr__(self, attr):
        if attr=='score':
            return 99

stu2=Student()
print(stu2.name) # lisi
print(stu2.score) # 99

# 返回函数
class Student(object):

    def __getattr__(self, attr):
        if attr=='age':
            return lambda: 25

stu3=Student()
print(stu3.age()) # 25
4.5 __call__

直接调用实例本身

# __call__

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

    def __call__(self):
        print('My name is %s.' % self.name)

stu4=Student('lisi')
stu4() # My name is lisi.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值