new,定制属性访问,装饰器

__new__方法

  • 在类对象构造时调用的方法,也是python解释器调用
  • 必须有参数cls
  • 必须有返回值,返回当前类的对象
  • 例1
class User(object):

	def __init__(self,username,password):
		self.username = username
		self.password = password
		print('对象构建好,由解释器自动回调的方法,对象初始化,成员方法,代表调用的当前对象本身')

	def __new__(cls,username,password):	#实际是静态方法,构建对象的方法,当对象构建时,由解释器自动回调的方法,该方法必须返回当前类的对象
		print('User类的对象开始构建')


u = User('jingyi','520')	#User类的对象开始构建
print(u)	#None	因为__new__没有返回,实际没构建对象
  • 例2
class User(object):

	def __init__(self,username,password):
		self.username = username
		self.password = password
		#不能用return,要用就用print
		print('对象构建好,由解释器自动回调的方法,对象初始化,成员方法,代表调用的当前对象本身')

#先执行new方法,在执行init方法
	def __new__(cls,username,password):	#当对象构建时,由解释器自动回调的方法,该方法必须返回当前类的对象
		print('User类的对象开始构建')
		return object.__new__(cls)		#返回cls所代表类的方法		#cls表示当前类

	def __str__(self):		#打印类return的对象时起作用,必须要有return
		return '用户名:%s,密码:%s' % (self.username,self.password)


u = User('jingyi','520')	#User类的对象开始构建
							# 对象构建好,由解释器自动回调的方法,对象初始化,成员方法,代表调用的当前对象本身
print(u)		# <__main__.User object at 0x7f32dea15d30>

new方法实际是静态方法,构建对象的方法
在这里插入图片描述

单例模式

  • 1
class Earth:
    def __new__(cls):
        if not hasattr(cls,"instance"):	#hasattr看一下这个对象里面有没有instance
            # 如果有,返回true,如果没有,返回false
            cls.instance = super().__new__(cls)
        return cls.instance
    def __init__(self):
        self.name = 'earth'
e = Earth()
print(e,id(e))
a = Earth()	
print(a,id(a))
#<__main__.Earth object at 0x7f5cca410cc0> 140036506979520
  <__main__.Earth object at 0x7f5cca410cc0> 140036506979520
  • 在上面例子中,两个实例的id是相同的,意味着这两个其实引用的是同一个实例,是一个实例的不同名字
  • 单例模式:防止内存浪费,一个类只实例一次e和a是一样的,是同一个实例
  • 2
class User(object):

	__instance = None	#私有的类属性
	def __init__(self,name):
		self.name = name

	@classmethod
	def get_instance(cls,name):

		if not cls.__instance:	#如果 __instance 为 NONE,执行下行代码
			cls.__instance = User(name)

		return cls.__instance

u1 = User.get_instance('xiaoge')	#此时cls.__instance不存在,判断后执行cls.__instance = User('xiaoge')
u2 = User.get_instance('liangzai')	#此时时cls.__instance已经存在,为User('xiaoge'),此时直接return cls.__instance
u3 = User.get_instance('handsome')	#此时时cls.__instance已经存在,为User('xiaoge'),此时直接return cls.__instance
print(u1 == u2)		#True

print('u1对象的内存地址:%s,u2对象的内存地址:%s' % (id(u1),id(u2)))		
#u1对象的内存地址:140022761147472,u2对象的内存地址:140022761147472
print(u1.name,u2.name)		#xiaoge  xiaoge
  • 3
class User(object):

	__instance = None	#私有的类属性
	def __init__(self,name):
		self.name = name


	def __new__(cls,name):

		if not cls.__instance:	#如果 __instance 为 NONE
			cls.__instance = object.__new__(cls)

		return cls.__instance

