类、对象、变量、方法
在实例化时,会先自动调用__new.__(cls)魔术方法,把类对象和其他的实参一起打包,把实例化的类对象作为实参传给cls,__new__会根据该类对象创建出一个实例对象,__new__再调用__init__(self),把该实例对象作为实参传递给self,把刚刚打包的其他实参传给__init__的其他形参,然后通过____init____方法对该实例对象进行属性的初始化操作,最后由__new__把初始化属性之后的实例对象返回出来
实例对象是由__new__会根据该类对象创建出一个实例对象,__new__创建并返回的,____init___只是起到加工的作用,所以__init__不能有返回值(必须返回None)
类变量、实例变量、实例化
# 定义一个类对象,类的名字首字母通常大写
class Student(object): # object 是所有类的基类, 通常省略不写
school = '二中' # 类变量
def __init__(self, name):
self.name = name # 实例变量
"""
对__new__(cls)方法介绍:
构造方法。它会将请求实例化所属的类作为实参传给cls(其他实参传给
__init__), 创建并返回这个类的实例对象, 通常不需要显示的声明该方
法, 因为父类的 object 中有定义
对__init__(self)方法介绍:
初始化方法。用来定制实例变量, 返回值只能是None(因为负责返回实例
对象的是构造方法)
"""
"""
实例化时, 会先调用__new__(cls)方法, 在实例对象被创建之后且返回
给调用者之前,
再调用__init__(self)方法, 把实例对象传给self参数, 做进一步的定
制
"""
stu1 = Student('小明') # 实例化, 得到实例对象stu1
stu2 = Student('小红') # 实例化,得到实例对象stu2
""" 实例变量的调用规则 """
print(stu1.name) # 实例对象stu1调用实例变量
print(stu2.name) # 实例对象stu2调用实例变量
# print(Student.name) # 类对象调用不到实例变量
""" 类变量的调用规则 """
print(Student.school) # 类对象可以直接调用类变量(推荐)
print(stu1.school) # 实例对象stu1也可以调用类变量
print(stu2.school) # 实例对象stu2也可以调用类变量
""" 实例变量是每个实例对象所独有的 """
stu1.name = '小强' # 把实例对象stu1的name变量指向新的值
print(stu1.name) # 实例对象stu1再次调用实例变量, 输出新的值
print(stu2.name) # 而实例对象stu2再次调用实例变量, 并不受到
影响
""" 类变量在整个实例对象中是公用的
类对象调用类变量重新赋值, 会影响所有的对象对该类变量的调用 """
Student.school = '一中' # 把Student类的school变量指向新的值
print(Student.school) # 类对象再次调用类变量, 输出新的值
print(stu1.school) # 实例对象stu1再次调用类变量, 也输出新的
值
print(stu2.school) # 实例对象stu2再次调用类变量, 也输出新的
值
""" 实例对象调用类变量重新赋值, 其实是在动态定义变量, 根本与类变
量无关 """
stu1.school = '三中' # 动态定义变量,定义了stu1对象的一个实例
变量
print(stu1.school) # 实例对象stu1调用上一步定义的实例变量
print(Student.school) # 而类变量还是那个类变量
print(stu2.school) # 而类变量还是那个类变量
类方法、对象方法、静态方法
- 在 Python 中,一般把定义在类中的函数叫方法(method),不在类中的叫函数(function)
- 方法通常有参数,比如对象方法隐式的接收了 self 参数,类方法隐式 的接收了 cls 参数
- 函数可以没有参数
class Student:
@staticmethod # 静态方法 装饰器
def eat():
print('我要开动了~')
@classmethod # 类方法 装饰器
def sleep(cls): # cls表示当前调用的类对象
print('我要就寝了~')
def init(self, age): # self表示当前调用的实例对象
self.age = age
print(f'我{self.age}岁开始学习')
# self, cls不是关键字,可以换成自己写的其他任意名字代替,调用的
时候统一就可以了
# 静态方法:类可以直接调用,实例对象也可以调用,推荐类调用
# 类方法:类可以直接调用,实例对象也可以调用,推荐类调用
# 对象方法:实例对象调用,类不可调用
stu = Student()
Student.eat()
Student.sleep()
stu.eat()
stu.sleep()
# print(stu.age) # 报错(stu没有age变量)
stu.init(7) # 可能会碰到另外一种写法:Student.init(stu, 7)
print(stu.age) # 不报错(上一步调用方法之后, 创建了self.age变量)
思考:静态方法、类方法有什么区别?
class A:
var1 = 123
@classmethod
def func1(cls):
print(cls.var1)
@staticmethod
def func2():
print(A.var1)
class B(A):
var1 = 321
A.func1()
A.func2()
B.func1()
B.func2()
动态定义变量
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print(f'名字:{self.name}, 年龄:{self.age}, 地址:{self.address}')
def study1(self):
self.course = "语文"
print(f'今天学习的科目是:{self.course}')
def study2(self):
print(f'今天学习的科目是:{self.course}')
stu1 = Student('张三', 18) # 实例化
stu2 = Student('小明', 28) # 实例化
# stu1.show_info() # 报错(因为stu1没有address变量)
stu1.address = '黄土高坡' # stu1动态定义实例变量
print(stu1.address) # 输出: 黄土高坡
# print(stu2.address) # 报错(因为实例变量是每个实例对象所独有的)
stu1.show_info() # 不报错(因为stu1动态定义了address变量)
# stu2.study2() # 报错(因为stu2没有course变量)
stu2.study1() # 不报错(因为study1方法中定义了course变量)
stu2.study2() # 不报错(因为study1方法执行之后, course变量已经被定义了)
stu2.course = '数学' # 动态定义实例变量
stu2.study1() # study1方法中会把self.course重写赋值
class Worker:
def __init__(self, name):
self.name = name
wk = Worker('李四')
Worker.factory = "江南皮革厂" # 动态定义类变量
print(Worker.factory) # 类对象调用类变量(推荐)
print(wk.factory) # 实例对象也可以调用类变量
# print(Worker.name) # 报错(类对象调用不到实例变量)
Worker.name = '王五' # 动态定义类变量
print(Worker.name) # 类对象调用类变量
print(wk.name) # 实例对象优先调用实例变量name, 而不调用类变量name