python基础-面向对象(装饰器)
属性:
@property
@method_name.setter
@method_name.deleter
三个标签都是放在方法的上面来使用,且方法名要和后续使用的
变量名字相一致。
好处:
1 防止别人乱改变量内容
2 在操作变量的时候,做一些附加操作,比如:写日志、写数据库
做参数的相关计算。
4 私有变量和私有方法:
变量和方法前面有2个下划线。
私有的仅限类内部使用,不能被类外部调用(不太严格)。
私有变量和私有方法可以被继承么?不行
5 继承:
父类、子类、子类继承父类
构造方法:
1 子类没有构造方法,调用父类的构造方法,如果父类的构造方法有
参数的话,那么实例化的时候也需要传递对应个数的参数。
2 如果子类有构造方法,父类的构造方法此时不会被调用。
父类构造方法有参数,那么你调用未初始化的父类实例变量会出错
推荐子类有构造方法的时候,显式调用父类的构造方法
多重继承:
简单可以继承多个父类的方法和变量
1 子类没有构造方法:调用第一个父类的构造方法,那么实例化的时候也需要传递对应个数的参数。
2 子类有构造方法:建议:所有的父类都实例化
方法重写:
在子类中重新定义父类中的同名方法。
简单来说:改造父类中不适合子类的部分。
- 新式类和经典类啥区别:
新式类继承的时候需要使用(object)
@method_name.setter
@method_name.deletter
支持新式类,不支持经典类
@property 支持新式类和经典类 - 封装:
- 把变量值通过实例化的方式传入到实例中来使用。
- 通过类中的方法(3种:类方法、实例方法、静态方法)把操作数据的逻辑进行了封装。
with open("e:\\a.txt".r) as fp:
fp.readline()
fp.read()
fp.seek()
推荐大家使用类似的封装方法。
- 多态
通过调用一个方法,呈现出不同的结果。某个对象中存在重名函数,就能实现多态。
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
def Func(obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 #s1_obj,执行 S1 的show方法,结果:#S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 #ss_obj,执行 Ss 的show方法,结果:#S2.show
跟基类没有关系,java存在类型,必须是基类和子类的继承关系才会存在多态;python不存在类型,所以跟基类也没有关系,只要传递的对象中有该方法就可以。
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
class X:
def show(self):
print 'x.show' #python中不必须是继承关系,只要有这个重名的函数就可以
def Func(obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 #s1_obj,执行 S1 的show方法,结果:
#S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 #ss_obj,执行 Ss 的show方法,结果:
#S2.show
x_obj=X()
Func(x_obj)
- 多态意味着可以对不同的对象使用同样的操作,但它们可能会以多种形态呈现出结果。在Python中,任何不知道对象到底是什么类型,但又需要对象做点什么的时候,都会用到多态
#coding=utf-8
class calculator:
def count(self,args):
return 1
calc=calculator()
#自定义类型
from random import choice
#obj是随机返回的类型不确定
obj=choice(['hello,world',[1,2,3],calc])
print obj
print type(obj)
print obj.count('a') #方法多态
#obj取到calc时等价于执行calc.count('a')
#如果没有取到calc,会自动执行字符串和列表自有的count()方法,由于
['hello,world',[1,2,3]里面都没有a,所以打印出来了0
- 多态—” 鸭子类型
#coding=utf-8
class Duck(object):
def quack(self):
print "Quaaaaaack!"
def feathers(self):
print "The duck has white and gray feathers."
class Person(object):
def quack(self):
print "The person imitates a duck."
def feathers(self):
print "The person takes a feather from the ground and shows it."
def in_the_forest(duck): #必须有这么一个方法,能有接收不同类型的参数,这个方法里面的参数都是一样的。
duck.quack()
duck.feathers()
donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john)
多态的好处:去除冗余代码
有一个方法可以接受不同类型的参数,产生不同的效果。
- 多态—运算符多态
#coding=utf-8
def add(x,y):
return x+y
print add(1,2) #输出3
print add("hello,","world") #输出hello,world
print add(1,"abc") #将抛出异常 TypeError,不同类型不能相加
- 方法重载
如果你学过C++、 JAVA或者是其他面向对象编程语言,你会发现Python中的重载与其他面向对象编程语言在使用上是有区别,其实可以这么说Python在形式上是不支持重载。
有相同的方法名时也能调用到最后一个,因此它是不支持方法重载的。
在java和c中,方法是可以重载的,方法名相同参数个数不同。
- 方法重写
重写是指子类重写父类的成员方法。子类可以改变父类方法所实现的功能,但子类中重写的方法必须与父类中对应的方法具有相同的方法名。也就是说要实现重写,就必须存在继承。
简单来讲,就是如果父类的方法不能满足子类的需求,子类就可以重写从父类那继承过来的方法。
方法重写必须方法名相同、参数个数相同
#coding=utf-8
class Parent(object): # 定义父类
def myMethod(self):
print 'call Parent'
def printName(self):
print "my name is LiLy"
class Child(Parent): # 定义子类
def myMethod(self): # 子类重写父类myMethod方法
print 'call Child'
Parent.myMethod(self)
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
c.printName()
- 运算符重写
#coding=utf-8
class Vector(object) :
def __init__(self, a, b) :
self.a = a
self.b = b
print self.a,self.b
def __str__(self):
print self.a,self.b
return '----Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other) :
#return Vector(self.a + other.a, self.b + other.b) #生成新的实例,print打印
时会固定的调用str这个方法
return self.a + other.a, self.b + other.b #直接这样不做实例化就不会调用str方法了
x = Vector(3,7)
y = Vector(1, -10)
print x + y
#print str(x)
#实现两个对象相加:3+1,7+-10
- __call__
对象后面加括号,触发执行
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print '__call__'
obj = Foo() # 执行 __init__
obj() # 执行 __call__
- 单例
实例只有一个,此为单例;占用的都是同一块内存。因为__new__方法的存在而实现的
#方法1,实现__new__方法
#并在将一个类的实例绑定到类变量_instance上,
#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
#如果cls._instance不为None,直接返回
class Singleton(object):
def __new__(cls, *args, **kw): #重写是为了控制它只生成一个
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls) #调用父类
cls._instance = orig.__new__(cls, *args, **kw) #生成实例
return cls._instance
class MyClass(Singleton):
a = 1
one = MyClass()
two = MyClass()
two.a = 3
print one.a
#3
#one和two完全相同,可以用id(), ==, is检测
print id(one)
#29097904
print id(two)
#29097904
print one == two
#True
print one is two
#True
- python对象销毁(垃圾回收)
内存泄漏:内存一直不释放就会出现内存泄漏,功能测试是很难发现的,操作次数少
系统连接数达不到那么多
这些必须从稳定性测试去测
循环引用:
- 装饰器
在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式,称之为装饰器(Decorator)。
(1)变量的工作范围
#coding=utf-8
outerVar = "this is a global variable"
def test() :
innerVar = "this is a Local variable"
#outerVar+=1 #发生赋值时就会报错,因为这个变量没有定义为全局,作用域有限
print outerVar #不赋值是不会报错的
print n
n = 10
test()
变量生存空间
#coding=utf-8
outerVar = "this is a global variable"
def test() :
innerVar = "this is a Local variable"
test()
print innerVar
嵌套函数
#coding=utf-8
def outer() :
name = "python"
def inner() :
print name
return inner()
outer()
print outer()
函数作为变量
#coding=utf-8
def add(x, y):
return x + y
def sub(x, y):
return x - y
def apply(func, x, y):
return func(x, y)
print apply(add, 2, 1)
print apply(sub, 2, 1)
闭包:内置函数带有函数外的参数,在外部执行
函数对象:就是指向函数指向的内存中的那部分地址
#coding=utf-8
def outer() :
name = 1
def inner() :
print name 红色字体部分组成一个闭包
return inner #函数对象
res = outer()
print type(res)
res() #闭包:内置函数带有函数外的参数,在外部执行
print res.func_closure #打印一下闭包里面的变量
装饰器:装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版函数。
如果我们想给now()函数增加一些别的功能,比如在调用该函数前后自动打印一些日志,但又不希望修改原now()的定义,这时候我们的装饰器就配上用场了。
#coding=utf-8
import time
#定义装饰器
def log(func):
def wrapper(*args, **kw):
print 'call func is %s' %func.__name__
return func(*args, **kw) #黄色字体部分形成一个闭包
#*args, **kw 可以接受任参数作为函数对象
return wrapper
@log
def now(): # @log+def now() 等价于log(now)
now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print "current time is %s" %now
now() #加括号是为了调用函数,等价于执行wrapper
print now #打印出now是个函数
log(now) #等价于wrapper
执行顺序:
now --->log(now)---->返回一个闭包:带有一个变量是函数对象now,还有wrapper这个嵌套函数----》wrapper()---》显示结果:打印了一下调用函数的名字和now函数的执行结果
使用@将装饰器应用到函数
理解过程:
#coding=utf-8
import time
#定义装饰器
def log(func):
def wrapper(*args, **kw):
print 'call func is %s' %func.__name__
return func(*args, **kw)
return wrapper
def now():
now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print "current time is %s" %now
#now是一个函数对象,传递到log中
#log函数的func局部变量值变成了now这个函数对象
#执行log函数,返回的是一个闭包-->闭包是啥?是wrapper这个嵌套函数+外部变量func
组成的,func现在是啥?func现在等于now函数
#print log(now)
#打印结果:<function wrapper at 0x00000000026DDB38>
#此结果返回了一个wrapper函数对象;证明log(now)返回的是一个函数
#如何调用函数? log(now)() 加括号就可以调用
log(now)()
#call func is now
#current time is 2017-09-24 17:26:11
#从结果可以看到,已经成功调用了该函数
#那么log(now)的另外一种写法是什么呢? 装饰器@log +def now()
import time
#定义装饰器
def log(func):
def wrapper(*args, **kw):
print 'call func is %s' %func.__name__
return func(*args, **kw)
return wrapper
@log
def now():
now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print "current time is %s" %now
#那么log(now)的另外一种写法是什么呢? 装饰器@log +def now(),把代码改成了这种形
#式了,那么调用就可以简化了呗
now()
#call func is now
#current time is 2017-09-24 17:29:17
#call func is now
#current time is 2017-09-24 17:29:17
#可以看到两个的执行结果是完全一样的。
小练习:写一个装饰器,把这个函数的执行时间计算出来。
#coding=utf-8
import time
#定义装饰器
def time_cal(func):
def time_cal2(*args, **kw):
start_time = time.time()
func(*args, **kw)
end_time = time.time()
print end_time-start_time
#return func(*args, **kw) #返回一下这个函数的执行结果
return time_cal2 #返回结果是一个函数对象,是这歌函数的执行结果
@time_cal
def now():
now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print "current time is %s" %now
time.sleep(5) #直接打印时间过快,加个停顿可以看出来时间,不然会打印出来0.0
now()
第三步:
#coding=utf-8
def deco(func):
print "before myfunc() called."
func()
print " after myfunc() called."
return func
@deco
def myfunc():
print " myfunc() called."
#myfunc()
#myfunc()
#E:\>python c.py
#before myfunc() called.
# myfunc() called.
# after myfunc() called.
#注释掉了调用函数,发现还是打印出来了,这就是装饰器的作用 等价于deco(myfounc
)
第四步:
def deco(func):
def _deco():
print "before myfunc() called."
func()
print " after myfunc() called."
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc():
print " myfunc() called."
return 'ok'
@deco
def print_mesage():
print "my message"
print myfunc #返回闭包:由_deco和myfunc的函数对象组成
myfunc() #调用了_deco()函数
print_mesage()
装饰器:减少重复代码的编写
装饰器的四步法:
- 最简单的函数,准备附加额外功能。
打印两次
#conding = utf-8
def myfunc():
print "myfunc() called"
myfunc()
myfunc()
- 使用装饰函数在函数执行前和执行后分别附加额外功能
装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)'''
#conding = utf-8
def deco(func):
print "before myfunc() called"
func()
print "after myfunc() called"
#print func
return func
def myfunc():
print "myfunc() called"
myfunc = deco(myfunc)
#以这样的形式去调用时,不加入return func会报错'NoneType' object is not callable
myfunc()
myfunc()
- 使用语法糖@来装饰函数,相当于“ myfunc = deco(myfunc)”但发现新函数只在第一次被调用,且原函数多调用了一次。等价于第二步程序
#conding = utf-8
def deco(func):
print "before myfunc() called"
func()
print "after myfunc() called"
#print func
return func
@deco
def myfunc():
print "myfunc() called"
#myfunc = deco(myfunc) #@@deco这;两种方式是等价的
myfunc()
myfunc()
调用了两次,打出来三次,而且后两次的结果都不符合预期。
- 使用内嵌包装函数来确保每次新函数都被调用
#conding = utf-8
def deco(func):
def _deco(): #使用内嵌包装函数来确保每次新函数都被调用
print "before myfunc() called"
func()
print "after myfunc() called"
#return func #不需要返回func,实际上应该返回的是原函数的返回值
return _deco #内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象
@deco
def myfunc():
print "myfunc() called"
myfunc()
myfunc()
关于装饰器自己的分析过程:
#conding = utf-8
def deco(func):
print "before myfunc() called"
func()
print "after myfunc() called"
#print func
#return func
@deco
def myfunc():
print "myfunc() called"
#myfunc = deco(myfunc) #@deco这;两种方式是等价的
myfunc()
#myfunc()
#@deco
#def myfunc(): 等价于 myfunc = deco(myfunc)
#这句话的意思是 利用@deco呼叫deco这个函数,并且赋值给被@的函数名即myfunc
#执行 步骤:
#第一轮 (deco def myfunc(): print "myfunc() called")
#为啥没调用也会执行? 因为这就是@deco这个在起作用
#1.myfunc = deco(myfunc)
#2.print "before myfunc() called"
#3.print "myfunc() called"
#4.print "after myfunc() called"
#5.没有return,默认返回一个 none
#此时myfunc等于none了 为啥等于none?因为deco(func)作为参数被传进来的,你
#不做返回它会自动返回none
#第二轮: 执行myfunc()
#上一轮执行后 myfunc成了none,后续无法执行了,报错 TypeError: 'NoneType' #object is not callable
借鉴之处:https://segmentfault.com/q/1010000006990592
python基础-面向对象(装饰器)的更多相关文章
- python基础—函数装饰器
python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...
- 十. Python基础(10)--装饰器
十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...
- [python基础]关于装饰器
在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...
- Day11 Python基础之装饰器(高级函数)(九)
在python中,装饰器.生成器和迭代器是特别重要的高级函数 https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...
- 1.16 Python基础知识 - 装饰器初识
Python中的装饰器就是函数,作用就是包装其他函数,为他们起到修饰作用.在不修改源代码的情况下,为这些函数额外添加一些功能,像日志记录,性能测试等.一个函数可以使用多个装饰器,产生的结果与装饰器的位 ...
- python基础之装饰器(实例)
1.必备 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...
- Python开发【第一篇】Python基础之装饰器
写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已实现的功能代码块开放:对扩展开发 #s2 ...
- python基础-----函数/装饰器
函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...
- 【Python基础】装饰器的解释和用法
装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下. 函数 我们定义了一个函数,没有什么具体操作,只是返回一个固定值 请注意一下缩 ...
- 学习PYTHON之路, DAY 5 - PYTHON 基础 5 (装饰器,字符格式化,递归,迭代器,生成器)
---恢复内容开始--- 一 装饰器 1 单层装饰器 def outer(func): def inner(): print('long') func() print('after') return ...
随机推荐
- 实战:mysql写存储过程并定时调用
有表:cap_meter_detail 字段:recordtime 情景:recordtime每半个小时记录一次,故一天会产生很很多数据,我们要做的是,每天00:00:00对cap_meter_det ...
- 基于.net core封装的xml序列化,反序列化操作
需求: 由于在.net core中去除了Xml序列化XmlSerializer操作类.因此,在于一此数据传输当中出,需要用到对xml格式字符串的处理问题.因此封装了一个xml序列化与反序列化操作的类库 ...
- jruby+watir-webdriver+cucumber自动化测试环境配置
1.安装java运行时环境,且配置环境变量 2.安装jruby环境,建议选择安装1.6.8或1.6.7版本的 3.安装需要的gem包 gem install activerecord -v='3.0. ...
- vue2 mint-ui loadmore(下拉刷新,上拉更多)
<template> <div class="page-loadmore"> <h1 class="page-title"> ...
- bmp图像文件格式说明
bmp图片文件包含4个部分数据,位图文件头,位图信息头,颜色表和位图数据(即RGB值). 在看位图格式之前先看一个问题,如果每个像素都用前面的24位色去表示,那么一个像素值需要3个字节数据,24位色也 ...
- [windows]设置使用空白密码进行远程登录
前提:系统用户设置了空白密码 方法1步骤: 开始菜单--〉运行--〉输入:gpedit.msc--> 计算机配置--〉Windows设置--〉安全设置--〉本地策略--〉安全选项:帐户:使用空白 ...
- win7 x64和win10 x64 windbg 本地调试记录
今天看CSDN和某文档看了win7 64位 和win10 64位 的windbg本地调试内核的办法 win7 x64 Step1:kdbgctrl –db Step2:kdbgctrl –e Step ...
- ZOJ 3537 Cake (区间DP,三角形剖分)
题意: 给出平面直角坐标系上的n个点的坐标,表示一个多边形蛋糕,先判断是否是凸多边形,若否,输出"I can't cut.".若是,则对这个蛋糕进行3角形剖分,切n-3次变成n-2 ...
- Ubuntu 14.04 配置confluence破解
1. 配置java环境,请参展我的另一篇博客 http://www.cnblogs.com/youran-he/p/8607155.html 2. 下载文件 https://pan.baidu.com ...
- Android计算器简单逻辑实现
Android计算器简单逻辑实现 引言: 我的android计算器的实现方式是:按钮输入一次,就处理一次. 但是如果你学过数据结构(栈),就可以使用表达式解析(前缀,后缀)处理. 而这个方式已经很成熟 ...