u1 = User('xiaoge')	#此时cls.__instance为None,判断后执行cls.__instance = User('xiaoge')
u2 = User('liangzai')	#此时时cls.__instance已经存在,为User('xiaoge'),此时直接return cls.__instance
print(u1 == u2)		#True
print(u1.name,u2.name)	#liangzai laingzai 	#因为先执行__new__,再执行__init__,所以name属性和后实例化的对象的name一致

print('u1对象的内存地址:%s,u2对象的内存地址:%s' % (id(u1),id(u2)))		#u1对象的内存地址:140713723821360,u2对象的内存地址:140713723821360

工厂模式

  • 工厂模式是最常用的实例化对象模式
  • 用工厂方法代替new操作,对染可能多做一些工作,但会给系统带来更大的可拓展性和可维护性
  • 原例
class Person(object):

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

	def work(self):
		print(self.name + '开始工作了')
		#person完成work,需要使用一把斧头
		#在原始社会,人需要石斧
		# axe = StoneAxe('花岗岩斧头')	#不用石斧,要用钢斧
		axe = SteelAxe('钢铁斧头')
		axe.cut_tree()

class Axe(object):	#斧子的父类

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

	def cut_tree(self):
		print('%s开始砍树' % self.name)

class StoneAxe(Axe):	#石斧

	def cut_tree(self):
		print('用石斧砍树')

class SteelAxe(Axe):

	def cut_tree(self):
		print('用钢斧砍树')
	
# p = Person('原始人')	#改现代人用钢斧
p = Person('现代人')	#人和斧头存在较强的依赖,不利于维护
p.work()

简单工厂

  • 两种方法
    • 静态的工厂类
    • 用全局函数改写工厂类,不是面向对象编程,用的不多
  • 解决两个类或者对象存在较强依赖关系,优化
class Person(object):
	"""
	人需要用斧头砍树,通过第三方(工厂)获得想要的斧头去砍树
	"""

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

	def work(self,axe_type):
		print(self.name + '开始工作了')
		#person完成work,需要使用一把斧头
		axe = Factory.create_axe(axe_type)
		axe.cut_tree()

class Axe(object):	#斧子的父类

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

	def cut_tree(self):
		print('%s开始砍树' % self.name)

class StoneAxe(Axe):	#石斧

	def cut_tree(self):
		print('用石斧砍树')

class SteelAxe(Axe):

	def cut_tree(self):
		print('用钢斧砍树')

class Factory(object):	#简单工厂类,第三方

	@staticmethod	#静态工厂类
	def create_axe(type):	#根据用户指定的类型生产斧头

		if type == 'stone':
			return StoneAxe('花岗岩斧头')

		elif type == 'steel':
			return SteelAxe('钢铁斧头')

		else:
			print('传入斧头类型不对')

p = Person('原始人')	#人和斧头存在较强的依赖,不利于维护
p.work('stone')

工厂方法模式

  • 工厂方法模式去掉了简单工厂模式中工厂方法的静态方法,使得它可以被子类继承,就是工厂类被具体工厂继承,这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担
  • 抽象的工厂类提供了一个创建对象的方法,也叫做工厂方法 (用于多产品)
  • 抽象工厂角色(Factory):这是工厂方法模式的核心,他与应用程序无关,是具体工厂角色必须实现的接口或者必须继承的父类
  • 具体工厂角色(StoneAxeFactory,SteelAxeFactory):它含有和具体业务逻辑有关的代码,由应用程序调用以创建对应的具体产品的对象
  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口,抽象产品一般为父类
  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例,由一个具体类实现
class Person(object):
	"""
	人需要用斧头砍树,通过第三方(工厂)获得想要的斧头去砍树
	"""

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

	def work(self):
		print(self.name + '开始工作了')
		#person完成work,需要使用一把斧头
		axe = SteelAxeFactory().create_axe()
		axe.cut_tree()

class Axe(object):	#斧子的父类

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

	def cut_tree(self):
		print('%s开始砍树' % self.name)

class StoneAxe(Axe):	#石斧

	def cut_tree(self):
		print('用石斧砍树')

