zoukankan      html  css  js  c++  java
  • 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
    目前看不懂。

     
     

     

  • 相关阅读:
    在windows下安装mongodb(1)
    kettle过滤记录运用
    Robberies(简单的01背包 HDU2955)
    Alice and Bob(贪心HDU 4268)
    A Simple Problem with Integers(树状数组HDU4267)
    A Round Peg in a Ground Hole(凸包应用POJ 1584)
    Fishnet(暴力POJ 1408)
    Wall(凸包POJ 1113)
    Pipe(点积叉积的应用POJ1039)
    I love sneakers!(分组背包HDU3033)
  • 原文地址:https://www.cnblogs.com/wuchenggong/p/8799711.html
Copyright © 2011-2022 走看看