首页 > 其他 > 详细

12 new方法和单例、定制访问函数、装饰器

时间:2018-05-30 23:47:17      阅读:183      评论:0      收藏:0      [点我收藏+]

new方法和单例、定制访问函数、装饰器

  • 上节课作业解答

# 通过多重继承方法,分别定义出动物,人类,和和荷兰人三种类
class Animal(object):
    def __init__(self, name):
        self.name = name
?
    def eat(self):
        print(%s正在吃东西 % self.name)
?
    def breath(self):
        print(%s正在呼吸 % self.name)
?
?
class Person(Animal):
    def __init__(self, name, money):
        super().__init__(name)
        self.money = money
?
    def speak(self):
        print(%s说他有%s人民币 % (self.name, self.money))
?
?
class Fulan(Person):
    def eat(self):
        print(弗兰人%s不仅爱吃辣,而且爱吃槟榔 % self.name)
?
    def speak(self):
        print(福兰人%s正在blablabla讲弗兰话。 % self.name)
?
?
juhao = Fulan(句号, 23)
juhao.breath()
juhao.eat()
juhao.speak()
?
?
#拼接一个Spiderman
class Spider(Animal):
    def climb(self):
        print(%s正在攀岩 % self.name)
?
    def tusi(self):
        print(%s正在吐丝 % self.name)
?
?
class Spiderman(Person, Spider):
    pass
?
?
Spiderman = Spiderman(Spiderman, 10)
Spiderman.tusi()
Spiderman.climb()
Spiderman.eat()
Spiderman.breath()
?
#说明:
1. 调用父类的两种方法:
Animal.__init__(self.name)
super().__init__(name)
2. 不能直接调用__init__,且__init__只能有一个
以上运行结果


句号正在呼吸
弗兰人句号不仅爱吃辣,而且爱吃槟榔
福兰人句号正在blablabla讲弗兰话。
Spiderman正在吐丝
Spiderman正在攀岩
Spiderman正在吃东西
Spiderman正在呼吸

 


 

一、魔术方法补充

所有的函数都是类(对象)

魔术方法示例:(__方法__)

(一) 引入
a = hahaha
b = 12
print(b + a)
?
# 等效于
print(b.__add__(a))
?
# 运行结果
# 12hahaha
# 12hahaha
(二) 魔术方法在类中的使用
  • 示例__add__

    # 添加其他属性

# 魔术方法在类中的使用
class Rectangle(object):
    def __init__(self, length, width):
        self.length = length
        self.width = width
?
    def get_area(self):
        return self.length * self.width
?
    def __add__(self, other):  
        add_length = self.length + other.length
        add_width = self.width + other.width
        return add_length, add_width
  • 示例__str__ __repr__

    str(面向使用者,提供简洁有用信息)

    repr(面向开发者,提供接近创建时的信息,让开发者可以通过复制粘贴来重建对象)

    直接在交互界面中,直接返回值和print()所使用的(str和repr)魔术方法不同

# str和repr原理
# 例 1
    def __str__(self):
        return length is %s, width is %s % (self.length, self.width)
    
    def __repr__(self):
        return 长是%s,宽是%s% (self.length, self.width)
?
    def __call__(self, *args, **kwargs):
        print(我正在被调用)
        
rec1 = Rectangle(10, 20)
rec2 = Rectangle(30, 40)
rec1()
print(rec1 + rec2)
print(str(rec1))   # (如果不写rec1会返回函数体<……>)
print(repr(rec1))  # (如果不写rec1会返回函数体<……>)
?
# 运行结果
我正在被调用
(40, 60)
length is 10, width is 20
长是10,宽是20
?
# 注: 直接在交互界面中,直接返回值和print()使用的(str和repr)魔术方法不同
# 例 2
a = 1,2,3
a
1,2,3
print(a)
1,2,3
?
# 说明:
函数可以直接调用,但是类必须要使用call魔术方法才可以直接调用
(三) 简单魔术方法(了解)
__class__查看类名
__base__ 查看继承的父类
__mro__ 追根溯源到object,super是基于mro实现的
__bases__ 查看继承的全部父类
__dict__ 查看全部属性,返回属性和属性值键值对形式
__doc__ 查看对象文档,即类中的注释(用引号注释的部分)(注释不能被继承)
__dir__ 查看全部属性和方法(等效于dir)