class SteelAxe(Axe):

	def cut_tree(self):
		print('用钢斧砍树')

class Factory(object):	#工厂方法

	def create_axe(type):	#根据用户指定的类型生产斧头
		pass


class StoneAxeFactory(Factory):

	def create_axe(self):
		return StoneAxe('花岗岩斧头')


class SteelAxeFactory(Factory):

	def create_axe(self):
		return SteelAxe('钢铁斧头')


p = Person('wenwen')
p.work()

定制属性访问

hasattr(object, name)

  • 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False
  • 需要注意的是name要用括号括起来

getattr(object, name[,default])

  • 获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选
  • 需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,可以在后面添加一对括号

setattr(object, name, values)

  • 给对象的属性赋值,若属性不存在,先创建再赋值

delattr删(object,name)

案例:

class Earth:
   color = "red"
   def __init__(self,length,width):
       self.length = length
       self.width = width
   def func(self):
       print("哈哈哈")
   def area(self):
       areas = self.length * self.width
       return areas
r = Earth(10,20)
a = r.area()
print(hasattr(r,"name"))	#false
print(hasattr(r,"length"))	#true
print(hasattr(r,"area"))		#true
print(hasattr(Earth,"area"))		#true
print(getattr(r,"color"))		#red
print(getattr(r,"length"))	#10
getattr(r,"func")()		#哈哈哈
print(hasattr(r,"name"))	#false
setattr(r,"name","Rectangle")	#有则改,无则增
print(hasattr(r,"name"))	#true
  • 在类里面实例化另一个类,对这个实例做访问时,需要定义__get__() ,__set__(), __delete__()方法
  • 描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个
    • __get__():调用一个属性时,触发
    • __set__():为一个属性赋值时,触发
    • __delete__():采用del删除属性时,触发
  • 描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
class MyAttribute:
    def __get__(self, instance, owner):
        print("get")
    def __set__(self, instance, value):
        print("set")
    def __delete__(self, instance):
        print("del")
class MyClass:
    m = MyAttribute()
    def __del__(self):	#创建对象就被调用
        print("instance delete")
c = MyClass()		 #instance delete
c.m		#get
c.m = 1		# set
del c.m	#del		删除后,所占内存被回收 
  • __del__:对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)
  • 不管是手动调用del还是由python自动回收都会触发__del__方法执行
class MyClass:

	def __init__(self):
		print('对象初始化')

	def __del__(self):
		print('haha')
	# def __delete__(self):
	# 	print('对象即将被销毁')
	
#只创建m1对象,当程序结束,python回收所占内存,所以也会调用__del__方法
m1 = MyClass()		#对象初始化
					 haha
------------------------------------------------------------------------------------------
m1 = MyClass()		#对象初始化	haha		#创建对象,相当于m1和MyClass()建立了连接,m1指向MyClass()的内存地址
print(m1)			#<__main__.MyClass object at 0x7f59ee803c88>
m2 = m1			#将m1赋值给m2,相当于m2也指向MyClass()的内存地址
print(m2)			#<__main__.MyClass object at 0x7f59ee803c88>
del m1			#删除m1和MyClass()的连接,m2和MyClass()的连接还存在,所以MyClass()仍占据原来的内存地址
print(m2)			#<__main__.MyClass object at 0x7f59ee803c88>
print('----------')
del m2			#haha		#删除m2,删除了m2和MyClass()的连接,由于没有连接,销毁MyClass()所占的内存,内存地址没了,才调用__del__方法
print('**********')

#对象初始化
 <__main__.MyClass object at 0x7fe3640b0cc0>
 <__main__.MyClass object at 0x7fe3640b0cc0>
 <__main__.MyClass object at 0x7fe3640b0cc0>
 ----------
 haha
 **********

