python基础13-item/__str__方法/__format__方法/__slots__方法/_cal_方法/迭代器协议/描述符
- 文件也是对象,也可以用反射模块中的四个方法
- 在团队协作中,可插拔机制,使用反射方法判断下模块中是否有对应的函数
- 导入就是将文件拿过来,在当前文件中执行一遍
-
#导入其他模块用import as的方法,想在模块自身应用反射方法,需要通过以下语句方法来导入模块本身,然后应用反射的方法
import sys obj1=sys.modules[__name__]#__name__是当前模块名,sys.modules通过key的方法能取到当前模块print('==>',hasattr(obj1,'x'))
-
内置函数补充
- isinstance(obj,cls)判断一个对象obj是否为某类class本身或子类生成的实例
- issubclass(sub,super)判断sub是否为super的子类
- type(b1)显示实例b1所属的类
- !没啥用__getattribute__:属性存在,返回匹配的值。属性不存在,抛出一个异常
-
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('执行的是getattr') def __getattribute__(self, item):#甭管属性是否能找到,都会触发此, print('执行的是getattribute') raise AttributeError('抛出异常了')#在此抛出这个指令的情况下,才会触发getattr f1=Foo(10) # f1.x f1.xxxxx
-
item系列
-
#.的调用方式跟getattr等三个方法相关,字典形式的操作跟getitem等三个方法相关
class Foo: def __getitem__(self, item): print('getitem') return self.__dict__[item] def __setitem__(self, key, value): print('setitem') self.__dict__[key] = value # 模拟字典新增键值对的方法 def __delitem__(self, key): print('delitem') self.__dict__.pop(key) f1 = Foo() print(f1.__dict__) # f1.name='egon'#这种方式不会触发setitem f1['name'] = 'egon' # 按照字典方式赋值,会触发setitem方法,字典是['属性']的形式 f1['age'] = 18 print(f1.__dict__) del f1.name # 通过.的方式,跟delattr那种方式匹配,不匹配delitem的方式 print(f1.__dict__) -
str方法:改变对象的字符串显示
- 一切皆对象,打印时本质都应该是object,有些对象的打印结果不是object。表明可以在自己的类中定制一些方法,来控制该类实例出的对象输出结果是什么形式
-
class Foo: #类中有默认的str方法,如果不自定义,则采用系统的 def __str__(self):#自定义该类实例的对象的打印结果 return '自定制的对象的显示方式'#必须return字符串类型 f1=Foo() print(f1)#本质是就调用的--str(f1)--方法,就是f1.__str__()方法
-
#在解释器中用__repr__
class Foo: #类中有默认的str方法,如果不自定义,则采用系统的 def __str__(self): return '这是str' def __repr__(self):#自定义该类实例的对象的打印结果 return '名字是%s 年龄是%s'%(self.name,self.age)
#不能return非字符串格式 f1=Foo() #在解释器中输入f1#本质是就调用的--repr(f1)--方法,就是f1.__repr__()方法 print(f1)#如果有str就找str,如无,则找repr。如都无,则找系统内置的 -
为实例定制format
-
format_dic = { 'ymd': '{0.year}{0.mon}{0.day}', 'm-d-y': '{0.mon}-{0.day}-{0.year}', 'y:m:d': '{0.year}:{0.mon}:{0.day}' } class Date: def __init__(self, year, mon, day): self.year = year self.mon = mon self.day = day def __format__(self, format_spec): print('我执行啦') print('-->', format_spec) if not format_spec or format_spec not in format_dic: format_spec = 'ymd' fm = format_dic[format_spec] return fm.format(self) d1 = Date(2016, 12, 26) # format(d1) print(format(d1, 'y:m:d'))
-
slots属性
- _solts_是一个类变量,变量值可以是列表,元组或者可迭代对象,也可以是字符串(意味着所有实例只有一个数据属性)
- 类的字典是共享的,供该类产生的实例调用
- 当类的属性很少,但是需要产生成千上万的实例时,每个实例都有独立的存储空间,很浪费内存
- _slots_上场后,每个实例不再有_dict_,这样不用为每个实例创建属性字典,节省内存空间
-
class Foo: # __slots__ = ['name','age'] __slots__ = 'name' # 不用每个实例创建属性字典,统一到类属性字典中找 # 缺点:每个实例只能创建一个name的属性,不能创建其他属性 # 优势所在是省内存,而不是处于限制实例扩展属性 f1 = Foo() f1.name = 'egon' print(f1.name) # print(f1.__dict__) print(f1.__slots__)
-
_doc_类方法
-
class Foo: '我是描述信息' # 这个信息不能被继承 pass class Bar(Foo): pass print(Bar.__doc__)
- c1.__module__获取当前c1是哪个模块产生的
- c1.__class__查看c1是哪个模块的哪个类产生的
-
__del__函数又叫析构函数
- 与描述符__delete__不同,当对象在内存中释放时,自动触发执行,一般无需定义。只在实例被删除,或者程序执行完毕后运行
-
__call__方法
- 对象后边加括号,触发执行,呼叫不动。f1(),就是实例f1调用创建该实例的类的call方法
class Foo: def __call__(self, *args, **kwargs): print('实例执行了,obj()') f1 = Foo() f1() # 执行就是调用该实例的类的call方法 Foo() # 调用创建该Foo实例的类的call方法#类是对象,所以也是别的类产生的
-
迭代器协议
- for循环的步骤,先通过_iter_方法把对象变为可迭代对象
-
#手动实现迭代器协议,包括iter和next方法即可
class Foo: def __init__(self, n): self.n = n def __iter__(self): return self def __next__(self): if self.n==100: raise StopIteration('终止了') self.n += 1 return self.n f1 = Foo(10) print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print(next(f1)) for i in f1:#步骤一,iter(obj),步骤二,调用obj.__iter__方法,步骤三,调用迭代器的__next__方法 print(i) -
# 迭代器实现斐波那契数列 class Fib: def __init__(self): self._a = 1 self._b = 1 def __iter__(self): return self def __next__(self): if self._b > 100: raise StopIteration('终止了') self._a, self._b = self._b, self._a + self._b return self._a f1 = Fib() print(next(f1)) print(next(f1)) print(next(f1)) print('>>>>>>>>>>>>>>') for i in f1:#接着上边的for循环开始 print(i)
-
描述符
- 如果一个类中包含三个魔术方法(__get__)(__set__)(__delete__)方法,该类就称为一个描述符
- 描述符的作用,就是对类或对象中某个成员进行详细的管理操作。描述符只管理某个成员,而setattr则是管理全部数据
- 数据描述符就至少有get和set,非数据描述符没有set
- 要想使用描述符,必须在类之前声明描述符
- 属性描述方法和描述符的区别
- 属性描述方法,__getattr__, __setattr__, __delattr__等。针对当前类/对象的所有成员的管理,属性描述方法仅对当前类有效
- 描述符,__del__, __set__, __deleate__。仅仅针对类/对象某一个成员的设置,描述符可对不同的类使用
- 描述符的使用方法
- 在py文件中定义一个描述符,既描述符,包括以上三个魔术方法
- 然后在想调用的类中,讲数据属性或函数属性=描述符,即交给描述符管理,
- 最后,在描述的三个魔术方法中,设置对应的返回值,或者设置,删除等操作即可
- 属性描述方法的使用方法
- 定义在类中,在满足条件时,触发类中自定义的getattr方法
- 如果没有定义,则调用系统内置的getattr方法
- 描述符第二种使用方式,将描述符和应用类写在一个类中,然后将成员交给描述符管理,username=property(获取描述符getusername,设置描述符 setusername, 删除描述符delusername, 文件d=‘ ’)
-
#描述符的第三种使用方式
@property # 将用户名交给描述符管理,默认是get描述符 def username(self): pass @username.setter # 设置描述符 def username(self,val): pass @username.deleter # 删除描述符 def username(self): pass - 描述符的优先级。类属性>数据描述符>实例属性>非数据描述符>找不到的属性触发getattr
-
软件开发规范
- 有bin目录,放置可执行文件。写一端小的脚本,不同角色登录程序
- 有conf文件。静态配置
- db存放数据
- lib,公共类库,公共功能
- log模块
- src,core存储核心逻辑
- 对象序列化后,在打开时,对象是依托类存在的,要在打开序列文件的程序导入类方可执行
-
python干的好事
- 新建包或者目录后,pycharm会自动将当前路径加入环境变量中
- 为了让程序在所有平台都能用,执行以下步骤
-
import sys, os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR)