python面向对象高级编程

1.使用__slots__

  给特定实例动态绑定方法:

       class Student():

                pass

       s = Student()

       def set_age(self,age):

             self.age = age

       from types import MethodType

       s.set_age = MethodType(set_age,s)

       s.set_age(99)

      print(s.age)

      给所有实例动态绑定方法,即给类动态添加方法:

      Student.set_age = set_age

      s2 = Student()

      s2.set_age(88)

      s2.age

      __slots__的使用场景是给类限定特定的参数名,子类继承则不受限制,除非子类也使用__slots__,那么所有的属性包含子类和父类限定的这些个属性之和。

       举例:

       class Student():
                 __slots__ = ('name','age') #用tuple定义允许绑定的属性名称

        s = Student()

        s.name = 'Macol'

        s.age = 23

        s.score = 89 #erro

       class GradeStudent(Student):

                __slots__ = ('score') #用tuple定义允许绑定的属性名称

        s1 = GradeStudent()

        s1.score = 89

 2.@property 是为了一方面可以对内部数据属性进行检查,另一方面又能通过实例直接操作属性而设置的。

 class Student(object):
def get_score(self):
return self.__score
def set_score(self,score):
if not isinstance(score,int):
raise ValueError('score must be an int!')
if score>100 or score<0:
raise ValueError('score must be 0<=score<=100!')
else:
self.__score = score

s = Student()
print(s.set_score(int(99)))
print(s.get_score())

#@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,
# 负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:


class Student1(object):
@property #把一个getter方法变成属性
def score(self):
return self.__score
@score.setter #负责把一个setter方法变成属性赋值
def score(self, score):
if not isinstance(score, int):
raise ValueError('score must be an int!')
if score > 100 or score < 0:
raise ValueError('score must be 0<=score<=100!')
else:
self.__score = score

s1 =Student1()
s1.score = 98
print(s1.score)

 

3.多重继承

在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。

为了更好地看出继承关系,我们把RunnableFlyable改为RunnableMixInFlyableMixIn。类似的,你还可以定义出肉食动物CarnivorousMixIn和植食动物HerbivoresMixIn,让某个动物同时拥有好几个MixIn:

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
    pass

4.定制类

    1)、__str__ 类调用显示,__repr__

          

这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。

 

解决办法是再定义一个__repr__()。但是通常__str__()__repr__()代码都是一样的,所以,有个偷懒的写法:

 

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

2)、__iter__ 类
如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象
,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
#我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:
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 >1000:
raise StopIteration()
return self.a


for n in Fib():
print(n)

3)、
__getitem__ 、__setitem__、__delitem__

    Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素:

   4)、__getattr__

         

要避免这个错误,除了可以加上一个score属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。修改如下:

class Student(object):

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

    def __getattr__(self, attr):
        if attr=='score':
            return 99
#利用完全动态的__getattr__,我们可以写出一个链式调用
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('home').usr.bin.env)
5)、__call__
  任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用,能不能调用可用callable(Student())进行判断。
class Student(object):
def __init__(self,name):
self.name = name
def __call__(self):
print('My name is %s'%self.name)

  s = Student('Bob')
  s()


小结

Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。

本节介绍的是最常用的几个定制方法,还有很多可定制的方法,请参考Python的官方文档。

5.使用枚举类:
更好的方法是为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了Enum类来实现这个功能:

from enum import Enum
WEEK = Enum('WEEK',('SUN','MON','TUE','WEN','THU','FRI','SAT'))
print(type(WEEK))
print(WEEK)
for name,value in WEEK.__members__.items():
print(name,value)


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

for i in Weekday.__members__.items():
print(i)

6.使用元类:
1)、type(),我们type(Student)一个类时,返回的是type类型,一个实例的时候是class。
type(),即可以返回一个类型,也可以创建一个类型。
先定义一个函数
def fn(self,name):
self.name = name
print('Hello, %s.' % name)
Student = type('Student',(object,),dict(hello=fn))

  

要创建一个class对象,type()函数依次传入3个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。

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

正常情况下,我们都用class Xxx...来定义类,但是,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。

   2)、metaclass
目前看不懂。

 
 

 

原文地址:https://www.cnblogs.com/wuchenggong/p/8799711.html