0
点赞
收藏
分享

微信扫一扫

Python 面向对象编程(二)

IT影子 2021-09-29 阅读 66

回顾

  • 使用面向对象组织代码,可以降低耦合度,其中类的创建使用 class 语句;
  • 构造函数的调用:类名(调用实参) ,用来实例化(创建)一个对象;
  • 实例方法:描述类有哪些行为;
  • 初始化方法:def __init__(self, 形参列表):
  • 析构方法:def __del__(self):
  • 实例属性:对象用于绑定自己数据的变量叫实例变量,也叫属性;
  • 每个对象都具有特殊属性:__dict____class__
  • 对象有 2 个常用的函数:isinstance(obj, 类或元组) type(obj)

一. 类变量

定义
类变量是类的属性,此属性属于类,不属于类的实例;通常用来存储该类对象共有的数据。

说明

  • 类变量可以通过属性直接访问:Human.total_count += 1
  • 类变量可以通过类的实例直接访问;
  • 类变量可以通过此类的对象的 __class__ 属性直接访问;

语法

class 类名(继承列表):
    类变量名 = 表达式
    ... 

示例:示意类变量的用法,以及类和对象的关系

class Human:
    # 类变量,记录所有实例对象的个数
    total_count = 0
 
    def __init__(self, n):
        """对象在创建时,自动被调用"""
        self.name = n
        # 如果一个对象诞生,则将类变量total_count做+1操作
        self.__class__.total_count += 1
 
    def __del__(self):
        """对象在销毁时,自动被调用"""
        self.__class__.total_count -= 1

类变量可以通过属性直接访问:

>> Human.total_count += 1
>> Human.total_count
1

类变量可以通过类的实例直接访问:

>> human1 = Human('Alex')
>> human1.total_count
2

实例的 __dict__ 属性存储了自定义的实例变量:

>> human1.__dict__
{'name': 'Alex'}

下面的做法将为当前的实例添加一个变量,并不是修改类变量:

>> human1.total_count = 100
>> Human.total_count
2
>> human1.total_count
100
>> human1.__dict__
{'name': 'Alex', 'total_count': 100}

实例对象的 __class__ 属性绑定了创建它的类,可以使用下面的方式修改类变量的值:

>> human1.__class__.total_count = 100
>> Human.total_count
100

类的 __slots__ 属性
用来限定一个类创建的实例只能有固定的属性(实例变量),不允许对象添加列表以外的属性。以防止用户因错写属性的名称而发生程序错误。

例如:Student 类中使用 __slots__ 类属性声明 - __slots__ = ['name', 'age'] ,让 Student 创建的对象只能用 name 属性和 age 属性,不能有其它属性。

class Student:
    """示意__slots__属性的作用和用法"""
    __slots__ = ['name', 'age']
 
    def __init__(self, name, age):
        self.name = name
        self.age = age

运行结果:

>> s1 = Student('Alex', 22)
>> s1.age
22
>> s1.name
'Alex'
>> s1.country = "China"
...
AttributeError: 'Student' object has no attribute 'country'

二. 类方法

类方法
用于描述类的行为,此方法属于类,不属于该类创建的实例;

说明

  • 类方法需要使用 @classmethod 装饰器定义;
  • 类方法至少有一个形参,第一个形参用于绑定类,约定为:cls
  • 类实例和对象实例都可以调用类方法;
  • 类方法不能访问实例属性和方法;

示例:类方法的使用

class A:
    """docstring for A"""
    # 类变量v
    v = 0
 
    def __init__(self):
        # __init__定义的为实例变量,属于类的实例
        self.my_v = 10000000
 
    # 类方法需要使用@classmethod装饰器定义
    @classmethod
    # 类方法至少有一个形参,第一个形参用于绑定类,约定为:'cls'
    def get_v(cls):
        """此方法为类方法,cls用于绑定调用此方法的类;此方法用于返回类变量v的值"""
        return cls.v
 
    @classmethod
    def set_v(cls, value):
        cls.v = value
 
 
