美文网首页Python
Python学习(五)

Python学习(五)

作者: BlainPeng | 来源:发表于2017-02-16 20:17 被阅读46次

    类与对象

    # 类的声明,括号中表示继承自哪个类,没有的话一般都是继承自object
    class Student(object):
        # 类属性
        age = 18
        # 类似于Java中的构造方法, 给属性一些初始化值
        def __init__(self, name, score, sex):
            # 实例属性
            self.name = name
            self.score = score
            # 被双下划线"__"修饰的都是private属性,不能被外部访问
            self.__sex = sex
    
        """
        类中的方法,与普通函数的区别:第一个参数永远是self,表示创建的实例本身;
        外部调用方法时不需要传self
        """
    
        def print_info(self):
            print("%s,%d,%s" % (self.name, self.score, self.__sex))
    
        """
        提供set、get方法, 用于外部使用者对属性进行修改和获取
        """
    
        def set_sex(self, sex):
            self.__sex = sex
    
        def get_sex(self):
            return self.__sex
    
    
    # 创建对象,并传入类属性初始化值
    s = Student("Blain", 90, "male")
    s.print_info()          # Blain,90,male
    s.score = 95
    s.print_info()          # Blain,95,male
    s.set_sex("female")
    print(s.get_sex())      # female
    # 获取对象信息
    print(hasattr(s, "name"))           # True
    # 判断是否有属性
    print(hasattr(s, "grade"))          # False
    # 设置属性
    setattr(s, "grade", 9)
    print(hasattr(s, "grade"))          # True
    # 没有这个属性会报错
    # print(getattr(s, "address"))
    # 无属性时也可以自定义返回结果
    print(getattr(s, "address", "没有这个属性"))      # 没有这个属性
    # 获取方法信息
    fn = getattr(s, "print_info")
    print(fn)           # <bound method Student.print_info of <__main__.Student object at 0x100686320>>
    fn()                # Blain,95,female
    # 类属性即可以用类来获取,也可以通过实例来获取,但实例属性的优先级比类属性要高
    print(Student.age)  # 18
    print(s.age)        # 18
    

    面向对象高级编程

    使用slots

    • 给一个类动态的绑定属性和方法

        from types import MethodType
      
        class People(object):
            pass
        
        p1 = People()
        p2 = People()
        # 动态的给实例p1绑定name属性
        p1.name = "Blain"
        
        # 定义一个函数作为实例方法
        def set_age(self, age):
            self.age = age
        
        # 动态的给实例p1绑定一个方法
        p1.set_age = MethodType(set_age, p1)
        
        print(p1.name)          # Blain
        p1.set_age(18)
        print(p1.age)           # 18
        
        # 给一个实例绑定的方法,对另一个实例是不起作用的
        # p2.set_age(19)  # AttributeError: 'People' object has no attribute 'set_age'
        
        # 为了给所有实例都绑定方法,可以给class绑定方法:
        def set_score(self, score):
            self.score = score
        
        People.set_score = set_score
        p1.set_score(80)
        print(p1.score)         # 80
        p2.set_score(90)
        print(p2.score)         # 90
      
    • 限制实例的属性

        class People2(object):
            # 用tuple定义允许绑定的属性名称
            __slots__ = ("name", "age")
        
        p3 = People2()
        p3.name = "Tom"
        p3.age = 16
        # p3.score = 99  # AttributeError: 'People2' object has no attribute 'score'
      

    slots定义的属性仅对当前类实例起作用,对继承的子类是不起作用

    使用@property

    修改和获取属性,可以通过实例对象直接获取属性来进行修改,但若这个属性是private的话就没办法修改;然后也可以通过类对外提供的set和get方法来获取属性或修改,不过这样的话略显繁琐。有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?之前有学到装饰器(decorator)可以给函数动态加上功能,Python内置的@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 integer")
            if value < 0 or value > 100:
                raise ValueError("score must be between 0 ~ 100")
            self.__score = value
    
    
    s = Student()
    s.score = 30            # 这里实际转化为s.set_score(60)
    print(s.score)          # 30 这里实际转化为s.get_score()
    s.score = 1000  
    print(s.score)          # ValueError: score must be between 0 ~ 100
    

    多重继承

    一个类是可以继承另一个类的,但以前都是单继承,若需要“混入”额外的功能,通过多重继承就可以实现。在Python中,这种设计通常称之为MixIn

    class Animal(object):
    pass
    
    
    class Mamal(Animal):
        pass
    
    
    class Bird(Animal):
        pass
    
    
    class RunnableMixIn(object):
        def run(self):
            print("可以跑的动物")
    
    
    class FlyableMixIn(object):
        def fly(self):
            print("可以飞的动物")
    
    
    class Dog(Mamal, RunnableMixIn):
        pass
    
    # 很显然,鹦鹉既属于鸟类,也具有飞的功能
    class Parrot(Bird, FlyableMixIn):
        pass
    

    但在Java中,一个类只能够进行单继承,所以MixIn这种设计不适用Java。

    定制类

    class Student(object):
        def __init__(self, name):
            self.name = name
            self.a, self.b = 0, 1  # 初始化两个计数器a,b
    
        # 自定义类输入信息,有点类似于java中的toString方法, 返回用户看到的字符串
        def __str__(self):
            return "Student object (name: %s)" % self.name
    
        # 当在命令行交互模式下直接调用实例变量时,会调用这个方法,返回程序开发者看到的字符串;代码一般与__str__一致
        __repr__ = __str__
    
        # 如果一个类想被用于for ... in循环,就必须实现__iter__方法
        def __iter__(self):
            return self  # 实例本身就是迭代对象,故返回自己
    
        # 然后for循环就会不断调用该迭代对象的__next__方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环
        def __next__(self):
            self.a, self.b = self.b, self.a + self.b  # 计算下一个值
            if self.a > 20:
                raise StopIteration
            return self.a
    
        # 实现此方法能够使Student像list一样通过索引获取值
        def __getitem__(self, item):
            a, b = 1, 1
            if isinstance(item, int):  # item代表的是索引
    
                for x in range(item):
                    a, b = b, a + b
                return a
            if isinstance(item, slice):  # item代表的是切片
                start = item.start
                stop = item.stop
                if start is None:
                    start = 0
                l = []
                for x in range(stop):
                    if x >= start:
                        l.append(a)
                    a, b = b, a + b
                return l
    
        # 当调用不存在的属性时,Python解释器会试图调用此方法来获得属性
        # 这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
        def __getattr__(self, attr):
            if attr == "sex":
                return "Male"
            raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
    
        # 实现此方法能够让对象像函数那样直接调用,也就是把对象看成函数,把函数看成对象,它们都是在运行期间创建出来的
        # 这样一来,我们就模糊了对象和函数数的界面,那如何来判断一个变量是对象还是函数呢? 可能通callable函数
        def __call__(self):
            print("My name is %s" % self.name)
    
    
    # print(Student("Blain"))           # Student object (name: Blain)
    # for n in Student("Blain"):
    #     print(n)                      # 1,1,2,3,5,8,13
    
    s = Student("Blain")
    # print(s[0])                           # 1
    # print(s[1])                           # 1
    # print(s[2])                           # 2
    # print(s[3])                           # 3
    # print(s[4])                           # 5
    # print(s[:5])                          # [1,1,2,3,5]
    # print(s.age)                          # AttributeError: 'Student' object has no attribute 'age'
    print(callable(s))                      # True
    print(callable("test"))                 # False
    

    使用枚举类

    Enum可以把一组相关常量定义在一个class中,且class不变,而且成员也可以直接比较

    from enum import Enum, unique
    
    Month = Enum("Month", ("Jan", "Feb", "Mar", "Apr", "May", "June", "July"))
    # 单独的引用一个常量
    print(Month.Jan)            # Month.Jan
    # 枚举它的所有成员
    for name, member in Month.__members__.items():
        # value属性是自动赋给成员的int常量,默认是从1开始
        print(name, "=>", member, ",", member.value)
        # Jan => Month.Jan , 1
        # Feb => Month.Feb , 2
        # Mar => Month.Mar , 3
        # Apr => Month.Apr , 4
        # May => Month.May , 5
        # June => Month.June , 6
        # July => Month.July , 7
    
    # 自定义枚举类
    @unique  # @unique装饰器可以帮助我们检查保证没有重复值
    class Weekday(Enum):
        Sun = 0  # Sun的Value被设置为0
        Mon = 1
        Tue = 2
        Wed = 3
        Thu = 4
        Fri = 5
        Sat = 6
    
    
    d1 = Weekday.Mon
    print(d1)                        # Weekday.Mon
    print(Weekday.Mon)              # Weekday.Mon
    print(Weekday["Mon"])             # Weekday.Mon
    print(Weekday(1))               # Weekday.Mon
    print(Weekday.Mon.value)          # 1
    print(d1 == Weekday(1))       # True
    print(d1 == Weekday.Mon)        # True

    相关文章

      网友评论

        本文标题:Python学习(五)

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