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 = ''
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('')
return self.func()

@TestClass
def shuzi():
print('')

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方法和单例、定制访问函数、装饰器的更多相关文章

  1. [Python]python面向对象 __new__方法及单例设计

    __new__ 方法 使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间 __new__ 是一个 由 object 基类提供的 内置的静态方法,主 ...

  2. 类 __new__方法实现单例

    继承了单例的类,子类也是单例模式

  3. python staticmethod,classmethod方法的使用和区别以及property装饰器的作用

    class Kls(object): def __init__(self, data): self.data = data def printd(self): print(self.data) @st ...

  4. python 函数 装饰器的使用方法

    一.装饰器  首先,我们要了解到什么是开放封闭式原则? 软件一旦上线后,对修改源代码是封闭的,对功能的扩张是开放的,所以我们应该遵循开放封闭的原则. 也就是说:我们必须找到一种解决方案,能够在不修改一 ...

  5. Day 12 闭包函数,装饰器

    闭包函数 回顾: 1.函数对象:可以将定义在函数内的函数返回到全局使用.从而打破了函数层级限制 2.名称空间与作用域:作用域关系在函数定义阶段时就已经固定死了,与调用位置无关,即在任意位置调用函数都需 ...

  6. Python---12函数式编程------12.3匿名函数&装饰器&偏函数

    一.匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时,除了定义一个f( ...

  7. spring静态工厂方法得到单例bean

    import org.springframework.beans.BeansException; import org.springframework.context.ApplicationConte ...

  8. django 把函数装饰器变为方法装饰器

    暗暗啊

  9. 关于python单例的常用几种实现方法

    这两天在看自己之前写的代码,所以正好把用过的东西整理一下,单例模式,在日常的代码工作中也是经常被用到, 所以这里把之前用过的不同方式实现的单例方式整理一下 装饰器的方式 这种方式也是工作中经常用的一种 ...

随机推荐

  1. git 推送代码到远程端

    git init git add . git commit -m "first commit" git remote add origin "地址" git p ...

  2. python列表生成式、列表推导式

    运用列表生成式,可以快速生成list,可以通过一个list推导出另一个list,而代码却十分简洁. 格式 [x for x in 内容] [x for x in 内容 if 条件] 1:要把生成的元素 ...

  3. Tomcat启动报Error listenerStart错误 | "beans" 必须匹配 DOCTYPE 根 "null" | java.lang.reflect.MalformedParameterizedTypeException

    maven打包发布工程时,发布上去却报错FAIL - Deployed application at context path /ch but context failed to start 在服务器 ...

  4. 用iSee图片专家制作淘宝店标教程

    普通的淘宝店铺都会有店标.店标都显示在店铺首页的显现位置,买家在逛淘宝店的时候,一眼都会瞄到店标.因此,如果可以制作一个专属于自己店铺的店标,可以吸引买家的眼光,也更好地宣传了店铺. 下面就用iSee ...

  5. 《反脆弱》:软件业现成的鲁棒性(Robust)换了个说法变成了作者的发明,按作者的理论推导出许多可笑愚蠢的原则来

    本书作者名气比较大,写过<黑天鹅><随机漫步的傻瓜>等书,据称专门研究不确定度性.本书是他以前的书的内容的延续. 所谓的反脆弱,其实软件业有现成的名词鲁棒性(Robust)就是 ...

  6. innerHTML动态添加html代码和脚本兼容性问题处理方法

    给某个元素的innerHTML赋值,并使得值中的js代码有效(兼容多个浏览器) 症状:给某个元素的 innerHTML 设置值时,如果提供的 HTML 代码中包含js脚本,很多时候这些脚本无效,或者在 ...

  7. Google Java编程风格指南(转)

    目录 前言 源文件基础 源文件结构 格式 命名约定 编程实践 Javadoc 后记 前言 这份文档是Google Java编程风格规范的完整定义.当且仅当一个Java源文件符合此文档中的规则, 我们才 ...

  8. 动态数组第k小,Poj(1442)

    题目链接:http://poj.org/problem?id=1442 本来想复制一下,然后直接sort,结果T了. 在网上看了一下,有用两个队列做的,想了半天,没看懂什么意思.后来模拟一边,总算是懂 ...

  9. Next K Permutation

    3457: Next K Permutation 时间限制: 1 Sec  内存限制: 128 MB提交: 4  解决: 4[提交] [状态] [讨论版] [命题人:admin] 题目描述 n 个数有 ...

  10. IOError: [Errno 22] invalid mode ('rb') or filename: 'F:\netData1.mat'

    这种错误的出现是在使用built-in函数file()或者open()的时候.或者是因为文件的打开模式不对,或者是文件名有问题.前者的话只需要注意文件是否可读或者可写就可以了.后者则是与文件路径相关的 ...