很多初学者遇到面向对象这块就会有点懵,尤其是魔法属性和装饰器,我们经常会遇到__str__
双下划线开头,双下划线结尾的特殊方法,这个就是Python给我们内置的特殊方法,下面将对于常用的方法详解:
- @staticmethod:
该方法称之为静态方法
1:静态方法无需传入self参数;
2:静态方法不能访问实例变量,实例属性,类属性,独立的方法;
3:说白了就是一个普通的函数,可以用来做一些工具类的东西,独立的函数
In [7]: class Static(object):
...: def __init__(self):
...: self.name = 123
...: @staticmethod
...: def static():
...: print('静态方法')
...: try:
...: print(self.name) #报错
...: except:
...: print('无法访问实例变量')
In [8]: s = Static()
In [9]: s.name
Out[9]: 123
In [10]: s.static()
静态方法
无法访问实例变量
@classmethod:
类方法:
1:类方法传入的第一个参数是cls,代表类本身,他不能访问实例变量,实例属性,但可以访问类属性,我们知道,实例可以访问类属性,也可以修改类属性(实例属性),但是无论你怎么改,他的类属性也不会改变,改变的也就是所谓的实例属性,这时候我们可以通过类方法来进行修改
class CLASSMethod(object):
Cls = 1 #类属性
def __init__(self,name):
self.name = name
@classmethod
def SetCls(cls,value):
cls.Cls = value
if __name__ == '__main__':
c = CLASSMethod('self')
print(c.name) #实例变量
print(c.Cls) #类属性,这时也成了实例属性了,他可以访问 也可以修改,但是无论你怎么修改 类属性默认值就是1
c.Cls = 2
print(c.Cls)
print(CLASSMethod('1').Cls)
c.SetCls(4)
print(c.Cls)
print(CLASSMethod('1').Cls)
打印结果:
self
1
2
1
2
4
@property
对于这个方法,我最开始接触的时候理解的就是 你实例调用方法的时候 不需要加()了~,后来研究了一下 原来并不是那么简单,他可以让你这个方法可读可写,还可以在进行赋值的时候,进行验证
#第一个用法
1:
In [11]: class Pro(object):
...: def __init_(self):
...: pass
...: @property #使用
...: def get(self):
...: print('hello')
...:
In [12]: p = Pro()#实例化
In [13]: p.get#当我们调用方法的时候不需要加括号 我们可以认为他是一个变量,但他实际不是,我们还可以给他进行赋值,下面讲
hello
In [14]: p.get()#报错
hello
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-b1f5e8758f96> in <module>()
----> 1 p.get()
TypeError: 'NoneType' object is not callable
In [15]:
2:
class Student(object):
@property #只读 当我 实例化.score的时候他会执行这个方法,
def score(self):
return self._score
@score.setter #可读可写 当我 实例化.Score = value的时候 他会到这里去做检查
def Score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100')
self._score = value
>>> s = Student()
>>> s.Score = 60
>>> s.score OK,
60
>>> s.Score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
魔法方法
__new__
这个方法是在实例化的时候他会调用
In [1]: class init(object):
...: def __init__(self):
...: self.name = '1'
...:
...: def __new__(self):
...: print('实例化调用')
...:
In [2]: response = init()
实例化调用
__getattr__
当我访问不存在的属性时,他会拦截做一些事情
In [18]: class GETArrr(object):
...: def __init_(self):
...: pass
...: def __getattr__(self,value):
...: if value == 'age':
...: print('该值不存在')
...: else:
...: raise ValueError('value is not defiend')
...:
In [19]: g = GETArrr()
In [20]: g.name
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-20-7bc222e866f3> in <module>()
----> 1 g.name
<ipython-input-18-b5c0f87787a9> in __getattr__(self, value)
6 print('该值不存在')
7 else:
----> 8 raise ValueError('value is not defiend')
9
ValueError: value is not defiend
In [21]: g.age
该值不存在
__setattr__
同理,当我给属赋值的时候拦截
def __setattr__(self, name. value):
self.name = value
# 因为每次属性幅值都要调用 __setattr__(),所以这里的实现会导致递归
# 这里的调用实际上是 self.__setattr('name', value)。因为这个方法一直
# 在调用自己,因此递归将持续进行,直到程序崩溃
def __setattr__(self, name, value):
self.__dict__[name] = value # 使用 __dict__ 进行赋值
# 定义自定义行为
__call__
调用实例本身,这里不举例子 self()
__setitem___ && __getitem__
赋值与获取值 这里以dict 为例子
class SetAttr(object):
def __init__(self):
self.name = 'ayang'
self.values = {}
def __getitem__(self,key):
try:
print(self.values[key])
except Exception:
raise ValueError('value is not found ')
def __setitem__(self,key,value):
self.values[key] = value
s = SetAttr()
s['name'] = 10
s['name']
s['age'] = 100
s['age']
装饰器
举个例子 我现在有一个需求,我每一次执行一个函数,如果这个函数崩溃了,那么我需要给这个崩溃的错误 记录到日志文件里面,我们的思路是这样的每一次做一个try except,如果程序崩溃了,那么我就给他写入文件里面,但是这并不是一个好的事情,这样的坏处是什么? 我代码重复,重复调用文件 重复写文件,很麻烦 消耗资源,这时候装饰器 就派上用场了:
import logging
def Logger(func):
logger = logging.getLogger('nobody')
logger.setLevel(logging.INFO)
debugfile = logging.FileHandler('debug.log')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
debugfile.setFormatter(formatter)
logger.addHandler(debugfile)
def Try(*args,**kwargs):
try:
func(*args,**kwargs)
except ValueError as e:
logger.error('value')
logger.error(e)
logger.error('value')
return Try
@Logger
def student(*args,**kwargs):
for i in args:
print('name:%d' % int(i))
student(1,2,3)
结果:
name:1
name:2
name:3
当我改成一个字符串:
student(1,2,3,'e')
name:1
name:2
name:3
正常输出 错误值捕捉,我们看日志
tail -f debug.log
2017-12-25 14:36:24,239 - nobody - ERROR - value
2017-12-25 14:36:24,239 - nobody - ERROR - invalid literal for int() with base 10: 'e'
2017-12-25 14:36:24,239 - nobody - ERROR - value