day27绑定方法与非绑定方法,反射,内置方法
上节课复习:
1. 组合
一个对象有一个属性,该属性的值是来自于另外一个类的对象。
2. 封装
装指的是将属性装进一个容器。
封指的是将容器内的属性隐藏起来。
如何做到"封":在属性名前加上__开头,特点如下:
1. __开头的属性会在检测语法时发生变形,规则_类名__属性名
2. 该隐藏是对外不对内的
3. 该变形只在语法检测时发生一次,在类定义之后新增的__开头的属性不会发生变形
4. 父类不想让子类覆盖自己的属性,可以在属性前加上__开头
封装不是单纯意义的隐藏:
(上句的理解:属性 的封装不是单纯的为了把属性隐藏起来让使用者找不到那些属性,
类定义时封装属性的目的是:为了给类外部使用,(属性定义出来就是为了被使用)只是不能直接使用封装的属性,但可以间接使用他们,
如何间接使用呢?就是类内部开个接口(类内部定义一个函数)供类外部使用者使用,接口内包含对封装属性的使用。)
1. 封装数据属性: 是为了开放接口让类外部的使用者间接地去操作属性,从而我们可以通过修改接口的逻辑来严格控制使用者对属性的操作
2. 封装函数属性: 隔离复杂度
3.类中的装饰器----------概括起来就是用于修饰类中定义的函数属性。
@property
是一个装饰器,用来将类中定义的函数属性伪装成一个数据属性。
class Foo:
@property
def xxx(self): # 查看属性的功能
pass
@xxx.setter
def xxx(self,val): # 修改属性的功能
pass
@xxx.deleter
def xxx(self): # 删除属性的功能
pass
class Eg:
def c(self):
pass
def a(self):
pass
def b(self):
pass
xxx=property(查看功能名a,修改功能名b,删除功能名c)
4. 多态
多态指的是同一种事物的多种形态。
多态性指的是可以在不用考虑对象具体类型的前提下而直接使用对象下的方法。
今日内容:
1. 绑定方法与非绑定方法
classmethod
staticmethod
2. 反射
hasattr
setattr
getattr
delattr
3. 内置方法
内置方法是什么?def __xxx__() 是这种两边都有__的函数。
内置方法与内置函数1.不同于内置函数的地方在于:内置方法满足一定条件时自动触发执行函数体代码。
2.相同的地方是:都是python解释器自带的函数。
__str__()内置方法
__del__()内置方法
1. 绑定方法与非绑定方法
'''
类中定义函数分为了两大类:
1. 绑定方法
特殊之处: 绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入。(即函数绑定给a,a调用此函数的话有自动传值效果。)
(应该由谁来调用的理解:就是一般情况给谁来调用,因为自动传值用起来简单,但并不是指其他人不能调用。)
绑定给对象的方法: 在类中定义的函数没有被任何装饰器修饰的情况下,默认就是绑定对象的。
对象调用绑定给对象的方法表现为:对象.boud_method(),自动将对象当作第一个参数传入。
绑定给类的方法: 为类中定义的函数添加一个装饰器classmethod,就是绑定类的。
类调用绑定给类的方法表现为:类.boud_method(),自动将类当作第一个参数传入。
2. 非绑定方法
特殊之处: 非绑定方法就是一个普通函数,既不与类绑定又不与对象绑定,
意味着类与对象都可以调用,但是无论谁来调用都是一个普通函数,没有自动传值效果。
非绑定方法: 为类中定义的函数添加一个装饰器staticmethod,就是非绑定方法
'''
# class Foo:
# def func1(self):
# print('func1',self)
#
# @classmethod
# def func2(cls):
# print('func2',cls)
#
# @staticmethod
# def func3(x,y):
# print('func3',x,y)
#
# obj=Foo()
#一.绑定给对象的方法
# 绑定给对象的,应该由对象来调用,有自动传值效果。
# obj.func1()
# print(obj)
# 绑定给对象的方法,类也可以调用,但是类调用就是一个普通函数,没有自动传值的效果。
# print(obj.func1)
# print(Foo.func1)
# Foo.func1(obj)
#二.绑定给类的方法
# 绑定给类的方法,应该由类来调用,把类当做第一个参数传入。
# print(Foo.func2)
# print(obj.func2)
# Foo.func2()
#绑定给对类的方法,对象也可以调用,但是对象调用仍然把类当做第一个参数传入。
# obj.func2()
#三.非绑定方法
# print(obj.func3)
# print(Foo.func3)
# obj.func3(1,2)
# Foo.func3(1,3)
类的定义中,如何决定函数时绑定给类、对象、非绑定?
看函数体代码要用到类,还是对象,还是2者都不用。
***类中的函数如何辨别是绑定给谁的?1.根据定义来判断;2.根据括号内的self或cls判断。
import settings
class MySQL:
def __init__(self,ip,port):#绑定给对象的方法??
self.id=self.create_id()
self.ip=ip
self.port=port
def tell_info(self):#绑定给对象的方法
print('<%s:%s:%s>' % (self.id,self.ip, self.port))
@classmethod
def from_conf(cls):#绑定给类的方法
return cls(settings.IP, settings.PORT)#实现自动生成对象。
@staticmethod
def create_id():#非绑定方法
import uuid
return uuid.uuid4()#实现每次调用造出来一个唯一的编号。
obj=MySQL('1.1.1.1',3306)
# obj1=MySQL('1.1.1.2',3406)
obj.tell_info()
# obj1.tell_info()
# obj2=MySQL.from_conf()
# obj2.tell_info()
二。反射
1.反射是什么?
Python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(类和对象都可以使用反射)。
2.如何用反射?
四个可以实现反射(即自省)的函数:hasattr,getattr,setattr,delattr
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
class Teacher:
school = 'oldboy'
def __init__(self,name,age):
self.name = name
self.age = age
def teach(self):
print('%s i teaching'%self.name)
'''
定义一个老师的类
有1个数据属性,2个函数属性
'''
hasattr(object,name) 判断对象object中有没有一个name字符串对应的方法或属性。有则返回True,没有则返回False。
print(hasattr(Teacher,'school')) #判断Teacher中是否有school print(hasattr(Teacher,'teach')) #判断Teacher中是否有teach ''' True True '''
getattr(object, name, default=None) 从object中取一个name字符串对应的方法或属性,没设置default/默认值时没有则报错,设置default后没有则返回default。
print(getattr(Teacher,'school',-1)) print(getattr(Teacher,'teach',-1)) print(getattr(Teacher,'student',-1)) ''' oldboy <function Teacher.teach at 0x000000000280BB70> -1 '''
setattr(x, y, v) 将对象x中的字符串为y的属性设置为v , setattr(x, 'y', v) is equivalent to “x.y=v”'。复习思考:类、对象如何增删数据属性和函数属性?
这里的value可以是值,也可以是函数或者方法。
print(getattr(Teacher,'school',-1)) setattr(Teacher,'school',123) print(Teacher.school) ''' oldboy 123 '''
delattr(x, y) 将对象x中的字符串为y的属性删除 delattr(x, 'y') is equivalent to “del x.y”
print(getattr(Teacher,'school',-1)) delattr(Teacher,'school') print(hasattr(Teacher,'school')) ''' oldboy False '''
应用:反射当前模块成员。
import sys
def s1():
print ('s1')
def s2():
print ('s2')
this_module = sys.modules[__name__]#得到当前模块对象。
print(hasattr(this_module, 's1'))
print(getattr(this_module, 's2'))
'''
True
<function s2 at 0x00000000027FBAE8>
'''
3.为什么要用反射?
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。
好处二:动态导入模块(基于反射当前模块成员)

