python面向对象高级编程(使用__slots__、使用@property、多重继承、定制类、使用枚举类、使用元类)

学习目标:

python学习十一、


学习内容:

1、使用__slots__
2、使用@property
3、多重继承
4、定制类
5、使用枚举类
6、使用元类


1、使用__slots__

1、一个类的实例可以绑定任意的属性和方法

  • 创建一个类,以及它的实例为实例绑定属性和方法
class Student(object):
    pass

def set_age(self,age):
        self.age = age
s = Student()
s.name = 'Bob'     #绑定属性
print(s.name)
from types import MethodType  #绑定方法
s.set_age = MethodType(set_age, s)  #绑定方法
s.set_age(25)
print(s.age)
  • 给一个实例绑定的方法,对另一个实例是不起作用的,除非直接在类里面设定函数
s2 = Student()
s2.set_age(25)
输出报错:
    s2.set_age(25)
AttributeError: 'Student' object has no attribute 'set_age'

同时调用类里面的方法

class Student(object):
    def set_age(self,age):
        self.age = age
s = Student()
s2 = Student()
s.set_age(25)
s2.set_age(25)
print(s.age)
print(s2.age)
输出:
25
25

2、使用__slots__
使用__slots__可以限制实例绑定指定的属性,slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用,除非在子类中也定义__slots,属性就是自身的__slots__加上父类的__slots__

class Student(object):
    __slots__ = ('name', 'age')
s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
s.score = 99
...
AttributeError: 'Student' object has no attribute 'score'

2、使用@property

Python内置的@property装饰器就是负责把一个方法变成属性调用

getter方法和setter方法构成读写属性,getter方法,不定义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 = 77
print(s.score)
输出:
77

3、多重继承

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

class Animal(object):
    pass
class Runnable(object):
    def run(self):
        print('Running...')
class Dog(Mammal,Runnable):
    pass

同时继承多个类的方式被称为MixIn,MixIn的目的就是给一个类增加多个功能


4、定制类

len()方法我们也知道是让class作用于len()函数

1、str()方法,返回一个好看的字符串

class Student(object):
    def __init__(self, name):
       self.name = name
    def __str__(self):
       return 'Student object (name: %s)' % self.name

print(Student('Bob'))
输出:
Student object (name: Bob)

2、str__与__repr(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,_repr_()是为调试服务的

解决办法是再定义一个__repr__()

class Student(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return 'Student object (name=%s)' % self.name
    __repr__ = __str__

3、iter
iter__方法用于for … in循环,类似list或tuple,该方法回一个迭代对象,Python的for循环就会不断调用该迭代对象的__next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环

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 > 100000:
            raise StopIteration()
        return self.a
for n in Fib():
    print(n)

4、getitem
像list那样按照下标取出元素,需要实现__getitem__()方法

Fib实例虽然能作用于for循环,list有点像,但是,它并不能像list一样直接去出某个下标的值

  • 取出脚标2的值
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[2])
  • 利用__getitem__实现切片取值
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[5:12])

5、getattr
Python中,可以写一个__getattr__()方法,动态返回一个原本没有的属性

当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self,
‘score’)来尝试获得属性并获得相应的值

class Student(object):

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

    def __getattr__(self, attr):
        if attr=='score':
            return 99
s = Student()
print(s.name)
print(s.score)
输出:
Michael
99
  • 利用__getattr__可以写一个API和SDK的链式调用
class Chain(object):

    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__
print(Chain().status.user.timeline.list)
/status/user/timeline/list

6、call
任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用

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

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

s = Student('Bob')
s()

7、Callable()函数
Callable可以检查一个变量是否可以被调用

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

    def __call__(self):
        print('My name is %s.' % self.name)
print(callable(Student('Bob')))
print(callable(max))
print(callable([1, 2, 3]))
print(callable(None))
print(callable('str'))
输出:
True
True
False
False
False

5、使用枚举类

定义常量时,一个办法是用大写变量通过整数来定义,虽然简单易操作,但是类型是int,并且仍然是变量
Enum枚举类型来定义一个class类型,每个常量都是class的一个唯一实例

  • 编写一个月份的类
  • value属性则是自动赋给成员的int常量,默认从1开始计数
  • @unique装饰器可以帮助我们检查保证没有重复值
  • 月份的枚举
from enum import Enum,unique
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)
  • 星期的枚举
 @unique
class Weekday(Enum):
    Sun = 0 # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

day1 = Weekday.Mon
print(day1)

## 6、使用元类 1、type type()函数可以查看一个类型或变量的类型,并且可以创建出新的类型

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class

def fn(self, name='world'): # 先定义函数
    print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class,把函数fn绑定到方法名hello

h = Hello()
h.hello()
输出:
Hello, world.

2、metaclass
除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass(元类)

  • 先定义metaclass,就可以创建类,最后创建实例,可以把类看成是metaclass创建出来的“实例”
    (https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值