一、类的描述符

#装饰器返回年纪 import time class Person: def __init__(self,name,birth): self.name = name self.birth = birth @property def age(self): # 返回年纪 struct_t = time.localtime() age = struct_t.tm_year - int(self.birth.split('-')[0]) return age alex = Person('alex','1965-5-12') print(alex.age) #54 #装饰器返回 class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property def price(self): #私有变量虽然不可以按原本的方式访问,但是可以使用property,改变 p = self.__price * self.discount return p apple = Goods('苹果', 5) # {'name': '苹果', '_Goods__price': 5} 返回私有变量, banana = Goods('香蕉', 10) #{'name': '香蕉', '_Goods__price': 10} print(apple.__dict__) print(banana.__dict__) print(apple.name) # 苹果 print(apple.price) # 4.0 print(banana.price) #8.0 Goods.discount = 1 print(apple.price) #5 print(banana.price) #10 #属性.setter修改属性 class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter # 其实这里是类似于纵向装饰器,先设置,在进入上面的peoperty,最后返回属性 def price(self,value): self.__price = value apple = Goods('苹果', 5) banana = Goods('香蕉', 10) print(apple.price) # 4 apple.price = 8 # 对应的调用的是被setter装饰的price方法 print(apple.price) # 6.4 对应调用的是被property装饰的price方法 class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter # 设置属性 def price(self,value): if type(value) is int or type(value) is float: self.__price = value @price.deleter # 删除属性 会自动删除属性 def price(self): del self.__price # 想删除一个属性 apple = Goods('苹果', 5) print(Goods.__dict__) print(apple.__dict__) #{'name': '苹果', '_Goods__price': 5} apple.price apple.price = 9 #设置 print(apple.price) #7.2 # del apple.price #执行后 就没有price属性了 class Teacher: __num = 0 def __init__(self,name,pw): self.name = name self.pw = pw self.__num += 1 # def read_num(): # 报错,这里显示找不到属性 # return __num @classmethod def read_num(cls): return cls.__num print(Teacher.read_num()) # 1 vccccccccc
总结:
私有的 :通过过给__名字这样的属性或者方法加上当前所在类的前缀,把属性隐藏起来了
只能在本类的内部使用,不能在类的外部使用,不能被继承
property 把一个方法伪装成属性
property和私有的两个概念一起用
定义一个私有的
再定义一个同名共有的方法,被property装饰
@方法名.setter
@方法名.deleter
2、

class Fruits: __discount = 0.8 def __init__(self, name, price): print('init',self) self.name = name self.__price = price #给对象创建一个以类名为基础的变量,以便下次类调用 @classmethod # 把一个方法从对象方法,变成一个类方法 def change_discount(cls,value): cls.__discount = value # cls到底是谁??? Fruits @classmethod def get_discount(cls): return cls.__discount print(Fruits.get_discount()) # 0.8 Fruits.change_discount(1) print(Fruits.get_discount()) # 1 # 类方法 # 1. 有些时候我们要修改的是类中的静态变量/类变量,此时根本不会和self有任何的操作关联 # 2.这时传一个self参数对我们来说完全没有用, 我们希望接受的是当前我们所在的类 apple = Fruits('apple',8) apple.change_discount(0.5) # 会去找父类 print(Fruits.get_discount()) # 0.5 # 类方法推荐使用类名调用而不是使用对象名调用
3、

class A: @staticmethod # 声明这个方法只是一个普通的不会使用任何和这个类中的变量相关的方法 def func(): # 此时 func是一个静态方法 print('既不操作和self相关的内容') print('也不操作和类名相关的内容') A.func() #打印…… class Student: def __init__(self,name): self.name = name @staticmethod def login(): pass # 先获取这个学生的用户名和密码 # 判断他登录成功之后进行实例化 # Student.login() # stu = Student('alex')
二、反射
反射: 通过字符串属性名 得到真正的这个字符串的名字对应的对象的属性值

class Student: def __init__(self,name): self.name = name def show_courses(self): print('调用了 show courses') def select_course(self): print('调用了 select course') def show_selected_course(self): print('调用了 show_selected_course') def quit(self): print('调用了 quit') wu = Student('吴彪') # 反射 通过字符串属性名 得到真正的这个字符串的名字对应的对象的属性值 ret = getattr(wu,'name') # 内置函数 可以查看属性 print(ret) # 吴彪 # print(getattr(wu,'show_courses')) # wu.show_courses getattr(wu,'show_courses')() #调用了 show courses getattr(wu,'select_course')() #调用了 select course ***** while True: name = input('user>>>') if hasattr(wu,name): func_attr = getattr(wu,name) # 如果取出对象属性名 if callable(func_attr): #是否可以调用 func_attr() else: print(func_attr)
1、

class Foo(object):pass class Son(Foo):pass ret = issubclass(Son,Foo) print(ret) #True
2、

