面向对象的进阶->反射、面向对象的进阶->内置方法 第二十二天 2018.11.9
上节复习:
静态属性,类方法,普通方法(混淆)
class 类名(父类1,父类2):
静态属性 = '' # 静态属性 类属性
def __init__(self): # 初始化方法
self.name = 'alex'
def func(self): # 动态属性 方法
print(self.age)
对象 = 类名() 对象.方法名() 对象.属性名 可以通过对象.属性名=XXX,直接给对象属性重新赋值,或者给对象建立新属性和赋值 对象.func() #类名.func(对象)
组合 :表达的是 什么有什么的关系 #***** 一个类的属性 是另外一个类的对象
继承 : 表达的上 什么是什么的关系
class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period #周期
python = Course('python',19800,'6 months') #建立Course的实例化对象
class Classes:
def __init__(self,name,course):
self.name = name
self.course = course #Classes类的属性是Course类的对象---->组合
# self.course_name = 'python' #只是给Classes类的对象加了一个属性---->属性名为Course_name 属性值为固定的python
pys9 = Classes('python_s9',python) #建立Classes的实例化对象
print(pys9.course.name) #对象名.属性名---->Classes属性名==Course对象名.属性名
python.name = 'python全栈' #将Course对象的属性值重新赋值修改
print(pys9.course.name) #找的Course对象的属性值也会跟着变化
命名空间:类和对象分别存在不同的命名空间中
面向对象的三大特性 : 继承 多态 封装
继承 :
单继承 : ****
父类(超类、基类)
子类(派生类):派生方法和派生属性
子类的对象在调用方法和属性 : 先用自己的 自己没有 才用父类的
多继承 :(面试)
不会超过三个父类,不要超过三层 ***
如果子类自己有用自己的,如果没有就用离子类最近的那个父类的方法
抽象类和接口类 **
经典类和新式类 继承规则不同 深度优先和广度优先 ***** (面试)
super 只能在python3中使用 mro ****
super是根据mro广度优先顺序找上一个类
多态 : (面试)
多态和鸭子类型
封装 : *** (面试)
私有的
__名字
只能在类的内部调用 子类都无法继承
三个装饰器
@property **** 规范 面试 #@name.setter
@staticmethod ***
@classmethod ***** 当一个方法只使用了类的静态变量时 就给这个方法加上@classmethod装饰器,默认传cls参数
class Goods:
__discount = 0.8 #私有类属性 折扣率
def __init__(self,name,price):
self.name=name
self.__price=price #定义为私有属性
@classmethod #下面最接近的方法变成类方法,可以直接被类调用,不需要依赖任何对象
def change_discount(cls): #类方法形参必须为cls,后面可以和self一样,加形参
cls.__discount = 0.5 #修改掉discount,私有属性在本类中可以被随便使用
@property #把原价定义为私有,用装饰器把price方法定义为公有方法 通过在类外调用同名方法进而使用
def price(self): #不可以传入cls,cls传入的只不过是一个类似'name','age'一样的属性,并不是cls对象的类属性
return self.__price*self.__discount #不可以表示为cls.__discount,类方法里面找不到cls对象
Goods.change_discount()
PG=Goods('苹果',5)
print(PG.price) #对象名.方法,调用的是方法,price方法中无self.__price重新赋值,因此不可以用对象名.方法(实参)
判断类与对象关系的两个方法:
isinstance(对象名a,类名B)检 对象a是否是类B的对象---->True是---->False不是
issubclass(类B, 类A)检查类B是否是类A的派生类---->True是---->False不是
class A:pass class B(A):pass a = A() print(isinstance(a,A)) #True print(issubclass(B,A)) #True print(issubclass(A,B)) #False
面向对象的进阶---->反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射 : 是用字符串类型的名字 去操作 变量(反射 就没有安全问题)
name = 1
eval('print(name)') # 安全隐患
eval---->提取并且执行
反射对象中的属性和方法 hasattr getattr setattr delattr
getattr:通过变量名的字符串形式取到的值
反射对象的属性和对象的方法getattr(对象名,'变量名/方法名')获得的方法是该方法的内存地址,执行在后面加()即可
class A:
def func(self):
print('in func')
a = A()
a.name = 'alex'
a.age = 63
# 反射对象的属性
ret = getattr(a,'name') # 通过变量名的字符串形式取到的值
print(ret)
print(a.__dict__)
#变量名 = input('>>>') # func
print(getattr(a,变量名))
print(a.__dict__[变量名])
# 反射对象的方法
a.func()
ret = getattr(a,'func')
ret()
反射类的属性和类的方法:getattr(类名,'属性名/方法名')获得的类方法是类方法的内存地址,执行在后面加()即可
类方法一般只有:classmethod staticmethod 对象.方法---->调用的是普通方法
class A:
price = 20
@classmethod
def func(cls):
print('in func')
# 反射类的属性
# A.price
print(getattr(A,'price'))
# 反射类的方法 :类方法一般只有:classmethod staticmethod #对象.方法---->调用的是普通方法
# A.func()
if hasattr(A,'func'):
getattr(A,'func')()
反射模块的属性和模块的方法getattr(模块名,'方法名')获得的方法是方法的内存地址,执行在后面加()即可
#模块 import my #反射模块的属性 print(my.day) print(getattr(my,'day')) #反射模块的方法 getattr(my,'wahaha')() #内置模块也能用 #time #asctime import time print(getattr(time,'time')()) print(getattr(time,'asctime')())
反射自己模块中的变量和函数和类 getattr(sys.modules[__name__],'变量名/函数名/类名')
def qqxing():
print('qqxing')
year = 2018
import sys
print(sys.modules['__main__'].year) #sys.modules获得当前模块的所有导入模块---->字典格式
#反射自己模块中的变量
print(getattr(sys.modules['__main__'],'year'))
#反射自己模块中的函数
getattr(sys.modules['__main__'],'qqxing')()
变量名 = input('>>>')
print(getattr(sys.modules[__name__],变量名))
#一个模块中的类能不能反射得到
import my
print(getattr(my,'C')())
if hasattr(my,'name'):
getattr(my,'name')
要反射的函数有参数怎么办?
print(time.strftime('%Y-%m-%d %H:%M:S'))
print(getattr(time,'strftime')('%Y-%m-%d %H:%M:S'))
hasattr---->判断将要反射的东西是否存在 一般和getattr组合起来使用
import my
print(getattr(my,'C')())
if hasattr(my,'name'): #判断是否存在
getattr(my,'name')
setattr---->设置修改变量
delattr 删除一个变量
class A:
pass
a = A()
setattr(a,'name','nezha')
setattr(A,'name','alex')
print(A.name)
print(a.name)
delattr(a,'name')
print(a.name)
delattr(A,'name')
print(a.name)
面向对象的进阶---->内置方法
双下方法: __init__ __dict__ __str__ __repr__ __len__ __del__ __cal__
__str__和__repr__
object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
repr 是str的备胎,但str不能做repr的备胎
print(obj)/'%s'%obj/str(obj)的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串
如果没有__str__方法,会先找本类中的__repr__方法,再没有再找上级父类中的__str__。
repr(),只会找__repr__,如果没有找父类的
%s str() 直接打印 实际上都是走的__str__
%r repr() 实际上都是走的__repr__
obj.__str__ str(obj)
obj.__repr__ repr(obj)
class Teacher:
def __init__(self,name,salary):
self.name = name
self.salary = salary
def __str__(self):
return "Teacher's object :%s"%self.name
def __repr__(self):
return str(self.__dict__)
def func(self):
return 'wahaha'
nezha = Teacher('哪吒',250)
print(nezha) # 打印一个对象的时候,就是调用a.__str__
print(repr(nezha))
print('>>> %r'%nezha)
a.__str__ --> object
#object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
l = [1,2,3,4,5] # 实例化 实例化了一个列表类的对象
print(l)
内置方法有很多,不一定全在object类中
例如:object里面没__len__内置方法(有些东西无法计算长度,object要兼容所有的,因此没len())
class Classes:
def __init__(self,name):
self.name = name
self.student = []
def __len__(self): #object里面没__len__内置方法(有些东西无法计算长度,object要兼容所有的,因此没len())
return len(self.student)
def __str__(self):
return 'classes'
py_s9= Classes('python全栈9期')
py_s9.student.append('二哥')
py_s9.student.append('泰哥')
print(len(py_s9))
print(py_s9)
__del__:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
析构函数: 在删除一个对象之前进行一些收尾工作(引用计数)
class A:
def __del__(self): # 析构函数: 在删除一个对象之前进行一些收尾工作
self.f.close()
a = A()
a.f = open() # 打开文件 第一 在操作系统中打开了一个文件 拿到了文件操作符存在了内存中
del a # a.f 拿到了文件操作符消失在了内存中
del a # del 既执行了这个方法,又删除了变量
__call__:对象()---->相当于执行__call__方法
class A:
def __init__(self,name):
self.name = name
def __call__(self):
'''
打印这个对象中的所有属性
:return:
'''
for k in self.__dict__:
print(k,self.__dict__[k])
a = A('alex')()
浙公网安备 33010602011771号