装饰器

  • 装饰器其实就是一个闭包,把一个函数当做参数然后返回给一个替代版函数
  • 装饰器有两个特性
    • 一是可以把被装饰的函数替换成其他函数
    • 二是可以在加载模块时候立即执行
  • 装饰器功能
    • 引入日志
    • 函数执行时间统计
    • 执行函数前预备处理
    • 执行函数后清理功能
    • 权限校验等场景
    • 缓存
  • 闭包:
    • 内部函数对外部函数作用域里变量的引用,内部函数为闭包
def f1(func):
    def f2(y):
        print("f2")
        return func(y) + 1
    return f2
def gun(m):		
    print("run gunning")
    # print(m * m)
    return m * m
fun = f1(gun)   	#把函数gun当做参数传入f1函数,再通过return传入f2函数
print(fun(10))		#f2
			   	     run gunning
				     101
  • 装饰器:装饰器的目的是不改变函数里面的代码给函数增加功能
def f1(func):
    def f2(y):
        print("f2")
        return func(y) + 1
    return f2
@f1 	#装饰器/语法糖  把装饰器下面的函数名当做参数传入f1函数
def gun(m):
    print("run gunning")
    return m * m
print(gun(10))		#f2
				     run gunning
					 101

无参数装饰器

def make_bold(func):

	def wrapped():
		return '<b>' + func() + '</b>'

	return wrapped

def make_italic(func):

	def wrapped():
		return '<i>' + func() + '</i>'

	return wrapped

@make_italic
@make_bold
def test1():
	return 'hello world1'

print(test1())
#<i><b>hello world1</b></i>
  • 一个函数可以加多个装饰器,使用顺序为从内到外,先使用离自己近的,在使用离自己远的

有参数装饰器

from time import ctime, sleep

def timefunc(func):

#因为 foo 函数有参数,所以这个内置函数也要有和 foo 函数一样的参数,才能被成功使用
#这种装饰器只能用在有两个参数的函数中
	def wrappedfunc(a,b):	
		print('%s called at %s' % (func.__name__, ctime()))
		print(a,b)
		func(a,b)

	return wrappedfunc

@timefunc
def foo(a,b):
	print(a+b)

foo(3,5)
sleep(2)
foo(2,4)
#foo called at Wed May 22 16:41:23 2019
 3 5
 8
 foo called at Wed May 22 16:41:25 2019
 2 4
 6

不定长参数装饰器

  • 通用装饰器
    • 参数写成不定长
    • 要有返回值,返回的是要用装饰器的函数的调用
from time import ctime, sleep

def timefunc(func):

	def wrappedfunc(*args, **kwargs):	#因为foo函数有参数,所以这个内置函数也要有和foo函数一样的参数,才能被成功使用
		print('%s called at %s' % (func.__name__, ctime()))
		print(*args, **kwargs)
		func(*args, **kwargs)
	return wrappedfunc

@timefunc
def foo(a,b):
	print(a+b)

foo(3,5)
sleep(2)
foo(2,4)
#foo called at Wed May 22 16:41:23 2019
 3 5
 8
 foo called at Wed May 22 16:41:25 2019
 2 4
 6

巩固基本功

  • 偶然发现个问题,多次尝试,对return有了新的认识
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

内置装饰器

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 area(self):
        return self.width * self.length
    @staticmethod   #静态方法
    def func():     #self在调用的时候会报错
        print("staticmenthod func")
    @classmethod    #类方法
    def show(cls):  
        print(cls)
        print("show fun")

动态语言

  • 动态语言:在运行过程中可以修改代码,如PHP,Python,JavaScript,ruby等
  • 静态语言:编译时已经确定好代码,运行过程中不能修改,如c,c++等
  • 在运行中可以为对象添加属性和方法

  • ipython3中
In [1]: class Person(object): 
   ...:     def __init__(self,name,age): 
   ...:         self.name = name 
   ...:         self.age = age 
   ...:             
   #添加类属性                                                                                                                   
