属性:
@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