(十八)python ,类变量, __slots__属性, 类方法, 静态方法 ,继承和派生

目录

类变量

类的  __slots__ 属性

类方法:

静态方法 @staticmethod

继承(inheritance)  和  派生  (derived)

覆盖override

super 函数:


类变量

    类变量的类的属性,此属性属于类,不属于类的实例
    作用:
        通常用来存储该类对象共有的数据
    说明:
        类变量可以通过类直接访问
        类变量可以通过类的实例直接访问
        类变量可以通过此类的对象的  __class__属性间接访问

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

# 此示例示意类变量的用法,及类和对象的关系
class Human:
    total_count = 0  # 类变量,此变量用来记录所有对象的个数
    def __init__(self, n):
        self.name = n

print("Human类内的类变量Human.total_count=",Human.total_count)

# 类变量可以通过类直接访问
Human.total_count += 1
print("Human.total_count=", Human.total_count)

# 类变量可以通过类的实例直接访问
h1 = Human('小张')
print("h1.total_count=", h1.total_count)
h1.total_count = 100  # 此做法是为实例添加一个变量,并不是修改类变量
print('Human.total_count=', Human.total_count)  # 1

# 类变量可以通过此类的对象的 __class__属性间接访问
h1.__class__.total_count = 200
print("Human.total_count=", Human.total_count)  # 200
# 此示例示意类变量的用法,及类和对象的关系
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

print("当前有%d个Human的实例对象" % Human.total_count)
h1 = Human('小张')
print("当前有%d个Human的实例对象" % Human.total_count)
h2 = Human('小李')
print("当前有%d个Human的实例对象" % Human.total_count)
del h1  # 当对象销毁时。自动将类变量做减1操作
print("当前有%d个Human的实例对象" % Human.total_count)

 类的文档字符串:
    类内没有赋值给任何变量的字符串为类的文档字符串
    类的文档字符串由类的__doc__属性绑定

