3-Python类class

作者: Creator_Ly | 来源:发表于2019-01-17 22:25 被阅读3次

    对于写习惯C语言的人才说,类其实就跟结构体一个样,就是类里面的成员又增加了很多特性。

    0.class的特点

    与结构体有一个很重要的区别是

    结构体定义后里面的成员就不能变了,而class却可以动态添加成员,这就是动态语言的牛逼之处。

    如定义如下lass,里面一个成员都没有

    class Student(object):
        pass
    
    

    我们定义一个实例后就可以对其进行添加成员name

    s = Student()
    s.name = 'ly'
    
    print(s.name)
    

    这样class里面就多了一个name的成员,我们可以打印看下

    class Student(object):
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def number(self):
            for i, j in vars(self).items():
                print(i,j)
    
    s = Student()
    s.number()
    s.name = 'ly'
    s.number()
    

    结果,可以看到第二次打印的时候多了一个name

    a 1
    b 2
    a 1
    b 2
    name ly
    

    1.添加必须绑定的属性init

    class Student(object):
    
        def __init__(self, name, score):
            self.name = name
            self.score = score
    

    特殊方法init前后分别有两个下划线

    注意到init方法的第一个参数永远是self,后面的参数为强制属性,所以在创建实例的时候,就不能传入空的参数了,必须传入与init方法匹配的参数

    如:

    lisa = Student('Lisa', 99)
    bart = Student('Bart')
    
    

    结果,可以看到缺少score就会出现错误

    TypeError: __init__() missing 1 required positional argument: 'score'
    

    2.添加函数

    和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

    class Student(object):
    
        def __init__(self, name, score):
            self.name = name
            self.score = score
    
        def print_score(self):
            print('%s: %s' % (self.name, self.score))
    
    >>>bart = Student('Bart Simpson', 59)
    >>>bart.print_score()
    Bart Simpson: 59
    
    

    3.限制实例的属性slots

    在《0.class的特点》里面,我们看到了实例的属性可以动态添加,如果我们想要限制实例的添加,只能是我们需要的几个才能用,就需要用到slots进行限制了

    class Student(object):
        __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    
    >>> s = Student() # 创建新的实例
    >>> s.name = 'Michael' # 绑定属性'name'
    >>> s.age = 25 # 绑定属性'age'
    >>> s.score = 99 # 绑定属性'score'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'score'
    

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

    4.添加访问权限

    果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

    class Student(object):
    
        def __init__(self, name, score, gender):
            self.name = name
            self.score = score
            self.__gender = gender
    
        def print_score(self):
            print('%s: %s: %s' % (self.name, self.score, self.__gender))
    
        def get_grade(self):
            if self.score >= 90:
                return 'A'
            elif self.score >= 60:
                return 'B'
            else:
                return 'C'
    
        def get_gender(self):
            return self.__gender
    
        def set_gender(self, gender):
            if 0 <= gender <= 100:
                self.__gender = gender
            else:
                print('bad gender')
    

    __gender变成了内部变量,所以外部没办法改也没办法读,这时候可以通过在类里面添加读和写的接口,这样做就可以进行条件的限制。

    如:

    def set_gender(self, gender):
            if 0 <= gender <= 100:
                self.__gender = gender
            else:
                print('bad gender')
    

    5.获取/判断对象信息

    type

    types

    isinstance

    总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。

    仅仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态

    首先你有一个command.py文件,内容如下,这里我们假若它后面还有100个方法

    class MyObject(object):
        def __init__(self):
            self.x = 9
        def add(self):
            return self.x + self.x
    
        def pow(self):
            return self.x * self.x
    
        def sub(self):
            return self.x - self.x
    
        def div(self):
            return self.x / self.x
    

    然后我们有一个入口文件 exec.py,要根据用户的输入来执行后端的操作

    from command import MyObject
    computer=MyObject()
    
    def run():
        inp = input('method>')
    
        if inp == 'add':
            computer.add()
        elif inp == 'sub':
            computer.sub()
        elif inp == 'div':
            computer.div()
        elif inp == 'pow':
            computer.pow()
        else:
            print('404')
    

    上面使用了if来进行判断,那么假若我的command里面真的有100个方法,那我总不可能写100次判断吧,所以这里我们就会用到python的反射特性,看下面的代码

    from command import MyObject
    
    computer=MyObject()
    def run(x):
        inp = input('method>')
        # 判断是否有这个属性
        if hasattr(computer,inp):
        # 有就获取然后赋值给新的变量
            func = getattr(computer,inp)
            print(func())
        else:
        # 没有我们来set一个
            setattr(computer,inp,lambda x:x+1)
            func = getattr(computer,inp)
            print(func(x))
    
    if __name__ == '__main__':
        run(10)
    

    6.使用@property优化下访问权限

    第4点的访问权限的调用方法又略显复杂,没有直接用属性这么直接简单。

    有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!

    还记得装饰器(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 an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value
    
    
    s = Student()
    s.score = 60    # OK,实际转化为s.set_score(60)
    print(s.score)  # OK,实际转化为s.get_score()
    #s.score = 9999
    

    相关文章

      网友评论

        本文标题:3-Python类class

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