静态方法
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
class Dog(object): def __init__(self,name): self.name = name @staticmethod #把eat变为静态方法 def eat(self): print("{} is eating {}".format(self.name,'bone')) d = Dog('wangcai') d.eat() 结果会报错 Traceback (most recent call last): File "D:/lxj/123/py3_training/atm/shopping_mall/test1.py", line 103, in <module> d.eat() TypeError: eat() missing 1 required positional argument: 'self'
程序中调用eat()方法会报错,报错信息为缺少一个位置参数。把eat变为静态方法实际上跟类没什么关系,把这个方法和类的关联截断了,其实就是一个函数,只是需要通过类调用。那我们要如何调用呢?其实很简单,就是按照函数的传参把参数传进去
class Dog(object): def __init__(self,name): self.name = name @staticmethod def eat(self): print("{} is eating {}".format(self.name,'bone')) d = Dog('wangcai') d.eat(d) 结果: wangcai is eating bone
class Dog(object): def __init__(self,name): self.name = name @staticmethod def eat(): print("{} is eating {}".format('wangcai','bone')) d = Dog('wangcai') d.eat() #实例化后再调用 结果: wangcai is eating bone -------------------------------------------------------- class Dog(object): def __init__(self,name): self.name = name @staticmethod def eat(): print("{} is eating {}".format('wangcai','bone')) Dog.eat() #实例化后再调用没什么意义。不实例化,直接调用
结果: wangcai is eating bone
类方法
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量,为什么会这样呢?继续往下看
class Dog(object): def __init__(self): self.name = 'lx' @classmethod def eat(cls): print("{} is eating {}".format(cls.name,'bone'))
d = Dog("aaaaa")
d.eat()
结果会报错: AttributeError: type object 'Dog' has no attribute 'name'
class Dog(object): name = 'bbbb' def __init__(self): # self.name = 'lx' pass @classmethod def eat(cls): print("{} is eating {}".format(cls.name,'bone'))
d = Dog("aaaaa")
d.eat()
结果: bbbb is eating bone
类方法和静态方法的区别:两者都可以通过类来调用,类方法中的cls参数就是类本身,静态方法默认没用参数,相当于函数,只是通过类来调用,需要什么参数再传进去
class Dog(object): name = 'bbbb' def __init__(self): # self.name = 'lx' pass @staticmethod def run(cls): print("{} running....".format(cls.name)) @classmethod def eat(cls): print(cls) print("{} is eating {}".format(cls.name,'bone')) Dog.run(Dog) Dog.eat() 结果: bbbb running.... <class '__main__.Dog'> bbbb is eating bone
属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
class Dog(object): #name = 'bbbb' def __init__(self,name): self.name = name @property def eat(self): print("{} is eating {}".format(self.name,'bone')) d = Dog("aaaaa") d.eat() 结果会报错: TypeError: 'NoneType' object is not callable
我们发现调用会报错, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
class Dog(object): #name = 'bbbb' def __init__(self,name): self.name = name @property def eat(self): print("{} is eating {}".format(self.name,'bone')) d = Dog("aaaaa") d.eat
既然是属性,那就可以赋值,那么如何对属性赋值呢?可以使用@setter
class Dog(object): #name = 'bbbb' def __init__(self,name): self.name = name @property def eat(self): print("{} is eating {}".format(self.name,'bone')) @eat.setter def eat(self,name): self.name = name d = Dog("aaaaa") d.eat = 'ccccc' #实际转化为d.eat('ccccc') d.eat #实际转化为d.eat() 结果: ccccc is eating bone
既然是属性那应该可以删除。如果直接使用del d.eat删除,发现会报错:AttributeError: can't delete attribute.需使用@deleter方法
class Dog(object): #name = 'bbbb' def __init__(self,name): self.name = name @property def eat(self): print("{} is eating {}".format(self.name,'bone')) @eat.setter def eat(self,name): self.name = name @eat.deleter def eat(self): del self.name print("删完了") d = Dog("aaaaa") d.eat = 'ccccc' #实际转化为d.eat('ccccc') d.eat #实际转化为d.eat() del d.eat #实际转化为d.eat() d.eat 结果: ccccc is eating bone 删完了
类的特殊成员方法
-
__doc__ 表示类的描述信息
class Dog(object): """ 描述狗这个对象 """ def __init__(self,name): self.name = name print(Dog.__doc__) 结果: 描述狗这个对象
-
__module__ 和 __class__
__module__ 表示当前操作的对象所属类在哪个模块
__class__ 表示当前操作的对象的类是什么
class Dog(object): """ 描述狗这个对象 """ def __init__(self,name): self.name = name
from test1 import Dog d = Dog('bbbb') print(d.__module__) print(d.__class__) 结果: test1 <class 'test1.Dog'>
-
__init__ 构造方法,通过类创建对象时,自动触发执行。
-
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
-
__call__ 对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Dog(object): """ 描述狗这个对象 """ def __init__(self,name): self.name = name def __call__(self, *args, **kwargs): print("__call__") d = Dog('aaaa') d() 结果:__call__
-
__dict__ 查看类或对象中的所有成员
class Role(object): school = '树人' def __init__(self,name): self.name = name self.age = 27 d = Role('lxj') print("实例化对象成员字典:",d.__dict__) print("类的成员字典:",Role.__dict__) 结果: 实例化对象成员字典: {'name': 'lxj', 'age': 27} 类的成员字典: {'__dict__': <attribute '__dict__' of 'Role' objects>, '__init__': <function Role.__init__ at 0x006B0270>, '__weakref__': <attribute '__weakref__' of 'Role' objects>, '__doc__': None, 'school': '树人', '__module__': '__main__'}
-
__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值,不影响实例的调用。
class Role(object): def __init__(self,name): self.name = name self.age = 27 def __str__(self): return "str..." d = Role('lxj') print(d) 结果: str...
-
__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
class Foo(object): def __init__(self): self.data = { } def __getitem__(self, key): print('__getitem__', key) return self.data.get(key) def __setitem__(self, key, value): print('__setitem__', key, value) self.data[key] = value def __delitem__(self, key): print('__delitem__', key) del self.data[key] obj = Foo() obj['k2'] = 'alex' # 自动触发执行 __setitem__ result = obj['k2'] #自动触发执行 __getitem__ print("result is :{}".format(result)) del obj['k2'] #自动触发执行 __delitem__ 结果: __setitem__ k2 alex __getitem__ k2 result is :alex __delitem__ k2
-
__slots__
class Student(object): pass s = Student() s.name = "Michael" #给实例绑定属性 print(s.name) 结果: Michael from types import MethodType def set_age(self,age): self.age = age class Student(object): pass s = Student() s.set_age = MethodType(set_age,s) #给实例绑定一个方法,只对该实例有用 s.set_age(27) #调用方法 print(s.age) 结果: 27 #给所有实例绑定方法可以用Student.set_age = set_age #但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。 #为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实#例能添加的属性: class Student(object): __slots__ = ('name','age') pass s = Student() s.name = 'lxj' s.age = 27 s.score = 99 结果: Traceback (most recent call last): File "D:/python_work/elective_system/test.py", line 39, in <module> s.score = 99 AttributeError: 'Student' object has no attribute 'score' #由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。 #使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
-
__repr__
class Role(object): def __init__(self, name,age): self.name = name self.age = age def __str__(self): return "({0.name},{0.age})".format(self) def __repr__(self): return 'Role({0.name},{0.age})'.format(self) d = Role('lxj',21) print("d is {!r}".format(d)) #显示repr print("d is {!s}".format(d)) #显示str 结果: d is Role(lxj,21) d is (lxj,21) #与__str的区别,__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。 #通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法: class Role(object): def __init__(self, name,age): self.name = name self.age = age def __str__(self): return "({0.name},{0.age})".format(self) __repr__ = __str__ d = Role('lxj',21) print("d is {!r}".format(d)) #显示repr print("d is {!s}".format(d)) #显示str 结果: d is (lxj,21) d is (lxj,21)
-
__getattr__
#首先来看个例子,当我们调用不存在的属性时,会报错 class Role(object): def __init__(self, name): self.name = name s = Role("lxj") print(s.name) print(s.age) 结果: lxj Traceback (most recent call last): File "D:/lxj/123/py3_training/atm/shopping_mall/test1.py", line 150, in <module> print(s.age) AttributeError: 'Role' object has no attribute 'age' #那如何避免这个错误呢?1、可以加上一个score属性外;2、Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。修改如下: class Role(object): def __init__(self, name): self.name = name def __getattr__(self, item): if item == 'age': return 23 s = Role("lxj") print(s.name) print(s.age) 结果: lxj 23 #当调用不存在的属性时,比如age,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值,也可以返回函数 #此时还有个问题,当我们调用其他不存在的属性,不会报错了,而是打印None 如:print(s.asd) -> None,我们有必要对上面的程序再优化下,当调用不存在的属性,继续报错 class Role(object): def __init__(self, name): self.name = name def __getattr__(self, item): if item == 'age': return 23 raise AttributeError("{self.__class__.__name__} object has no attribute {item}".format(self = self,item = item)) s = Role("lxj") print(s.name) print(s.age) print(s.asd) 结果: Traceback (most recent call last): lxj File "D:/lxj/123/py3_training/atm/shopping_mall/test1.py", line 157, in <module> 23 print(s.asd) File "D:/lxj/123/py3_training/atm/shopping_mall/test1.py", line 151, in __getattr__ raise AttributeError("{self.__class__.__name__} object has no attribute {item}".format(self = self,item = item)) AttributeError: Role object has no attribute asd
这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。
-
__new__ __metaclass__
class Foo(object): def __init__(self,name): self.name = name f = Foo("lxj")
上述代码中,f是通过 Foo 类实例化的对象,其实,不仅f是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建。
print type(f) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建 print type(Foo) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
类创建方式
1、普通方式
class Foo(object): def func(self): print("hello lxj")
2、特殊方式
def func(self): print("hello lxj") Foo = type('Foo',(object,),{'func':func}) #type第一个参数为类名 #type第二个参数为当前类的基类,为元组形式 #type第三个参数为类的成员,为字典形式
1 def func(self): 2 print("hello {}".format(self.name)) 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 8 Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) 9 10 11 a = Foo('lxj',27) 12 a.func()
类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__(元类),其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
class Foo(object): #__metaclass__ = MyType def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__") return object.__new__(cls) #继承父亲的__new__方法 Foo('lxj') 结果: Foo __new__ Foo __init__ #此时我们可以得出结论__new__在__init__之前运行,现在我们注释掉return object.__new__(cls) def __new__(cls, *args, **kwargs): print("Foo __new__") #return object.__new__(cls) a = Foo('lxj') print(a) 结果: Foo __new__ None #此时我们发现根本就没有实例化,我们可以得出结论new是用来创建实例的
class MyType(type): def __init__(self,what,bases=None,dict=None): print("MyType __init__") super().__init__(what,bases,dict) def __call__(self, *args, **kwargs): print("MyType __call__") obj = self.__new__(self,*args,**kwargs) self.__init__(obj,*args,**kwargs) class Foo(object): __metaclass__ = MyType def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__") return object.__new__(cls) a = Foo('lxj') #在python3上应该这么写class Foo(object,metaclass=MyType),运行结果与python2一致 MyType __init__ MyType __call__ Foo __new__ Foo __init__
关于元类的使用:https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python?answertab=votes#tab-top
更多定制类用法