二、new方法和单例

在初始化函数init之前执行,创建实例

# __new__
a = Rectangle.__new__()
Rectangle.__init__(a)  
?
?
# 单例模式(节省内存)
class Esrth(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,instance):
            cls.instance = super().__new__(cls)
        return cls.instance
?
    def __init__(self):
        self.name = 单例
?
a = Esrth()
print(id(a))
b = Esrth()
print(id(b))  # 把e覆盖了
?
#运行结果
3072614988
3072614988
?
# 说明:
1. 在以上例子中可以看见两个实例的id其实是相同的,意味着这两个实例其实引用的是同一个实例,(只占一个内存)是一个实例的不同名字
2. 其中self代表实例本身,cls代表类本身hasattr判断类中有没有(‘‘)参数
3. 如果没有就调用object中new方法

(一)__new__方法class Hero(object):
?
    def __init__(self):
        print(这是init方法)
?
    def __new__(cls):
        print(这个cls是:%s % cls)
        print(这是new方法)
        return object.__new__(cls)
?
?
garen = Hero()
?
运行结果:
这个cls是:<class __main__.Hero>
这是new方法
这是init方法
?
说明:
四个点理解__new__方法
1、__new__方法是在 类 创建实例 的时候自动调用的。
2、实例是通过类里面的__new__方法是在 类 创建出来的。
3、先调用__new__方法创建实例,再调用 __init__方法初始化实例4、__new__方法,,后面括号里的cls代表的是类本身
在上面的例子中,我们可以看到创建实例的时候,自动调用了__new__,方法和__init__方法,并且是先调用的__new__再调用的__init__方法,打印 cls 的时候显示的这个Hero类
(二)单例模式:
class Hero(object):
    __instance = None   # 定义一个私有属性__instance等于None
?
    def __new__(cls):
        if cls.__instance == None:      # 然后我们判断它是不是等于None,如果等于None,我们调用父类的方法创建一个实例对象,并把返回的对象赋值给 __instance,并且返回__instance
            cls.__instance = object.__new__(cls)
            return cls.__instance
        else:       #  如果__instance不等于None,那就说明已经创建了对象我们直接把__instance返回去。
            return cls.__instance
?
?
a = Hero()
b = Hero()
print(id(a))
print(id(b))
?
打印结果:
3072101708
3072101708
?
# 说明:
单例模式实现的原理:通过重写__new__方法,让__new__只能进行一次实例创建。
在上面的例子中,我们可以看到两个实例的ID是相同的,意味着第二次创建的时候,并没有真正的去创建,而是引用的第一次创的实例,同一个实例的不同名字

三、定制访问函数

(一) 常见方法
作用方法返回
hasattr(re,‘length‘) 返回bool值
  getattr(re,‘length‘) 返回属性值
  b.__getattribute__(‘length‘) 返回全部属性值
setattr(b,‘length‘,6)  
  b.__setattr__(‘length‘,5)  
b.aaa = 1  
  setattr(b,‘leg‘,2)  
  b.__setattr__(‘leg‘,3)  
delattr(b,‘leg‘)  
  b.__delattr__(‘leg‘)  
  del b  

# 实例:
class Rectangle(object):
    def __init__(self,length,width):
        self.length = length
        self.width = width
?
    def area(self):
        return self.length * self.width
