美文网首页
Python面向对象高级编程

Python面向对象高级编程

作者: 云木杉 | 来源:发表于2019-01-03 18:58 被阅读0次

    使用slots

    • 给实例绑定一个属性
    >>> def set_age(self, age): # 定义一个函数作为实例方法
    ...     self.age = age
    ...
    >>> from types import MethodType
    >>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
    >>> s.set_age(25) # 调用实例方法
    >>> s.age # 测试结果
    
    class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    

    @Property

    • @Property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数必要的检查,这样,程序运行时就减少了出错的可能性。
    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 = 60
    print('s.score =', s.score)
    # ValueError: score must between 0 ~ 100!
    s.score = 9999
    

    多重继承

    • 通过多重继承,一个子类就可以同时获得多个父类的所有功能
    class Animal:
              pass
    
    class Fly:
              pass
    
    class Bard(Animal, Fly):
        pass
    
    • 多继承设计 称为MIxIn 目的就是给一个类增加多个功能。

    定制类

    • str 类似于Java中的toString()
    >>> class Student(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...     def __str__(self):
    ...         return 'Student object (name: %s)' % self.name
    
    • reprstr的区别,str返回用户看到的字符串,而repr返回程序开发者看到的字符串。

    • iter() 如果一个类想被用于for...in循环,类似list或tuple那样,就必须实现一个iter方法,该方法返回一个迭代对象,然后,python的for循环就会不断调用迭代对象的next方法拿到循环的下一个值

    • getitem Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list还是不行,需要实现getitem方法

    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):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
    for n in Fib():
         print(n)
    print(Fib()[5])
    
    • getattr 动态返回一个属性 只有在没有找到属性的情况下,才调用getattr,已有的属性,比如name,不会在getattr中查找
    class Student(object):
    
        def __init__(self):
            self.name = 'Michael'
    
          def __getattr__(self, attr):
            if attr=='score':
                return 99
    >>> s = Student()
    >>> s.name
    'Michael'
    >>> s.score
    99
    
    
    • call 复写此方法,直接对实例进行调用
    • 通过callable()函数,我们就可以判断一个对象是否是可调用对象
    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            print('My name is %s.' % self.name)
    
    >>> s = Student('Michael')
    >>> s() # self参数不要传入
    My name is Michael.
    
    
    >>> callable(Student())
    True
    >>> callable(max)
    True
    >>> callable([1, 2, 3])
    False
    >>> callable(None)
    False
    >>> callable('str')
    False
    
    
    

    使用枚举类

    • @unique装饰器可以帮组我们检查保证没有重复值
    • 既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    from enum import Enum, unique
    
    @unique
    class Weekday(Enum):
        Sun = 0
        Mon = 1
        Tue = 2
        Wed = 3
        Thu = 4
        Fri = 5
        Sat = 6
    
    day1 = Weekday.Mon
    
    print('day1 =', day1)
    print('Weekday.Tue =', Weekday.Tue)
    print('Weekday[\'Tue\'] =', Weekday['Tue'])
    print('Weekday.Tue.value =', Weekday.Tue.value)
    print('day1 == Weekday.Mon ?', day1 == Weekday.Mon)
    print('day1 == Weekday.Tue ?', day1 == Weekday.Tue)
    print('day1 == Weekday(1) ?', day1 == Weekday(1))
    
    for name, member in Weekday.__members__.items():
        print(name, '=>', member)
    
    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)
    

    使用元类

    type()

    • 动态语言和静态语言最大的不同,就是函数和类的定义,不是便已是定义的,二是运行时动态创建的。

    • type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type,而h是一个实例,它的类型就是class Hello。

    • 我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。

    • type()函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object)...的定义:

    >>> def fn(self, name='world'): # 先定义函数
    ...     print('Hello, %s.' % name)
    ...
    >>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
    >>> h = Hello()
    >>> h.hello()
    Hello, world.
    >>> print(type(Hello))
    <class 'type'>
    >>> print(type(h))
    <class '__main__.Hello'>
    

    要创建一个class对象,type()函数依次传入3个参数:
    class的名称;
    继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
    class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。

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

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

    metaclass元类 (看不懂 不看了)

    • 除了使用type()动态创建类以外,要控制类的创建行为,可以使用metaclass(元类)

    当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。
    但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。
    连接起来就是:先定义metaclass,就可以创建类,最后创建实例。

    相关文章

      网友评论

          本文标题:Python面向对象高级编程

          本文链接:https://www.haomeiwen.com/subject/ubhqrqtx.html