python创建类的流程
要想真正的了解类方法、实例方法和静态方法的区别。首先要搞清楚python在实例化中的过程。
首先我们编写一个Person
类。
class Person():
country = 'china'
def __init__(self):
self.name = 'root'
self.age = 30
# 实例方法
# 当你调用实例方法的时候,python解释器会自动将实例对象传给self
def test(self):
self.country = 'xxx'
print("实例方法", self)
# 静态方法
@staticmethod
def test2():
print("静态方法")
# 类方法
# 当你调用类方法的时候,python解释器会将类对象传递给self
@classmethod
def test3(cls):
cls.country = 'ddddd'
print("类方法", cls)
一个类已经创建好了,下面当我们执行
p = Person()
的时候,python是怎么工作的呢?
- 调用
__new__
方法申请一个内存空间。 - 调用
Person
中的__init__
方法,对__new__
方法申请到的内存空间进行初始化。 - 这里我们把
Person
称之为类对象,而p
我们称之为实例对象。 - 那么在内存中,就如下图:
python会另外开启一个内存空间给实例对象使用。在这个实例对象中,仅仅拥有__init__
定义的属性和__class___
等一些魔法属性。
而类对象中定义的方法在实例对象的空间中是没有的。实例对象中有一个__class__
属性,这个属性指向创建该实例对象的类对象。当实例对象想要调用类中定义的方法的时候,会通过__class__
进行调用。
有几个重点需要知道
-
实例对象中不存在类对象中定义的方法
class Person(): country = 'china' def __init__(self): self.name = 'root' self.age = 30 # 实例方法 # 当你调用实例方法的时候,python解释器会自动将实例对象传给self def test(self): self.country = 'xxx' print("实例方法", self) # 静态方法 @staticmethod def test2(): print("静态方法") # 类方法 # 当你调用类方法的时候,python解释器会将类对象传递给self @classmethod def test3(cls): cls.country = 'ddddd' print("类方法", cls) p = Person() print(p.__dict__) print(Person.__dict__)
看一下结果:
{'name': 'root', 'age': 30} {'__module__': '__main__', 'country': 'china', '__init__': <function Person.__init__ at 0x03AB9108>, 'test': <function Person.test at 0x03AB9390>, 'test2': <staticmethod object at 0x03AB8E10>, 'test3': <classmethod object at 0x03ABA5B0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
通过
__dict__
,我们可以看到在实例对象中,仅仅有的是通过__init__
初始化的内容。 -
实例对象通过
__class__
调用类对象中方法和属性
我们知道,刚刚类中定义的country
是类属性,那么如果实例对象想要修改这个类属性,就需要通过__class__
进行调用并修改。
还是刚才那个类,我们添加两个实例方法进去,通过对类属性的修改做一个验证。
# 通过self直接修改
def change1(self):
self.country = 'xxx'
# 通过__class__修改
def change2(self):
self.__class__.country = 'xxx'
然后分别进行调用:
p = Person()
p1 = Person()
print("self直接修改")
print("*"*50)
p.change1()
print(p.country)
print(p1.country)
print(p.__dict__)
print("*"*50)
print()
p = Person()
p1 = Person()
print("__class__直接修改")
print("*"*50)
p.change2()
print(p.country)
print(p1.country)
print(p.__dict__)
print("*"*50)
结果:
self直接修改
**************************************************
xxx
china
{'name': 'root', 'age': 30, 'country': 'xxx'}
**************************************************
__class__直接修改
**************************************************
xxx
xxx
{'name': 'root', 'age': 30}
**************************************************
可以看到,如果不通过__class__
修改类属性,那么仅仅是为实例对象添加了一个新的属性,而没有改变类属性的值。而通过__class__
才真正的引用到了类属性。而我们在直接使用实例对象去访问类属性的时候是可以访问的,原因是因为当python发现实例对象中没有这个属性的时候,就会自动调用__class__
去类对象中寻找。
类方法、实例方法、静态方法
在了解了类的创建以及内存分配以后。我们就可以来了解一下类中的方法。
还是我们定义的这个类:
class Person():
country = 'china'
def __init__(self):
self.name = 'root'
self.age = 30
# 实例方法
def test(self):
self.country = 'xxx'
print("实例方法", self)
# 静态方法
@staticmethod
def test2():
print("静态方法")
# 类方法
@classmethod
def test3(cls):
cls.country = 'ddddd'
print("类方法", cls)
首先要弄清楚实例方法中的self
和类方法中的cls
指的是什么东西?
我们弄一个例子看一下:
p = Person()
# 查看self
p.test()
Person.test(p)
Person.test3()
p.test3()
结果:
实例方法 <__main__.Person object at 0x0BAD41F0>
实例方法 <__main__.Person object at 0x0BAD41F0>
类方法 <class '__main__.Person'>
类方法 <class '__main__.Person'>
由此我们可以知道self
指向的是实例对象所在的内存空间,而cls
指向的是类对象。当我们调用实例方法的时候,python解释器会自动将实例对象传入self
,而当我们调用类方法的时候,python解释器则会将类对象存入到cls
中。
那么实例方法和类方法有什么区别呢?
由于实例方法传入的是实例对象,因此当我们对一些实例属性进行操作的时候,一般就构造实例方法。而当我们对类属性进行操作的时候就使用类方法。还是刚才的例子,更改country
的值。这次我们使用类方法就会轻松很多:
@classmethod
def test3(cls):
cls.country = 'ddddd'
print("类方法", cls)
同理,当我们对实例属性进行操作的时候,使用实例方法也就很方便。
除此之外,类方法和实例方法还有一个区别就是,当你所创造的这个类被当做一个模块导入的时候。如果要调用实例方法,那么就必须要进行实例化。实例化就会占用一些内存空间,当你仅仅是想使用这个类中的一些方法而并不想要实例化的时候,就可以定义一个类方法。
静态方法的作用则是,当你定义了一个类,需要构造一种方法,但是又不需要为这个方法传递类对象或者实例对象,仅仅想当做这个类中的一个普通方法的时候,就可以定义一个静态方法。(比如一些类的说明等)