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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yyy72999/article/details/78890615

很多初学者遇到面向对象这块就会有点懵,尤其是魔法属性和装饰器,我们经常会遇到__str__双下划线开头,双下划线结尾的特殊方法,这个就是Python给我们内置的特殊方法,下面将对于常用的方法详解:

  1. @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

猜你喜欢

转载自blog.csdn.net/yyy72999/article/details/78890615
今日推荐