a = 1 ret1 = type(a) is int ret2 = isinstance(a,int) print(ret1) #True print(ret2) #True
4、
-
所有的a.b都可以变成
getattr(a,'b')
-
用字符串数据类型的变量名
'b'
来获取实际的变量值,实则用字符串数据类型的变量名 找到这个变量对应的内存地址 -
作用于对象反射:obj.属性名 obj.方法名()
-
作用于类反射: cls.静态变量名 cls.类方法名() cls.静态方法名()
-
作用于模块反射: 模块名.方法名()
-
作用于调用函数和方法: def func():pass
-
作用于当前文件: 当前模块中得变量,函数等
#简单的反射,在类中使用反射 class Manager: # 管理员用户 def __init__(self,name): self.name = name def create_course(self): # 创建课程 print('in Manager create_course') def create_student(self): # 给学生创建账号 print('in Manager create_student') def show_courses(self): # 查看所有课程 print('in Manager show_courses') def show_students(self): # 查看所有学生 print('in Manager show_students') alex = Manager('alex') operate_lst = [('创建课程','create_course'),('创建学生账号','create_student'), ('查看所有课程','show_courses'),('查看所有学生','show_students')] for index,opt in enumerate(operate_lst,1): print(index,opt[0]) num = input('请输入您要做的操作 :') if num.isdigit(): num = int(num) if hasattr(alex,operate_lst[num-1][1]): #hasattr与getattr连用 getattr(alex,operate_lst[num-1][1])() # 如何使用反射 alex = Manager('alex') print(alex.name) # ==> print(getattr(alex,'name')) 用的相对少 funcname = 'create_course' a = getattr(alex,funcname) b = alex.create_course print(a) print(b) #a 和b一致 getattr(alex,'create_course')() # ==> # alex.create_course() 用的多 #类中的反射: class A: Country = '中国' @classmethod def show(cls): print('国家 : ',cls.Country) #使用了类中的私有变量 print(getattr(A,'Country')) # print(A.Country) A.show # getattr(A,'show') getattr(A,'show')() # A.show() #类中反射两种方式: #对象名.属性名 / 对象名.方法名() 可以直接使用对象的方法和属性 #当我们只有字符串数据类型的内容的时候 # getattr(对象名,'方法名')() # getattr(对象名,'属性名') #反射模块中的方法 import re ret = re.findall('d+','2985urowhn0857023u9t4') print(ret) #['2985', '0857023', '9', '4'] 'findall' getattr(re,'findall') # re.findall ret = getattr(re,'findall')('d','wuhfa0y80aujeiagu') print(ret) #['0', '8', '0'] import time time.time == getattr(time,'time') time.time() == getattr(time,'time')() # 反射本文件中的内容:只是要出现在全局变量中的名字,都可以通过getattr(modules[__name__],字符串数据类型的名字)获得 from sys import modules print(modules) # DICT KEY是模块的名字,value就是这个模块对应的文件地址 import re print(re) # <module 're' from 'D:\python3\lib\re.py'> print(modules['re']) # 也就是找到re模块的内存地址 print(modules['re'].findall) # print(re.findall) 参数添加在后面,效果相同, #打印本地加载的所有属性: a = 1 b = 2 print(__name__) #__main__ print('__main__') #__main__ print(getattr(modules[__name__],'a')) #1 #语法 a = 1 b = 2 getattr(modules[__name__],'变量名') #函数名 def func(a,b): print('in func',a,b) getattr(modules[__name__],'func') # func getattr(modules[__name__],'func')(1,2) # func #类名 class Course: def func(self): print('in func') print(Course) print(getattr(modules[__name__],'Course')) # Course getattr(modules[__name__],'Course')() # 实例化的过程
总结:
hasattr和getattr:
只要是a.b这种结构,都可以使用反射,用对象类模块反射,都只有以下场景
这种结构有两种场景
1、a.b b是属性或者变量值
getattr(a,'b') == a.b
2、a.b() b是函数或者方法
a.b()
getattr(a,'b')()
a.b(arg1,arg2)
getattr(a,'b')(arg1,arg2)
a.b(*args,**kwargs)
getattr(a,'b')(*args,**kwargs)
如果是本文件中的内容,不符合a.b这种结构
1、直接调用func()
getattr(sys.modules[__name__],'func')()
2、直接使用类名 Person()
getattr(sys.modules[__name__],'Person')()
3、直接使用变量名 print(a)
getattr(sys.modules[__name__],'a')
4、所有的getattr都应该和hasattr一起使用
if hasattr():
getattr()
setattr 只用来修改或者添加属性变量,不能用来处理函数或者是其他方法
a.b = value
setattr(a,'b',value)
delattr 只用来删除 属性变量
del a.b 删除属性 相当于删除了a对象当中的b属性
delattr(a,'b')