?
a = Rectangle(10,20)
print(a.area())
#
print(hasattr(a,length))      # 返回bool值
print(getattr(a,length))      # 返回属性值
print(a.__getattribute__(width))      # 返回属性值
#
setattr(a,length,5)
a.__setattr__(width,5)
print(a.length)
print(a.width)
#
a.aaa = 1
setattr(a,bbb,2)
a.__setattr__(ccc,3)
print(a.aaa)
print(a.bbb)
print(a.ccc)
#
delattr(a,ccc)
a.__delattr__(bbb)
del a
# print(a.ccc)
# print(a.bbb)
# print(a.length)
?
打印结果:
200
True
10
20
5
5
1
2
3
注:print(hasattr(实例rec1,属性length))等效于print(rec1.__hasattr__(name))
(二) 举例
# 定制属性访问
# 例 __getattr__
?
re = Rectangle(3,4)
?
def __getattr__(self,item):
    print(no attribute)
# 当属性不存在时,若定义了此方法则调用此方法,若存在则返回原值
(三) 了解__getattribute__
b.__getattribute__(length)
# 正常调用返回属性值,属性值不存在,调用__getattr__未定义时会报错

四、装饰器

(一) 引入
def eat():
    return 小明在吃东西
?
def boom():
    return eat() + 并且爆炸了
?
print(boom())
?
#等效于
def boom(func):
    return func() + 并且爆炸了
?
xiaoming = boom(eat)
print(xiaoming)
?
# 运行结果
小明在吃东西并且爆炸了
小明在吃东西并且爆炸了
(二) 改善

可以看到输出时方式不一样,可以修改为以下操作

# 例 1
?
def boom(func):
    def new_func():
        return func() + 并且爆炸了
    return new_func
?
xiaoming = boom(eat)
print(xiaoming())
?
#运行结果
小明在吃东西并且爆炸了

# 例 2
def eat2(name):
    return 小明和%s在吃东西 % name
?
def boom2(func2):
    def new_func2(name):
        return func2(name) + 并且爆炸了
    return new_func2
?
eat2 = boom2(eat2)
print(eat2(小红))
?
#运行结果
小明和小红在吃东西并且爆炸了
(三) 装饰器
例1
def boom3(func3):
    def new_func3(name):
        return func3(name) + 并且爆炸了
    return new_func3
?
?
@boom3
def eat3(name):
    return 小明和%s在吃东西 % name
?
print(eat3(小红))
?
# 运行结果
小明和小红在吃东西并且爆炸了

 

例2
def f1(fu):
    def func2():
        print(这是装饰器功能代码)
        fu()
?
    return func2
?
?
@f1
def func():
    print(这是基础功能代码)
?
?
func = f1(func)  # 等同@f1
?
func()
?
打印结果:
这是装饰器功能代码
这是装饰器功能代码
这是基础功能代码
(四) 其他装饰器
class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width
?
    def area(self):
        areas = self.length * self.width
        return areas
?
# 像访问属性一样
    @property
    def areal(self):
        return self.width *self.length
?
?
#静态方法
    @staticmethod
    def func(): #如果写了self在调用时会报错
        print(staticmethod func)
?
?
?
#类方法
    @classmethod
    def show(cls): #cls代表类本身 如果加上self在调用时要把实例传入
        print(cls)
        print(show fun)
        
        
?
        
# 用类做装饰器
class TestClass(object):
    def __init__(self, func):
        self.func = func
?
    def __call__(self, *args, **kwargs):
        print(1234)
        return self.func()
?
@TestClass
def shuzi():
    print(5678)
?
shuzi()
?
?
# 运行结果
1234
5678
(五) 装饰器参考
?
from datetime import datetime
?
?
def run_time(func):
    def new_func(*args,**kwargs):
        start_time = datetime.now()
        print(程序开始时间:%s % start_time)
        func(*args, **kwargs)
        end_time = datetime.now()
        print(程序结束时间:%s % end_time)
        print(程序总共执行时间:%s % (end_time - start_time))
?
    return new_func()
?
print(datetime.now())
?
# 运行结果
2018-04-13 17:10:39.332348

 

12 new方法和单例、定制访问函数、装饰器

原文:https://www.cnblogs.com/zcmq/p/9114111.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!