class Dog:
    ''这是类的文档字符串'''
    pass
>>> help(Dog)
>>> dog1 = Dog()
>>> help(Dog1)

类的  __slots__ 属性

    作用:
        限定一个类创建的实例只能有固定的属性(实例变量),不允许对象添加列表以外的属性
        防止用户因错写属性的名称而发生程序错误
    说明:
        含有__slots__属性的类所创建的实例没有__dict__属性,即此实例不用字典来存储对象的属性

# 此示例示意__slots__属性的作用和用法
class Student:
    # 此列表让Student创建的对象只能用name和 age属性
    # 不能有其它属性
    __slots__ = ['name', 'age']
    def __init__(self, name, age):
        self.name = name
        self.age = age

s1 = Student('Tarena', 15)
print(s1.age)  # 15
# s1.Age = 16  # 报错,不允添加__slots__列表以外的属性
print(s1.age)  # 16?

类方法:

    类方法是用于描述类的行为的方法,此方法属于类,不属于该类创建的实例
    说明:
        1.类方法需要使用@classmethod 装饰器定义
        2.类方法至少有一个形参,第一个形参用于绑定类,约定写为'cls'
        3.类实例和对象实例都可以调用类方法
        4.类方法不能访问此类创建的对象的属性
 

# 此示例示用类方法的使用
class A:
    v = 0  # <<<---类变量
    def __init__(self):
        self.my_v = 10000
    @classmethod
    def get_v(cls):
        '''此方法为类方法,cls用于绑定调用此方法的类
        此方法用于返回类变量v的值
        '''
        return cls.v
        # return cls.my_v  # 出错
    @classmethod
    def set_v(cls, value):
        cls.v = value

print(A.get_v())  # 0  调用类方法返回值
A.set_v(100)
print(A.get_v())  # 100

a = A()
print(a.get_v())  # 100
a.set_v(200)
print(a.get_v())  # 200
print(A.get_v())  # 200

print(a.my_v)  # 10000

静态方法 @staticmethod

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

    说明:
        静态方法需要使用@statimethod装饰器定义
        静态方法与普通函数定义相同,不需要传入self实例参数和cls类参数
        静态方法只能凭借该类或类的实例调用
        静态方法不能访问类变量和实例变量(属性)

# 此示例示意静态方法的使用
class A:
    @staticmethod
    def myadd(x, y):
        return x + y

print(A.myadd(100, 200))  # 300
a = A()
print(a.myadd(300, 400))  # 700

练习:
    用类来描述一个学生的信息(可以修改之前写的Student类)
    class Student:
        ....此处自己实现

    学生信息有:
        姓名,  年龄,  成绩
    将这些学生对象存于列表中,可以任意添加和删除学生信息
    1) 打印学生的个数
    2) 打印出所有学生的平均成绩
    3) 打印出所有学生的平均年龄
    (建议用类变量存储学生的个数)

class Student:
    count = 0
    def __init__(self, n, a, s):
        self.name, self.age, self.score = n, a, s
        self.__class__.count += 1
    def __del__(self):
        self.__class__.count -= 1
    
L = []
L.append(Student("小张", 20, 100))
L.append(Student("小李", 19, 97))

# L.remove(Student("小李", 19, 97))
del L[1]
L.append(Student("小赵", 18, 70))
L.append(Student("小姜", 17, 80))
print(L)

print("当前有%d个学生对象" % Student.count)
scores = 0
for s in L:
    scores += s.score
print("平均成绩是:", scores/Student.count)

ages =  sum( (s.age for s in L) )
print('平均年龄是:', ages/Student.count)


继承(inheritance)  和  派生  (derived)

什么是继承/派生
    继承是从已有的类中派生出新的类,新类具有类的原类的行为,并能扩展新的行为
    派生类就是从一个已有的类衍生出新的类,在新的类上可以添加新的属性和行为

    作用:
        1.用继承派生机制,可以将一些共有功能加在基类中,实现代码共享
        2.在不改变超类的代码的基础上改变原有的功能    
    名词
        基类(base class)/超类(super class)/父类(father class)
        派生类(derivef class) / 子类

    单继承:
        语法:
            class 类名(基类名):
                语句块
        说明:
            单继承是指派生类由一个基类衍生出来
 

# 此示例示意单继承的语句及定义方法
class Human:
    '''此类用于描述人类的共性行为'''
    def say(self, what):
        print("say:", what)
    def walk(self, distance):
        print("走了", distance, '公里')

class Student(Human):
    def study(self, subject):
        print("学习", subject)

class Teacher(Human):
    def teach(self, subject):
        print("正在教:", subject)

h1 = Human()
h1.say('今天天气真好')
h1.walk(5)
print('-----------------')
s1 = Student()
s1.walk(4)
s1.say("走的有点累")
s1.study('python')

print('---------------')
t1 = Teacher()
t1.say("今天晚饭吃什么?")
t1.walk(3)
t1.teach("继承/派生")

思考下列代码做什么事?

class MyList(list):
    def insert_head(self, n):
        self.insert(0, n)

myl = MyList(range(3, 6))
myl.insert_head(2)
myl.append(6)
print(myl)  # [2, 3, 4, 5, 6]


继承说明:
    任何类都直接可间接的继承自object类
    object类是一切类的超类

类的  __base__ 属性
     __base__属性用来记录此类的基类

示例:
  class Human:
      pass
  class Student(Human):
      pass
  class Teacher(Human):
      pass
  Student.__base__is Human # True


内建类的继承关系见:
  >>> help(__builtins__)


覆盖override


什么是覆盖
  覆盖是指在有继承关系的类中子类中实现了与基类同名的方法,在子类实例调用该方法时,实际调用的是子类中的覆盖版本的方法的现象叫覆盖

class A:
    '''A类'''
    def work(self):
        print("A.work被调用!")

class B(A):
    '''B类'''
    def work(self):
        '''work 方法覆盖了父类的work'''
        print("B.work被调用!")

b = B()
b.work()  # B.work

a = A()
a.work()  # A.work


super 函数:


  super(type,obj)  返回绑定超类的实例(要求obj必须为type类型的实例)
  super() 返回绑定超类的实例,等同于  super(__class__,实例方法的第一个参数),必须用在方法内调用

作用:
  返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法

# 此示例示意用super构造函数来间接调用父类的覆盖版本的方法
class A:
    def work(self):
        print("A.work()")

class B(A):
    def work(self):
        print("B.work()")

    def super_work(self):
        '''此方法先调用一下子类的work,
        再调用一下父类的work'''
        self.work()  # 调用自己的work
        # super(B, self).work()  # 调用父类的work
        super().work()  # 调用父类的work

b = B()
# b.work()  # B.work(),
# super(B, b).work()  # A.work()
b.super_work()
# super().work()  # 错的!!! super() 不能在方法使用


显示调用基类的构造方法
  当子类中实现了__init__方法,基类的构造方法并不会被调用,此时需要显示调用基类的构造方法

class Human:
    def __init__(self, n, a):
        self.name = n
        self.age = a
        print("Human.__init__被调用")
    def infos(self):
        print("姓名:", self.name)
        print("年龄:", self.age)

class Student(Human):
    def __init__(self, n, a, s):
        super().__init__(n, a)  # 显式调用父类的初始化方法
        self.score = s
        print("Student.__init__被调用")

    def infos(self):
        super().infos()
        print("成绩:", self.score)

# h1 = Human('小张', 18)
# h1.infos()
s1 = Student("魏老师", 35, 60)
s1.infos()
#扩展list类,创建新的类型示例:
class MyList(list):
     def __init__(self, a, age=0):
         super().__init__(a)
         self.age = age
     def infos(self):
        print("列表是:", self)
        print('年龄是:', self.age)


 

猜你喜欢

转载自blog.csdn.net/zh__quan/article/details/81608283
今日推荐