您的位置:首页 > 编程语言 > Python开发

[Python/魔法方法/装饰器]

2017-12-25 11:14 435 查看

很多初学者遇到面向对象这块就会有点懵,尤其是魔法属性和装饰器,我们经常会遇到
__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'
d7b7
)
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息