In [2]: Person.addr = '肇东'                                                                                                           
In [3]: p = Person('xiaoge',15)                                                                                                        
In [4]: p.addr                                                                                                                         
Out[4]: '肇东'
In [5]: p2 = Person('jingyi',14)                                                                                                       
In [6]: p2.addr                                                                                                                        
Out[6]: '肇东'
#添加实例属性
In [27]: p.sex = 'man' 
In [28]: dir(p)                                                                                                                        
Out[28]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'addr',
 'age',
 'name',
 'sex',
 'show_info']
In [7]: def show_info(self): 
   ...:     print(self.name) 
   ...:     print(self.age) 
   ...:                                                                                                                                
In [9]: p.show_info = show_info                                                                                                        
In [10]: show_info                                                                                                                     
Out[10]: <function __main__.show_info(self)>
In [13]: p.show_info()                                                                                                                 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-7a2c006f6f60> in <module>
----> 1 p.show_info()
TypeError: show_info() missing 1 required positional argument: 'self'
#添加实例方法
In [14]: import types     #出现上述问题导入types        
# types.MethodType传入两个参数,第一个参数show_info是要加的方法名,第二个参数p是实例化的对象名 ,这个过程实际就是把p做为self,往里面传参                                                                                                   
In [15]: p.show_info = types.MethodType(show_info,p)             	                                                                      
In [16]: p.show_info                                                                                                                   
Out[16]: <bound method show_info of <__main__.Person object at 0x7f63f8e0f5c0>>
In [17]: p.show_info()                                                                                                                 
xiaoge
15
In [25]: a = types.MethodType(show_info,p2)                                                                                            
In [26]: a()                                                                                                                           
jingyi
14
#添加类方法
In [29]: @classmethod 
    ...: def fun1(cls): 
    ...:     print('classMethod') 
    ...:                                                                                                                               
In [30]: Person.fun1 = fun1                                                                                                            
In [31]: p.fun1()                                                                                                                      
classMethod
In [32]: p2.fun1()                                                                                                                     
classMethod
#添加静态方法
In [33]: @staticmethod 
    ...: def fun2(a,b): 
    ...:     return a + b 
    ...:                                                                                                                               
In [34]: Person.fun2 = fun2                                                                                                            
In [35]: print(p.fun2(2,3))                                                                                                            
5
In [36]: print(p2.fun2(1,2))                                                                                                           
3
#限制修改对象的属性,设定类时不想让对象随便添加属性,就在定义类的下面__slots__ = ('限制对象可以添加的属性'),其他的属性就无法添加,防止别人乱添加
In [37]: class Student(object): 
    ...:     __slots__ = ('name','age') 
    ...:                                                                                                                               
In [38]: stu = Student()                                                                                                               
In [39]: stu.name = 'haha'                                                                                                             
In [40]: stu.name                                                                                                                      
Out[40]: 'haha'
In [41]: stu.age = 20                                                                                                                  
In [42]: stu.age                                                                                                                       
Out[42]: 20
In [43]: stu.sex = 'boy'                                                                                                               
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-43-df04242a9dfd> in <module>
----> 1 stu.sex = 'boy'
AttributeError: 'Student' object has no attribute 'sex'

类装饰器

  • 装饰器函数其实是一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象
  • 一般callable对象都是函数,但也有例外,只要某个对象重写了__call__()方法,那么这个对象就是callable的
  • 类当函数用
class Test(object):

	def __call__(self):
		print('call')

t = Test()
t()		#call
  • 类当装饰器
class Test_Class:
    def __init__(self,func):		#func_test传入func作为参数
        self.func = func
    def __call__(self):
        print("类")
        return self.func
@Test_Class	#用类名做语法糖/装饰器,生成一个Test的对象,会调用__init__方法,把装饰的函数作为参数传入
def func_test():
    print("这是个测试函数")
func_test()	#调用Test一个对象的__call__方法
print(func_test())
#类
 类
 <function func_test at 0x7f7c72a07e18>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值