延伸:如何查看类或对象下有什么属性?
一。内置函数:dir函数
1.1通过print(dir(对象名/类名))******
dir([object]) --------》会返回对象中所有定义的属性名字列表。(属性分为 数据属性 和 函数属性)。
class Foo(object): def __init__(self): self.__name = 'private name' self.age=123 def inn(self): pass def __out(self): pass f=Foo() print(f.__dict__) print(dir(f)) #返回类中和对象中定义的属性名列表,也显示封装的属性名。****** print(dir(Foo)) #返回所有类中定义的属性名列表,也显示封装的属性名。******
对象:
['_Foo__name', '_Foo__out', '__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__', 'age', 'inn']
类:
['_Foo__out', '__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__', 'inn']
得到属性列表后,问题来了:如何区分他们都是属于对象/类的数据属性还是函数属性?
******属性与对象/类的关系与用法:(自己)
属性是隶属于对象或类的,这些属性名被使用时只能类/对象调用(即名字前+点和对象/类名来调用),在类内和类外使用属性名时都要+点和对象名/类名,
而不能像变量和函数被无附加的单独使用。
因为本质上他们被定义在类/对象的__dict__名称空间中。
******方法1,自动提示法:pycharm中写出对象名/类名+.后,会自动提示其有的属性名,并且末尾有括号的为函数属性,无括号为数据属性。
方法2,实验法:print(对象名/类名.属性名)看打印结果,结果为基础数据类型(‘bob’、list、{})的为数据类型,反之函数属性。
1.2 dir函数在模块或py文件中的用法:******
1.而在一个py文件中print(dir())--------------》返回模块/py文件中所有定义的全局名字列表。有效即可使用。
2.在py文件中,导入一个模块b,然后print(dir(b))------》返回模块b所有中定义的全局名字列表。
2中可以看出py文件名对应一个模块对象,py文件也是个对象。python中一切皆对象。验证:print(type(b))---》<class 'module'>。
class Foo: def __init__(self): self.__name = 'private name' self.age=123 def inn(self): pass def __out(self): pass f=Foo() print(dir()) -----》#返回模块/py文件的所有定义的全局名字列表。 print(globals())---》#返回这个py文件中可用的全局名字字典。
print([i for i in globals()])----》
['Foo', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'f']
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000241B4A8>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/新建文件夹/day30杨元虎讲面向对象实现选课系统/自己写选课系统的管理员登录注册/1.py',
'__cached__': None, 'Foo': <class '__main__.Foo'>, 'f': <__main__.Foo object at 0x00000000027D0DD8>}
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'Foo', 'f']
二。globals()和nonlocals()内置函数的用法:
在一个py文件中:print(globals())----》返回这个文件中定义的全局名字字典。
return the names in the current scope。
scope 在python中义为:作用域。
current scope 义:当前作用域
global scope全局作用域 -----local scope 局部作用域
三。内置函数
问题:以前如何判断类型?
way1.以前:print(type(a) is str)
way2.以后要用isinstan函数来判断类型。
isinstance(obj,cls)检查是否obj是否是类 cls 的对象。
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 6 isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类。
1 class Foo(object): 2 pass 3 4 class Bar(Foo): 5 pass 6 7 issubclass(Bar, Foo)
四。对象的内置方法
参见:http://www.cnblogs.com/haiyan123/p/7375772.html
1.__str__方法: 会在对象被打印时自动触发执行,然后将返回值返回给print功能进行打印。
使用注意:1.打印return后的数据。2.返回值类型必须是str类型!!
何时触发执行?1.str(对象)时 2.字符串拼接时 3.print(对象)时。
1 class Foo: 2 def __init__(self,name): 3 self.name = name 4 def __repr__(self): 5 return 'obj in str' #这里只能是return 6 # def __str__(self): 7 # return '%s obj in str'%self.name 8 f = Foo('egon') 9 print(f) #优先执行__str__里面的内容 10 # 那么你是不是据地__repr__没用呢? 11 # print('%s'%f) #执行的是__str__里面的返回值 12 # print('%r'%f) #执行的是__repr__里面的返回值 13 print('==============') 14 print(str(f)) #当执行str(f)时,会去找__str__这个方法,如果找不到的时候,__repr__这个方法就给替补了 15 print(repr(f)) 16 #1.当打印一个对象的时候,如果实现了__str__方法,打印__str__中的返回值 17 # 2.当__str__没有被实现的时候,就会调用__repr__方法 18 # 3.但是当你用字符串格式化的时候,%s和%r会分别调用__str__和__repr__方法 19 # 4.不管是在字符串格式化的时候还是在打印对象的时候, 20 # __repr__方法都可以作为__str__方法的替补,但反之则不行 21 # 5.用于友好的表示对象。如果__str__和__repr__方法你只能实现一个:先实现__repr__
如何用?:
在自定义__str__方法之前,打印对象print(peo),输出是对象的内存地址。
class People:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):#自定义__str__方法,来实现控制对象被打印时显示的信息。
return '<%s:%s>' %(self.name,self.age)
peo=People('egon',18)
print(peo) #等同于print(peo.__str__())
l=list([1,2,3])
print(l)
2.__del__方法: 会在对象被删除时自动触发执行,用来在对象被删除前回收系统资源。
注:如果产生的对象仅仅只是python程序级别的(用户级),python应用程序会自动回收自己的内存空间,所以无需定义__del__;
如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,
比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。
class Foo:
def __del__(self):
print('===>')
obj=Foo()
# del obj
print('其他代码...')
class Bar: def __init__(self,x,y,filepath): self.x=x self.y=y self.f=open(filepath,'r',encoding='utf-8') def __del__(self): # del方法内,写回收系统资源相关的代码 self.f.close() obj=Bar(10,20) del obj
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收系统资源。
class Mysql: def __init__(self,file,mocode='r',encoding='utf-8'): self.file=file self.mocode=mocode self.encodeing=encoding self.fobj=open(file,mode=mocode,encoding=encoding) def __str__(self): msg=''' file:%s mocode:%s encoding:%s '''%(self.file,self.mocode,self.encodeing) def __del__(self): self.fobj.close() f=Mysql('D:\Python\第五周\day22\settings.py',mocode='r',encoding='utf-8') res=f.fobj.read() print(res) # __del__析构方法,当对象在内存中被释放时,自动触发执行。主要是用来回收系统资源,



浙公网安备 33010602011771号