if __name__ == "__main__":
    # 通过类实例来调用类方法
    print(A.get_v())
    A.set_v(100)
    print(A.get_v())
 
    # 通过对象实例调用类方法
    a = A()
    print(a.get_v())
    a.set_v(200)
    print(a.get_v())
 
    # 访问实例属性
    print(a.my_v)

三. 静态方法

静态方法
定义在类内的函数,此函数的作用域是类的内部;

说明

  • 静态方法需要使用 @staticmethod 装饰器定义;
  • 静态方法与普通函数定义相同,不需要传入 self 实例参数和 cls 参数;
  • 静态方法只能凭借该类或类的实例来调用;
  • 静态方法不能访问类变量和实例变量(属性);
  • 静态方法仅仅是属于一个类,和普通的函数是一样的。

示例:利用类方法和静态方法重写学生类

class Student:
    """描述学生的信息"""
    count = 0
 
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
        self.__class__.count += 1
 
    def print_info(self):
        print("{}: age={}, score={}".format(self.name, self.age, self.score))
 
    @classmethod
    def get_stu_number(cls):
        """只访问类变量,使用类方法即可"""
        return cls.count
 
    @staticmethod
    def average(students, kind):
        """不需要访问实例变量和类变量,仅仅是定义在类内的函数,使用静态方法即可"""
        sum_kind = 0
        for student in students:
            sum_kind += student.__dict__[kind]
        average = sum_kind // Student.get_stu_number()
        return average
 
    @staticmethod
    def add_stu_info():
        """一次性录入所有的学生信息,并以列表形式返回所有创建好的学生实例"""
        students = []
        while True:
            name = input('输入姓名:') or 'q'
            if name == 'q':
                break
            age = int(input('输入年龄:'))
            score = int(input('输入成绩:'))
            student = Student(name, age, score)
            students.append(student)
        return students
 
    @classmethod
    def remove_student(cls, name, students):
        """根据姓名删除列表中的学生"""
        for student in students:
            if student.name.lower() == name.lower():
                stu_list.remove(student)
                cls.count -= 1

录入学生信息:

>> stu_list = Student.add_stu_info()
输入姓名:Alex
输入年龄:12
输入成绩:100
输入姓名:Bob
输入年龄:14
输入成绩:90
输入姓名:
>>

调用静态方法,计算平均成绩 / 年龄:

>> Student.average(stu_list, 'score')
95
>> Student.average(stu_list, 'age')
13

删除列表中的学生:

>> Student.get_stu_number()
2
>> Student.remove_student('Alex', stu_list)
>> Student.get_stu_number()
1

调用实例方法,打印剩下学生的信息:

>> iter_stu = iter(stu_list)
>> next(iter_stu).print_info()
Bob: age=14, score=90
>> next(iter_stu).print_info()
...
StopIteration: 

四. 特性属性 @properity

作用
用来模拟一个属性,通过 @properity 装饰器可以对模拟的属性赋值和取值加以控制,以实现其它语言所拥有的 gettersetter 功能。

方式一score = property(get_score, set_score)

class Student:
    def __init__(self, score):
        self.__score = score
 
    def get_score(self):
        """实现getter"""
        return self.__score
 
    def set_score(self, s):
        """实现setter"""
        if 0 <= s <= 100:
            self.__score = s
        else:
            raise ValueError
 
    score = property(get_score, set_score)

运行结果:

>> s = Student(59)
>> s.score
59
>> s.score = 100
>> s.score
100
>> s.score = 1000
...
ValueError: 

方式二@property@score.setter

class Student:
    def __init__(self, score):
        self.__score = score
 
    @property
    def score(self):
        """实现getter"""
        return self.__score
 
    @score.setter
    def score(self, s):
        """实现setter"""
        if 0 <= s <= 100:
            self.__score = s
        else:
            raise ValueError

运行结果同上。

举报

相关推荐

0 条评论