10.new方法和单列模式、定制属性访问、描述符、装饰器

  new方法和单列模式  

 一、new方法

1 . 四个点理解__new__方法

1、__new__方法是在 类 创建实例 的时候 自动调用的。

2、实例是通过类里面的__new__方法是在 类 创建出来的

3、先调用__new__方法创建实例,再调用 __init__方法初始化实例。

4、__new__方法,,后面括号里的cls代表 的是类本身

#一般不会重写__new__方法,常用在单例模式
class Hero(object):

    def __init__(self,name):
        self.name = name

        print('%s调用了我进行初始化'%self.name)

    def __new__(cls, *args, **kwargs):
        print(args)       #*args  传入位置参数   #**kwargs  传入关键字参数     #用于间接传参
        print('new方法被调用了,要创建一个对象')
        return object.__new__(cls)   #重写__new__方法不要忘记       #cls 代表类本身

moran = Hero('墨染')
print(id(moran) )
ni = Hero('AA')
print(id(ni))
# print(moran.name)

('墨染',)
new方法被调用了,要创建一个对象
墨染调用了我进行初始化
3072197388
('AA',)
new方法被调用了,要创建一个对象
AA调用了我进行初始化
3072197420

我们可以看到创建实例的时候,自动调用了__new__,方法和__init__方法,并且 是先调用的__new__再调用的__init__方法,打印 cls 的时候显示的这个Hero类

二、单例模式

单例模式实现的原理:通过重写__new__方法,让__new__只能进行一次实例创建。

class Hero:
    __instance = None      #定义一个私有 类属性 并赋值为None
    def __new__(cls, *args, **kwargs):          #创建对象
        if cls.__instance == None:              #然后我们判断它是不是等于None,如果等于None,我们调用父类的方法创建一个实例对象,并把返回的对象赋值给 __instance,并且返回__instance

            cls.__instance = object.__new__(cls)
            return cls.__instance
        else:                                  #如果__instance不等于None,那就说明已经创建了对象  我们直接把__instance返回出去。
            return cls.__instance
moran = Hero()
print(id(moran))
yanzhi = Hero()
print(id(yanzhi))


3072236972
3072236972

两个实例的ID是相同的,意味着第二 次创建的时候,并没有真正的去创建,而是引用的第一次创的实例, 同一个实例的不同名字

       定制属性访问      

class Hero:
    attr1 = 1001
    attr2 = 1002
    def __getattribute__(self, item):        
print('------bute------')                                 
    def __getattr__(self, item):                          
        print('get调用的时候触发了我')                       
    def __setattr__(self, key, value):                        
        print('set调用的时候触发了我')                       
yanzhi = Hero()                                           
yanzhi.attr1
#  属性查找
print(hasattr(yanzhi,'attr2')) #属性存在返回Ture 不存在返回False 判断是否存在属性,果属性存在则进行下一步操作
print(getattr(yanzhi,'attr1'))    #属性存在返回属性值 不存在报错   得到属性值
#  增加属性
yanzhi.name = '炎志'
setattr(yanzhi,'age',18)
print(yanzhi.name)
print(yanzhi.age)
#  修改属性
setattr(yanzhi,'age',28)           #设置属性值
print(yanzhi.age)
#  删除属性
# delattr(yanzhi,'attr1')
# print(yanzhi.attr1)

------bute------
------bute------
True
------bute------
None
set调用的时候触发了我
set调用的时候触发了我
------bute------
None
------bute------
None
set调用的时候触发了我
------bute------
None

            描述符             

描述符协议:python描述符是一个“绑定行 为”的对象属性,在描述符协议中,它可以 通过方法重写属性的访问。这些方法有 __get__(), __set__(), 和__delete__()。

如果这些方法中的任何一个被定义在一个对 象中,这个对象就是一个描述符

魔术方法的作用其实是让开发人员能够更加灵活的控制类的表现形式

class Hero:
    def __get__(self, instance, owner):
        print("--------get----------")
    def __set__(self, instance, value):
        print("---------set---------")
    def __delete__(self, instance):
        print("-------delete--------")
class MyClass:
    m = Hero()
    attr = 111
c = MyClass()
c.m

c.m = 1111
del c.m

--------get----------
---------set---------
-------delete--------

            装饰器             

 一、装饰器

能够实现在不修改原来的函数的基础上添加功能,修饰函数。

#闭包复习,装饰器引入
def func(a):
    def fun1():
        print("---------func------------")
        print(a)
        a()
    return fun1
@func
def fun():
    print("我是-----fun------")
# # func(fun)()
# result = func(fun)
# result()
fun()

---------func------------
<function fun at 0xb7249a4c>
我是-----fun------
#简单装饰器
def f1(func):
    def f2():
        print("装饰的功能")
        func()
    return f2
@f1
def func():
    print("基础功能代码")
func()


装饰的功能
基础功能代码
#通过装饰器实现功能
def f1(func):
    def f2(a,b):
        print("a加b的结果是:%s" % (a + b))
        print("a减b的结果是:%s" % (a - b))
        print("a除b的结果是:%s" % (a / b))
        func(a,b)
    return f2
@f1
def func(a,b):
    print("a乘b的结果是:%s"%(a*b))
func(11,2)


a加b的结果是:13
a减b的结果是:9
a除b的结果是:5.5
a乘b的结果是:22

二、内置装饰器(经常使用)

 python的类里面中还有三个内置的装饰器:

class MyClass(object):
    attr = ''
    @property            #让方法像属性一样被访问  将类里面的一个方法变成属性
    def func1(self):
        print('--------这是func1---------')
    @classmethod        #
    def func2(cls):    #cls 标识类方法   self访问不到
        print('--------这是func2---------')
    @staticmethod
    def func3():         #类的静态方法
        print('---------这是fun3---------')
    def func4(self):
        print('----------这是fun4---------')
#类方法可以通过实例和类去访问yan.func2  实例方法只能通过实例去访问
yan = MyClass()
print(yan.attr)
yan.func1
yan.func2()
MyClass.func2()
yan.func3()
MyClass.func3()
yan.func4()


人
--------这是func1---------
--------这是func2---------
--------这是func2---------
---------这是fun3---------
---------这是fun3---------
----------这是fun4---------

三、类装饰器

类也可以做装饰器,但是需要定义 __call__ 方法

# #类装饰器
class Text(object):

    def __init__(self,fun):
        self.fun = fun

    def __call__(self, *args, **kwargs):
        print('装饰器的功能代码')
        self.fun()

@Text
def func():
    print('原来的功能代码')

# func = Text(func)
func()

装饰器的功能代码
原来的功能代码

四、装饰器参考

#查看函数运行时间:
>>> import time
>>> def run_time(func):
...     def new_fun(*args,**kwargs):
...             t0 = time.time()
...             print('star time: %s'%(time.strftime('%x',time.localtime())) )
...             back = func(*args,**kwargs)
...             print('end time: %s'%(time.strftime('%x',time.localtime())) )
...             print('run time: %s'%(time.time() - t0))
...             return back
...     return back
原文地址:https://www.cnblogs.com/lyh-520/p/9296401.html