zoukankan      html  css  js  c++  java
  • python learning OOP2.py

    class Student(object):
        pass
    
    s = Student()
    s.name = 'Chang' # 给一个实例动态绑定一个属性
    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)
    
    
    s2 = Student()
    '''
    s2.set_age(25) # 会报错
    给一个实例动态绑定的方法对另一个实例不起作用
    '''
    
    def set_score(self, score):
        self.score = score
    
    Student.set_score = set_score # 给所有实例都绑定方法,可以给class绑定方法:
    
    # 给class绑定方法后,所有实例均可调用:
    
    s.set_score(100)
    print(s.score)
    
    s2.set_score(99)
    print(s2.score)
    
    
    # 动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
    
    
    # __slots__ : 限制实例的属性
    
    class Student(object):
        __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    
    s = Student()
    s.name = 'Michael'
    s.age = 25
    # s.score = 99 # 报错 AttributeError: 'Student' object has no attribute 'score'
    
    class  GraduateStudent(Student):
        pass
    
    g = GraduateStudent()
    g.score = 9999 # __slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
    
    # 在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
    
    ##################################################
    
    # 使用@property 来进行输入检测
    
    s = Student()
    s.age = 9999 # 这显然不合理
    
    # 普通的方法就是在构造函数里加限制条件
    
    class Student(object):
        
        def get_score(self):
            return self._score
        
        def set_score(self, value):
            if not isinstance(value, int):
                raise TypeError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 and 100!')
            self._score = value
    
    s = Student()
    s.set_score(60) # ok
    print(s.get_score()) # 60
    # s.set_score(9999) # error
    
    # 然而上述调用方式稍显复杂,能不能用类似 属性 这样简单的方式来访问类的变量
    
    # Python内置的@property装饰器就是负责把一个方法变成属性调用的:
    
    class Student(object):
    
        # getter 变成属性,加上一行 @property 就可以了
        @property
        def score(self):
            return self._score
    
        # @property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
        @score.setter
        def score(self, value):
            if not isinstance(value, int):
                raise TypeError('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 # score.setter
    print(s.score) # score
    # s.score = 9999 报 typeerror 错
    
    # 定义只读属性:只定义 getter 不定义 setter
    
    class Student(object):
        @property
        def birth(self):
            return self._birth
        
        @birth.setter
        def birth(self, value):
            self._birth = value
        
        @property
        def age(self):
            return 2018 - self._birth
    
    # 上面的birth是可读写属性,而age就是一个只读属性
    
    s = Student()
    s.birth = 1996
    print(s.birth)
    print(s.age)
    # s.age = 100 # 报错:can't set attribute
    
    # 练习:
    # 请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:
    
    class Screen(object):
        
        @property
        def width(self):
            return self._width # 变量名和函数名要区分开,不然会死循环
        
        @width.setter
        def width(self, value):
            self._width = value
    
        @property
        def height(self):
            return self._height
    
        @height.setter
        def height(self, value):
            self._height = value
    
        @property
        def resolution(self):
            return self._width * self._height # 一个和C++很不相同的地方,在类内写属性也要加 slef. 前缀
    
    # 测试:
    s = Screen()
    s.width = 1024
    s.height = 768
    print('resolution =', s.resolution)
    if s.resolution == 786432:
        print('测试通过!')
    else:
        print('测试失败!')
    
    
    
    ##################################################
    
    # 多重继承
    
    class Animal(object): # 基类
        pass
    
    class Mammal(Animal): # 哺乳动物
        pass
    
    class Bird(Animal): # 鸟类
        pass
    
    class Runnable(object): # 能跑
        def run(self):
            print('Running...')
    
    class Flyable(object): # 能飞
        def fly(self):
            print('Flying...')
    
    class Dog(Mammal, Runnable): # 狗
        pass
    
    class Bat(Mammal, Flyable): # 蝙蝠
        pass
    
    class Parrot(Bird, Flyable): # 鹦鹉
        pass
    
    class Ostrich(Bird, Runnable): # 鸵鸟
        pass
    
    # MixIn
    '''
    # 举个例子,Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixIn和ThreadingMixIn提供。通过组合,我们就可以创造出合适的服务来。
    
    # 比如,编写一个多进程模式的TCP服务,定义如下:
    
    class MyTCPServer(TCPServer, ForkingMixIn):
        pass
    
    # 编写一个多线程模式的UDP服务,定义如下:
    
    class MyUDPServer(UDPServer, ThreadingMixIn):
        pass
    '''
    
    # 定制类
    
    class Student(object):
        def __init__(self, name):
            self.name = name
    
    print(Student('Micheal')) # <__main__.Student object at 0x00000140EEBFC320>
    
    # 自定义打印实例信息
    
    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return 'Student object (name: %s)' % self.name
    
        __repr__ = __str__ # __str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。
    
    print(Student('Micheal'))
    
    # __iter__
    
    # 如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
    
    class Fib(object):
        def __init__(self):
            self.a = 0 
            self.b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            self.a, self.b = self.b, self.a + self.b
            if self.a > 100:
                raise StopIteration() # 迭代的停止条件
            return self.a
    
    
    for n in Fib():
        print(n)
    
    
    # __getitem__
    
    # Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行
    # 不能通过 Fib()[5] 取元素
    # 要想使用下标来取元素,需要实现 __getitem__() 方法
    
    class Fib(object):
        def __getitem__(self, n):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
    
    f = Fib()
    for x in range(10):
        print(f[x])
    
    # 实现切片
    
    class Fib(object):
        def __getitem__(self, n):
            if type(n) == int:
                a, b = 1, 1
                for x in range(n):
                    a, b = b, a + b
                return a
            
            if type(n) == slice:
                start = n.start
                stop = n.stop
                if start is None:
                    start = 0
                a, b = 1, 1
                L = []
                for x in range(stop):
                    if x >= start:
                        L.append(a)
                    a, b = b, a + b
                return L
    
    f = Fib()
    for x in range(10):
        print(f[x])
    
    print(f[0:5])
    print(f[:10])
    
    # 与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值。
    # 最后,还有一个__delitem__()方法,用于删除某个元素。
    
    # __getattr__
    
    # 正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。
    # 要避免这个错误,除了可以加上这个属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。
    
    class Student(object):
        def __init__(self):
            self.name = 'Michael'
        
        def __getattr__(self, attr):
            if attr == 'score':
                return 99
            if attr == 'age':
                return lambda:24
            raise AttributeError('no such a attribute.')
    
    # 当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值:
    # 注意,只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。
    
    s = Student()
    print(s.name)
    print(s.score)
    print(s.age()) # 返回函数也可以,但相应的调用方式要变
    # print(s.abc)
    
    # 这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
    
    
    # __call__
    
    # 在实例本身上调用
    
    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            print('My name is %s' % self.name)
    
    s = Student("chang")
    s()
    
    # __call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象
    
    # 怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用
    # 使用 Callalbe 来判断类中有 __call__() 的类实例
    
    print(callable(s))
    
    
    # 枚举类
    
    # Python 中实现常量定义
    
    JAN = 1
    FEB = 2
    PI = 3.1415
    
    # 缺点是 仍是变量
    
    # 更好的方法是为这样的枚举类型定义一个class类型,每个常量都是class的一个唯一实例。Python提供了Enum类来实现这个功能:
    
    from enum import Enum
    
    Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
    
    # Month类型的枚举类,直接使用Month.Jan来引用一个常量,或者枚举它的所有成员,value属性则是自动赋给成员的int常量,默认从1开始计数
    
    for name, member in Month.__members__.items():
        print(name, '=>', member, ',', member.value)
    
  • 相关阅读:
    javascript的window.open()具体解释
    Async.js解决Node.js操作MySQL的回调大坑
    入门--JTBC系统学习(1)
    Hadoop1.2.1 全然分布式集群搭建实操笔记
    Hessian原理与程序设计
    pycharm最新注册方法 pycharm最新激活方法 2016pycharm最新注册方法
    如何修改linux时间? 校正linux系统的时间
    python 内建函数 type() 和 isinstance() 介绍
    标准类型内建函数 str()和 repr() (及 `` 运算符) 简单介绍
    标准类型内建函数 cmp()介绍
  • 原文地址:https://www.cnblogs.com/ZCplayground/p/8995130.html
Copyright © 2011-2022 走看看