学习目标:
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)