day18笔记:
类变量
类变量的类的属性,此属性属于类,不属于类的实例
作用:
通常用来存储该类对象共有的数据
说明:
类变量可以通过类直接访问
类变量可以通过类的实例直接访问
类变量可以通过此类的对象的 __class__属性间接访问
类变量
类变量的类的属性,此属性属于类,不属于类的实例
作用:
通常用来存储该类对象共有的数据
说明:
类变量可以通过类直接访问
类变量可以通过类的实例直接访问
类变量可以通过此类的对象的 __class__属性间接访问
语法:
class 类名(继承列表):
类变量名 = 表达式
...
class 类名(继承列表):
类变量名 = 表达式
...
示例见:
# 此示例示意类变量的用法,及类和对象的关系
class Human:
total_count = 0 # 类变量,此变量用来记录所有对象的个数
def __init__(self, n):
self.name = n
# 此示例示意类变量的用法,及类和对象的关系
class Human:
total_count = 0 # 类变量,此变量用来记录所有对象的个数
def __init__(self, n):
self.name = n
print("Human类内的类变量Human.total_count=",
Human.total_count)
Human.total_count)
# 类变量可以通过类直接访问
Human.total_count += 1
print("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
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
h1.__class__.total_count = 200
print("Human.total_count=", Human.total_count) # 200
# h2 = Human('小李')
类的文档字符串:
类内没有赋值给任何变量的字符串为类的文档字符串
类的文档字符串由类的__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
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?
print(s1.age) # 15
# s1.Age = 16 # 报错,不允添加__slots__列表以外的属性
print(s1.age) # 16?
类方法:
类方法是用于描述类的行为的方法,此方法属于类,不属于该类创建的实例
说明:
1. 类方法需要使用@classmethod 装饰器定义
2. 类方法至少有一个形参,第一个形参用于绑定类,约定写为'cls'
3. 类实例和对象实例都可以调用类方法
4. 类方法不能访问此类创建的对象的属性
示例见:
# 此示例示用类方法的使用
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
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.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.get_v()) # 100
a.set_v(200)
print(a.get_v()) # 200
print(A.get_v()) # 200
print(a.my_v) # 10000
# 无法用类方法访问调用此对象的a的my_v实例变量
print(a.get_v())
print(a.get_v())
静态方法 @staticmethod
静态方法是定义在类内的函数,此函数的作用域是类的内部
静态方法是定义在类内的函数,此函数的作用域是类的内部
说明:
静态方法需要使用staticmethod装饰器定义
静态方法与普通函数定义相同,不需要传入self实例参数和cls类参数
静态方法只能凭借该类或类的实例调用
静态方法不能访问类变量和实例变量(属性)
静态方法需要使用staticmethod装饰器定义
静态方法与普通函数定义相同,不需要传入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
a = A()
print(a.myadd(300, 400)) # 700
小结 :
实例方法, 类方法, 静态方法, 函数
实例方法, 类方法, 静态方法, 函数
练习:
用类来描述一个学生的信息(可以修改之前写的Student类)
用类来描述一个学生的信息(可以修改之前写的Student类)
class Student:
....此处自己实现
....此处自己实现
学生信息有:
姓名,年龄,成绩
将这些学生对象存于列表中,可以任意添加和删除学生信息
1) 打印学生的个数
2) 打印出所有学生的平均成绩
3) 打印出所有学生的平均年龄
(建议用类变量存储学生的个数)
姓名,年龄,成绩
将这些学生对象存于列表中,可以任意添加和删除学生信息
1) 打印学生的个数
2) 打印出所有学生的平均成绩
3) 打印出所有学生的平均年龄
(建议用类变量存储学生的个数)
继承(inheritance) 和 派生 (derived)
什么是继承/派生
继承是从已有的类中派生出新的类,新类具有原类的行为,并能扩展新的行为
派生类就是从一个已有的类衍生出新的类,在新的类上可以添加新的属性和行为
继承是从已有的类中派生出新的类,新类具有原类的行为,并能扩展新的行为
派生类就是从一个已有的类衍生出新的类,在新的类上可以添加新的属性和行为
作用:
1. 用继承派生机制,可以将一些共有功能加在基类中,实现代码共享.
2. 在不改变超类的代码的基础上改变原有的功能
名词
基类(base class)/超类(super class)/父类(father class)
派生类(derived class) / 子类
单继承:
语法:
class 类名(基类名):
语句块
说明:
单继承是指派生类由一个基类衍生出来
示例见:
1. 用继承派生机制,可以将一些共有功能加在基类中,实现代码共享.
2. 在不改变超类的代码的基础上改变原有的功能
名词
基类(base class)/超类(super class)/父类(father class)
派生类(derived 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)
def study(self, subject):
print("学习", subject)
class Teacher(Human):
def teach(self, subject):
print("正在教:", subject)
def teach(self, subject):
print("正在教:", subject)
h1 = Human()
h1.say('今天天气真好')
h1.walk(5)
print('-----------------')
s1 = Student()
s1.walk(4)
s1.say("走的有点累")
s1.study('python')
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("继承/派生")
t1 = Teacher()
t1.say("今天晚饭吃什么?")
t1.walk(3)
t1.teach("继承/派生")
思考下列表代码做什么事儿?
class MyList(list):
def insert_head(self, n):
self.insert(0, n)
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]
myl.insert_head(2)
myl.append(6)
print(myl) # [2, 3, 4, 5, 6]
继承说明:
任何类都直接可间接的继承自object类
object类是一切类的超类
任何类都直接可间接的继承自object类
object类是一切类的超类
类的 __base__ 属性
__base__属性用来记录此类的基类
__base__属性用来记录此类的基类
示例:
class Human:
pass
class Student(Human):
pass
class Teacher(Human):
pass
Student.__base__ is Human # True
class Human:
pass
class Student(Human):
pass
class Teacher(Human):
pass
Student.__base__ is Human # True
内建类的继承关系见:
>>> help(__builtins__)
>>> 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类'''
def work(self):
'''work 方法覆盖了父类的work'''
print("B.work被调用!")
b = B()
b.work() # B.work
b.work() # B.work
a = A()
a.work() # A.work
a.work() # A.work
问题:
在override.py中 ,b能否调用到父类的work方法?
在override.py中 ,b能否调用到父类的work方法?
super 函数:
super(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例)
super() 返回绑定超类的实例,等同于 super(__class__, 实例方法的第一个参数), 必须用在方法内调用
super(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例)
super() 返回绑定超类的实例,等同于 super(__class__, 实例方法的第一个参数), 必须用在方法内调用
作用:
返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法
示例见:
super.py
返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法
示例见:
super.py
显式调用基类的构造方法
当子类中实现了__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 __init__(self, n, a, s):
super().__init__(n, a) # 显式调用父类的初始化方法
self.score = s
print("Student.__init__被调用")
def infos(self):
super().infos()
print("成绩:", self.score)
super().infos()
print("成绩:", self.score)
# h1 = Human('小张', 18)
# h1.infos()
s1 = Student("魏老师", 35, 60)
s1.infos()
# 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)
class MyList(list):
def __init__(self, a, age=0):
super().__init__(a)
self.age = age
def infos(self):
print("列表是:", self)
print('年龄是:', self.age)