3.3. 面向对象高级编程
3.3.1. 给类绑定一个方法
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Student(object):
def __init__(self,name) -> None:
self.name = name
pass
s = Student("zhang")
print(s.name)
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)
def set_age2(self,age):
self.age = age
Student.set_age2 = set_age2
3.3.2. slot
Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
3.3.3. @property
Python内置的@property装饰器就是负责把一个方法变成属性调用的。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Student(object):
def __init__(self,name) -> None:
self._name = name
pass
def get_age(self):
return self._age
def set_age(self,age):
if not isinstance(age,int):
return ValueError("should be int")
if age <0 or age >200:
return ValueError("age >=0 && age <=200")
self._age =age
class StudentV2(object):
def __init__(self,name) -> None:
self._name = name
pass
@property
def age(self):
return self._age
@age.setter
def age(self,age):
if not isinstance(age,int):
return ValueError("should be int")
if age <0 or age >200:
return ValueError("age >=0 && age <=200")
self._age =age
3.3.4. 多重继承
由于Python允许使用多重继承,因此,MixIn就是一种常见的设计.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Animal():
pass
class Flyable():
def fly(self):
print("fly")
class Bid(Animal,Flyable):
pass
3.3.5. 定制类
__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串。
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
__iter__,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
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 # 返回下一个值
def __getitem__(self,n):
if isinstance(n,int):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
if isinstance(n,slice):
start =n.start
stop = n.stop
if start is None:
start =0
res = []
a,b=1,1
for x in range(stop):
if x>=start:
res.append(a)
a,b=b,a+b
return res
f = Fib()
for i in f:
print(i)
print(f[1:2])
print(f[:4])
__getitem__可以实现按照下标来获取元素。
代码同上
__getattr__ 会在获取属性的时候进行调用。
class Student(object):
def __init__(self):
self.name = 'panda'
def __getattr__(self,attr):
if attr == "score":
return 9999999
只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。
__call__ 可以让对象直接调用,通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。
3.3.6. 枚举
Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较。
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
In [2]: d1 = Weekday.Mon
In [3]: d1
Out[3]: <Weekday.Mon: 1>
In [4]: print(d1)
Weekday.Mon
In [5]: print(d1.value)
1
In [6]: d2 =Weekday(2)
In [7]: d2 == Weekday.Tue
Out[7]: True
In [8]: 2 == Weekday.Tue
Out[8]: False
3.3.7. 元类
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Student(object):
def study(self,book):
print(f"study {book}")
def study_v2(self,book):
print(f"study {book}")
StudentV2 = type('StudentV2',(object,),dict(study_v2=study_v2))
s = StudentV2()
s.study_v2("math")