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")