1. 在Python中定义一个Class,通常用到的是普通的instanceMethod。定义instanceMethod时候,第一个参数必须是self,就是instance本身。调用的时候不用手动传入这个参数。classMethod第一个参数必须是cls,就是Class本身。staticMethod不需要(不能用)特殊参数。这里self和cls是convention,你也可以用任何名字,但这个位置会被解释器自动传入instance和class。定义classMethod和staticMethod时候,要在def的上一行用decorator来装饰一下,不加decorator会被当做普通instanceMethod,第一个参数被传入instance。
这几种method都无法直接读取class里的变量/属性,必须要加上类的名字。
class A():
z = 1
def im(self):
print('inst', z)
@classmethod
def cm(cls):
print('cls', z)
@staticmethod
def sm():
print('stat', z)
A.im('self')
# -=> NameError: name 'z' is not defined
# 从class来调用im,没有对应的instance,要手动传入。
A.cm()
# -=> NameError: name 'z' is not defined
# 与im不同,这是classMethod。如果cm传入参数,会报错说传入了2个参数,因为A就是classObject。
A.sm()
# -=> NameError: name 'z' is not defined
a = A() # 实例化A
a.im()
# -=> NameError: name 'z' is not defined
a.cm()
# -=> NameError: name 'z' is not defined
# cls仍然自动传入
a.sm()
# -=> NameError: name 'z' is not defined
如果把print里的z都改为A.z,那就都能正常运行了。这几种method区别呢?从下面代码可以看出,区别只在于传参方式不同,导致方法内可访问的对象不同,self可访问到当前instance,cls可访问到当前class。然而,当且仅当 知道class的名字,和 将来 instance名字,任何method都还是可以通过名字访问到。实例和类的同名属性,在实例里重新赋值之后,就变成了实例属性,不再受类属性的值影响。
在程序运行当中,instance可以通过type(instance).__name__或者instance.__class__.__name__来获取自己的class名字。class无法获取instance名字。staticMethod也无法获取instance和class名字。只有编程阶段,作者可以知道。
所以,这3种函数的区别只在于decorator导致的传入的参数不同,限制了使用的方式。并没有本质不同。
class A():
z = 1
def im(self):
print('inst', self.z)
self.z = 3
print('inst', self.z, '\n')
@classmethod
def cm(cls):
print('cls', cls.z)
cls.z = 4
print('cls', cls.z, '\n')
@staticmethod
def sm():
print('stat', a.z)
print('stat', A.z)
a.z = 2
A.z = 6
print('stat', a.z)
print('stat', A.z, '\n')
a = A()
a.im()
a.cm()
a.sm()
a.cm()
a.im()
"""
运行结果:
inst 1
inst 3
cls 1
cls 4
stat 3
stat 4
stat 2
stat 6
cls 6
cls 4
inst 2
inst 3
"""
A.im(a)
A.cm()
A.sm()
A.cm()
A.im(a)
# 结果和上面一样
2. 类class中的内嵌函数(self的变量传递):
普通的不在class里的函数中的函数是不可以直接访问的,只能外层函数内部自用。
实例instance中的变量用self.var表示,需要访问实例 变量和函数 的函数在def的时候要显式声明self参数
def fun(self):
那函数中的函数呢?
class MyClass():
a = 1
def fun(self):
self.b = 2
def func():
print(self.b)
mc = MyClass()
print(mc.a)
# -=> 1
mc.fun()
print(mc.b)
# -=> 2
# 到这里一切正常
mc.fun.func()
# -=> AttributeError: 'function' object has no attribute 'func'
# 不能直接访问函数中的函数,不论func()括号中加不加self
# 这点和普通的函数中的函数相同
把class稍加改动,看一下fun能不能访问func,还有func在不加self时,能否读写self.a,self.b
class MyClass():
a = 1
def fun(self):
self.b = 2
def func():
print(self.a)
print(self.b)
self.a = 3
self.b = 4
self.c = self.a + self.b
print(self.a)
print(self.b)
print(self.c)
func()
mc = MyClass()
mc.fun()
print(mc.a)
print(mc.b)
print(mc.c)
"""
运行结果:
1
2
3
4
7
3
4
7
"""
也就是说,外层函数可以访问自己的内层函数,而且,self.var在整个内外层函数中通用,可以读写;相当于self.var是整个实例instance里的全局global变量。
嵌套函数,内部函数可以访问外部函数定义的变量,但无法修改,如要修改,加nonlocal关键字。
如果想要访问函数中的函数,一般只能靠外层函数返回return一个内层函数出来。
想实现一层一层".访问",其实是返回的实例,不是内嵌函数。比如下面的例子:
class MyClass():
b = 1
def fun(self):
self.b = 2
print(self.b)
class MyClass2():
a = MyClass()
mc = MyClass2()
print(mc.a.b)
mc.a.fun()
print(mc.a.b)
3. 类class属性在文件读取的时候就已经初始化了,貌似方法并不会(反正没啥可初始化的)。不会等到实例化__init__的时候。