如何定义一个类?
class 类名:pass
怎样通过类,创建出一个对象?
根据类创建对象one = Money()
执行流程1. 类的定义2. 根据类,创建出一个对象3. 将对象的唯一标识返回
class Money:passprint(Money.__name__)
xxx = Money
print(xxx.__name__)Money = 666
print(id(Money))
print(Money)
one = Noney()
print(one)
print(one.__class__)
属性相关
属性和变量的区别及判定依据?
区别概念变量是“可以改变的量值”属性是“属于某个对象的特性”访问权限变量:根据不同的位置,存在不同的访问权限全局变量局部变量...属性:只能通过对象来进行访问所以,必须先找到对象对象也是通过变量名来引用;而既然是变量,也有对应的访问权限
判定依据是否存在宿主
对象属性
怎样让一个对象拥有一些属性?(增)
1. 直接通过对象,动态添加语法:对象.属性 = 值
2. 通过类的初始化方法(构造方法)__init__方法
class Person:pass
p = Person()
p.age = 18
p.height = 180
print(p.age)
print(p.__dict__)
怎样访问一个对象的属性?(查)
一般访问对象.属性
如果访问不到会直接报错需要记住错误提示
怎样修改一个对象的属性?(改)
同新增一样;系统会自动识别,不存在则新增,存在则修改
语法对象.属性 = 值
class Person:pass
p = Person()
p.age = 18
p.height = 180
p.pets = ["小花", "小黑"]
print(p.pets, id(p.pets))p.pets.append("小黄")
print(p.pets, id(p.pets))
怎样删除一个对象的属性?(删)
del 对象.属性
class Person:pass
p.age = 18del p.age
print(p.age)
补充:
查看对象的所有属性?对象.__dict__
不同对象之间不能互相访问对方的属性
_*_ encoding:utf-8 _*_
class Person:passp1 = Person()
p2 = Person()p1.age = 18
p2.address = "上海"print(p1.__dict__)
print(p1.address)
类属性
万物皆对象,类也是一个对象比如,生产月饼的模板,对于月饼来说它是“类”但模板本身是不是也是一个具体的东西,也是由其他的东西创建出来的??
怎样让一个类拥有属性?(增)
方式1类名.类属性 = 值
方式2class Dog:dogCount = 0
class Money:pass
Money.count = 1
Money.age = 18
Money.num = 666print(Money.count)
print(Money.__dict__)class Money:age = 18count = 1num = 666
怎样查询一个类的属性?(查)
通过类访问类名.类属性
通过对象访问对象.类属性
注意:为什么可以通过对象访问到类属性?答:和Python对象的属性查找机制有关优先到对象自身去查找属性找到则结束如果没有找到则根据__class__找到对象对应的类到这个类里面查找
class Money:age = 18count = 1num = 666
one = Money()print(one.__class__)print(one.age)
print(one.count)
print(one.num)
class Test:sex = "男"class Money:age = 18count = 1num = 666one = Money()
one.sex = "女"
one.__class__ = Test
print(one.__class__)print(one.sex)
print(one.age)
怎样修改一个类的属性?(改)
通过类名改语法如同给类增加一个属性的方式1系统也会自动检测不存在,则新增存在,则修改类名.属性 = 值
能否通过对象改?不能!
class Money:age = 18count = 1num = 666Money.age = 22one = Money()
one.xxx = 999
print(one.xxx)one.age = 13
print(one.age)
print(Money.age)
print(one.__dict__)
怎样删除一个类的属性?(删)
通过类名删除del 类名.属性
能否通过对象删除?不能!del 语句只删除直系属性
class Money:age = 18count = 1num = 666one = Money()
del one.age
注意
类属性的内存存储问题一般情况下,属性存储在__dict__的字典当中有些内置对象没有这个__dict__属性一般对象可以直接修改__dict__属性但类对象的__dict__为只读;默认无法修改可以通过setattr方法修改
类属性被各个对象共享类属性修改之后,所有的对象访问到的类属性都会跟着修改
class Money:age = 18name = "sz"
补充
查看一个类的所有属性
类名.__dict__
对象属性和类属性之间的区别联系?
存储不同
抽象层级不同
宿主不同
案例考察类class Person:count = 1对象p = Person()问p.count += 1代码执行之后Person.count 与 p.count 打印的结果分别是多少?
如何限制对象的属性?
通过设置类属性:__slots__
这个属性是一个列表列表中的元素,即为通过这个类创建出的对象可以添加的对象属性如果这个类实例出的对象,添加了非列表之内的属性,则会报错
class person:__slots__ = ["age"]pass
p1 = person
p1.age = 1
p1.num = 2
方法相关
方法的概念
描述一个目标的行为动作比如描述一个人怎样吃,怎样喝,怎样玩...
和函数非常类似都封装了一系列行为动作都可以被调用的之后,执行一系列行为动作最主要的区别就是:调用方式
方法的划分
实例方法默认第一个参数需要接收到一个实例
类方法默认第一个参数需要接收到一个类
静态方法静静的看着前面俩装逼,第一个参数啥也不默认接收
注意1. 划分的依据是:方法的第一个参数必须要接收的数据类型2. 不管是哪一种类型的方法,都是存储在类当中;没有在实例当中的3. 不同类型方法的调用方式不同但,不管怎么调,把握一个原则不管是自己传递,还是解释器帮我们处理;最终要保证不同类型的方法第一个参数接收到的数据,是他们想要的类型
class Person:def eat2():print("这是一个实例方法")@classmethoddef leifangfa(cls):print("这是一个类方法", cls)@staticmethoddef jingtaifangfa():print("这是一个静态方法")p = Person()
print(p)
p.eat2()
Person.leifangfa()Person.jingtaifangfa()print(person.__dict__)
print(p.__dict__)def run():print("run")
p.age = run
print(p.__dict__)
实例方法
class Person:def run(self):pass
类调用注意必须传递一个对象,因为实例方法要求呀。该方法没有实际意义,相当于将实例方法当作函数在调用
对象调用【主流】不用手动传,解释器会默认把调用对象本身传递过去
注意一般使用对象来调用
class Person:def eat(self, food):print("在吃饭,",self, food)print("在吃饭,", food)def eat2():print("123")def eat3(xxx):print(xxx)p = Person()
print(p)
p.eat("土豆") print(Person.eat)Person.eat(123, "abc") func = Person.eat func("abc", 999)
p.eat3()
类方法
class Person:@classmethoddef countPerson(cls):pass
类调用不用手动传递第一个参数,会自动的把调用的类本身给传递过去
对象调用不用手动传递第一个参数,会自动的把调用的对象对应的类给传递过去
注意一般使用类来调用
class Person:@classmethoddef leifangfa(cls, a):print("这是一个类方法", cls, a)Person.leifangfa(123)p = Person()
p.leifangfa(666)func = Person.leifangfa
func(111)
class A(Person):pass
A.leifangfa(0)
静态方法
class Person:@staticemethoddef countPerson():pass
类调用直接调用就可以, 不需要考虑第一个参数
对象调用直接调用就可以
注意具体使用谁来调用,根据场景,哪个比较适合方便就使用哪个
class Person:@staticmethoddef jingtai():print("这是一个静态方法")Person.jingtai()
p = Person()
p.jingtai()func = Person.jingtai
func()
不同类型的方法访问不同类型的属性的规律
class Person:age = 0def shilifangfa(self):print(self)print(self.age)print(self.num)@classmethoddef leifangfa(cls):print(cls)print(cls.age)print(cls.num)@staticmethoddef jingtaifangfa():print(Person.age)p = Person()
p.num = 10p.shilifangfa()
Person.leifangfa()
Person.jingtaifangfa()
print(Person.age)
print(p.age)
print(p.num)
补充
函数和方法的区别?是否有宿主函数都是独立的个体,函数之间几乎没有共享的数据方法有宿主
self-注意点代表调用的对象
补充
类相关补充
元类
概念
创建类对象的类对象怎样产生的?由类创建出来的类是不是对象?是所以,类对象是不是由另外一个类创建出来的?是元类
结构图
num = 10print(num.__class__)s = "abc"
print(s.__class__)class Person:passp = Person()
print(p.__class__)print("-"*20)
print(int.__class__)
print(num.__class__.__class__) print(str.__class__) print(Person.__class__)
print(Person.__class__.__class__)
print(type.__class__)
类对象的创建方式以及创建流程
创建方式通过class 定义当我们这么写这个类描述的时候, 解释器会自动的帮我们创建对应的类对象通过type函数进行创建
类的创建流程1. 检测类中是否有明确 __metaclass__属性有, 则通过指定元类来创建这个类对象2. 检测父类中是否存在__metaclass__属性有, 则通过指定元类来创建这个类对象3. 检测模块中是否存在__metaclass__属性有, 则通过指定元类来创建这个类对象4. 通过内置的type这个元类,来创建这个类对象
class Person:count = 0def run(self):passnum = 10
print(type(num)) def run(self):print("---", self)xxx = type("Dog",(),{"count": 0, "run": run})
print(xxx)print(xxx.__dict__)d = xxx()
print(d)d.run()
class Test():pass
__metaclass__ = Test
class Animal:pass
class Person(Animal): passclass Dog(Animal):__metaclass__ = xxxpassprint(Person.__metaclass__)
元类的应用场景
1) 拦截类的创建
2) 修改类
3) 返回修改之后的类后面补充
类的描述
目的方便理清逻辑思路方便多人合作开发时的沟通方便生成项目文档...
描述方式直接在类的下方,使用三个 "双引号"对就可以需要注明类的作用, 以及类属性描述至于方法, 则直接在方法下,使用三个"双引号"对描述即可作用参数返回值
class Person:"""关于这个类的描述, 类的作用, 类的构造函数等等; 类属性的描述Attributes:count: int 代表是人的个数"""count = 1def run(self, distance, step):"""这个方法的作用效果:param distance: 参数的含义, 参数的类型int, 是否有默认值:param step::return: 返回的结果的含义(时间), 返回数据的类型int"""print("人在跑")return distance / stepdef __init__(self):self.__name = "sz"help(Person)def xxx():"""这是一个xxx函数, 有xxx作用:return:"""print("xxx")
生成项目文档(补充)方式1使用内置模块pydoc具体步骤前置步骤:打开控制台,进入当前项目所在目录查看文档描述python3 -m pydoc 模块名称启动本地服务, 浏览文档python3 -m pydoc -p 端口号eg:python3 -m pydoc -p 1234生成指定模块html文档python3 -m pydoc -w 模块名称
python3 --help //查看python3命令
python3 -m //以一个脚本的形式运行某个库文档
python3 -m pydoc -h //查看相关使用方式
方式2使用三方模块Sphinxepydocdoxygen具体步骤目前感兴趣了可以先自行研究后续讲完"包和模块"之后,会进行补充
属性相关补充
私有化属性
概念
是指将一些原本公开的属性设置权限, 只能小范围访问, 其他地方访问不了
意义
保证数据的安全性
提高代码的可维护性
注意
Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果
类属性(方法)和实例属性(方法)遵循相同的规则
x
公有属性 类内部访问 【√】子类内部访问 【√】模块内其他位置访问 【√】类访问父类派生类实例访问父类实例派生类实例跨模块访问 【√】import形式导入from 模块 import * 形式导入
class Animal:x = 10def test(self):print(Animal.__x)print(self.__x)passclass Dog(Animal):def test2(self):print(Dog.x)print(self.x)pass
a = Animal()
a.test()
d = Dog()
d.test2()
print(Animal.x)
print(Dog.x)
print(a.x)
print(d.x)a = 666import 私有化属性
print(a)from 私有化属性 import *
print(a)
_x
受保护属性类内部访问 【√】子类内部访问 【√】模块内其他位置访问 【警告】类访问父类派生类实例访问父类实例派生类实例跨模块访问import形式导入 【警告】from module import * 形式导入有__all__指明对应变量 【警告】没有__all__指明对应变量 【会报错】
class Animal:_x = 10def test(self):print(Animal._x)print(self._x)passclass Dog(Animal):def test2(self):print(Dog._x)print(self._x)pass
a = Animal()
a.test()
d = Dog()
d.test2()
print(Animal._x)
print(Dog._x)
print(a._x)
print(d._x)_a = 666
__all__ = ["_a"]
import 私有化属性
print(a) from 私有化属性 import *
print(a)
__x
私有属性类内部访问 【√】子类内部访问 【X】模块内其他位置访问 【X】类访问父类派生类实例访问父类实例派生类实例跨模块访问参照单下划线开头变量的访问原则
私有属性的实现机制名字重整(Name Mangling)重改__x为另外一个名称, 如_类名__x目的防止外界直接访问防止被子类同名称属性覆盖
应用场景数据保护数据过滤
class Animal:__x = 10def test(self):print(Animal.__x)print(self.__x)passclass Dog(Animal):def test2(self):print(Dog.__x)print(self.__x)pass
a = Animal()
a.test()
d = Dog()
d.test2()
print(Animal.__x)
print(Dog.__x)
print(a.__x)
print(d.__x) __a = 666
__all__ = ["_a"]
print(Animal.__dict__)
print(Animal._Animal__x)
import 私有化属性
print(私有化属性.__a) from 私有化属性 import *
print(__a)
```python
class Person:def __init__(self):self.__age = 18def setAge(self, value):if isinstance(value, int) and 0 < value < 200:self.__age = valueelse:print("你输入的数据有问题, 请重新输入")def getAge(self):return self.__agep1 = Person()
p1.setAge("abc")
print(p1.getAge())p2 = Person()p3 = Person()
补充
xx_"变量名_" 这个格式是为了与系统属性作区分
__xx__两端__一般为系统内置属性或方法, 所以以后命名注意避免
class_
__xx__
只读属性
概念一个属性(一般指实例属性), 只能读取, 不能写入
应用场景有些属性, 只限在内部根据不同场景进行修改, 而对外界来说, 不能修改, 只能读取比如电脑类的网速属性, 网络状态属性
方式1方案全部隐藏私有化既不能读也不能写部分公开公开读的操作具体实现私有化通过"属性前置双下划线"实现部分公开通过公开的方法优化property作用将一些"属性的操作方法"关联到某一个属性中概念补充经典类没有继承(object)新式类继承(object)Python2.x版本定义一个类时, 默认不继承(object)Python3.x版本定义一个类时, 默认继承(object)建议使用新式类property在经典类中只能管理一个属性的读取操作在新式类中可以管理一个属性的删改查操作方式2方案借助系统内置的方法进行拦截具体实现__setattr__方法当我们使用 "实例.属性 = 值" 这种格式给一个实例增加或修改属性的时候, 都会调用系统内置的这个方法在这个方法的内部, 才会真正的把属性以及对应的值给存储到 __dict__当中解决方案在这个方法中, 进行拦截
class Person(object):def __init__(self):self.__age = 18def getAge(self):return self.__agep1 = Person
print(p1.getAge())
class Person(object):def __init__(self):self.__age = 18@propertydef age(self):return self.__agep1 = Person()print(p1.age)
p1.age = 10
p1._Person__age = 999
p1.__dict__["_Person__age"] = 999 p1.__age = 999
print(p1.__dict__)
class Person(object):passprint(Person.__bases__)
class Person(object):def __init__(self):self.__age = 18def get_age(self):print("----, get")return self.__agedef set_age(self, value):print("----, set")self.__age = valueage = property(get_age, set_age)p = Person()
print(p.age)p.age = 90
print(p.age)print(p.__dict__)
class Person(object):def __init__(self):self.__age = 18@propertydef age(self):print("----- get")return self.__age@age.setterdef age(self, value):print("----- set")self.__age = valuep = Person()
print(p.age)p.age = 10
print(p.age)
class Person:def __init__(self):self.__age = 18def get_age(self):print("----, get")return self.__agedef set_age(self, value):print("----, set")self.__age = valueage = property(get_age, set_age)p = Person()
print p.agep.age = 19
print p.age
print p.__dict__
class Person:def __init__(self):self.__age = 18@propertydef age(self):print "-----get"return self.__age@age.setterdef age(self, value):self.__age = valuep = Person()
p.age = 19
print p.age
print p.__dict__
class Person:def __setattr__(self, key, value):print(key, value)if key == "age" and key in self.__dict__.keys():print("这个属性是只读属性, 不能设置数据")else:self.__dict__[key] = value
p1 = Person()
p1.age = 18
print(p1.age)p1.age = 999
print(p1.age)print(p1.__dict__)
内置特殊属性
类属性__dict__ : 类的属性__bases__ : 类的所有父类构成元组__doc__ :类的文档字符串__name__: 类名__module__: 类定义所在的模块
实例属性__dict__ : 实例的属性__class__: 实例对应的类
class Person:"""这是一个人, 类"""age = 19def __init__(self):self.name = "sz"def run(self):print("run")
print(Person.__dict__)
print(Person.__bases__)
print(Person.__doc__)
print(Person.__name__)
print(Person.__module__)p = Person()
print(p.__class__)
方法相关补充
私有化方法
私有方法def __方法():pass注意不要定义 "_类名__方法名" 这种方法
class Person:__age = 18def __run(self):print("pao")def _Person__run(self)print("Xxx")p = person
p.__Person_run()
print(Person.__dict__)
内置特殊方法
生命周期方法(下一小节单独介绍)
其他内置方法
信息格式化操作
__str__方法作用一个对象的描述字符串, 更加方便用户阅读, 对用户更友好触发方式print 打印一个对象时str() 函数时格式def __str__(self):return "描述信息"
class Person:def __init__(self, n, a):self.name = nself.age = adef __str__(self):return "这个人的姓名是%s, 这个人的年龄是:%s" % (self.name, self.age)p1 = Person("sz", 18)
print(p1)p2 = Person("zhangsan", 19)
print(p2)
__repr__方法作用一个对象的描述字符串, 更加方便机器处理, 对机器更友好(开发人员查看)触发方式当我们在交互模式下, 直接执行某个变量, 就会输出对应信息repr() 函数时格式def __repr__(self):return "描述信息"注意一般情况下, 应满足如下等式obj == eval(repr(obj))或者描述一个实例详细的信息(类名等等)
class Person:def __init__(self, n, a):self.name = nself.age = adef __str__(self):return "这个人的姓名是%s, 这个人的年龄是:%s" % (self.name, self.age)def __repr__(self):return "reprxxxxx"p1 = Person("sz", 18)
print(p1)p2 = Person("zhangsan", 19)
print(p2)s = str(p1)
print(s, type(s))print(repr(p1))import datetimet = datetime.datetime.now()
print(t)
print(repr(t))tmp = repr(t)result = eval(tmp)
print(result)
调用操作
__call__方法作用使得“对象”具备当做函数,来调用的能力使用1. 实现实例方法 __call__2. 那么创建好的实例, 就可以通过函数的形式来调用实例(参数)应用场景有点类似于之前所讲的"偏函数"的应用场景可以将"常变参数"和"不常变参数"进行分离案例不同类型的笔, 画不同的图形
class Person:def __call__(self, *args, **kwargs):print("xxx", args, kwargs)passp = Person()p(123, 456, name="sz")
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "红色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "黄色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "青色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "绿色"))
print("创建了一个%s这个类型的画笔, 它是%s颜色" % ("钢笔", "橘色"))
def createPen(p_color, p_type):print("创建了一个%s这个类型的画笔, 它是%s颜色" % (p_type, p_color))createPen("钢笔", "红色")
createPen("钢笔", "绿色")
createPen("钢笔", "黄色")
import functoolsgangbiFunc = functools.partial(createPen, p_type="钢笔")gangbiFunc("红色")
gangbiFunc("黄色")
gangbiFunc("绿色")
class PenFactory:def __init__(self, p_type):self.p_type = p_typedef __call__(self, p_color):print("创建了一个%s这个类型的画笔, 它是%s颜色" % (self.p_type, p_color))gangbiF = PenFactory("钢笔")
gangbiF("红色")
gangbiF("绿色")
gangbiF("黄色")qianbiF = PenFactory("铅笔")
qianbiF("红色")
qianbiF("绿色")
qianbiF("黄色")
索引操作
作用可以对一个实例对象进行索引操作
步骤1. 实现三个内置方法设置元素的方法def __setitem__(self, key, value):获取元素的方法def __getitem__(self, item):删除元素的方法def __delitem__(self, key):2. 可以以索引的形式操作对象增/改p[1] = 666p["name"] = "sz"查p["name"]p[1]删del p["name"]del p[1]
class Person:def __init__(self):self.cache = {}def __setitem__(self, key, value):self.cache[key] = valuedef __getitem__(self, item):return self.cache[item]def __delitem__(self, key):del self.cache[key]p = Person()
p["name"] = "sz"print(p["name"])del p["name"]print(p["name"])
print(p.cache)
切片操作
作用可以对一个实例对象进行切片操作
步骤Python2.x1. 实现三个内置方法__setspice__设置某个元素切片时调用__getspice__获取某个元素切片时调用__delspice__删除某个元素切片时调用2. 可以直接按照切片的方式操作对象p[1, 6, 2]注意: 过期Python3.x统一由"索引操作"进行管理def __setitem__(self, key, value):def __getitem__(self, item):def __delitem__(self, key):
l = [1, 2, 3, 4, 5]
print(l[3])
print(l[1: 4: 2])class Person:def __init__(self):self.items = [1, 2, 3, 4, 5, 6, 7, 8]def __setitem__(self, key, value):if isinstance(key, slice):self.items[key.start: key.stop: key.step] = valuedef __getitem__(self, item):print("getitem", item)def __delitem__(self, key):print("delitem", key)p = Person()
p[0: 4: 2] = ["a", "b"]
print(p.items)
p[0: 5: 2]
del p[0: 5: 2]
比较操作
作用可以自定义对象 "比较大小, 相等以及真假" 规则
步骤实现6个方法相等__eq__不相等__ne__小于__lt__小于或等于__le__大于__gt__大于或等于__ge__
注意如果对于反向操作的比较符, 只定义了其中一个方法但使用的是另外一种比较运算那么, 解释器会采用调换参数的方式进行调用该方法例如定义了 "小于" 操作x < y使用 x > y会被调换参数, 调用上面的 "小于操作"但是, 不支持叠加操作例如定义了 "小于" 和 "等于" 操作不能使用 x <= y
补充使用装饰器, 自动生成"反向" "组合"的方法步骤1. 使用装饰器装饰类@functools.total_ordering2. 实现> 或 >= 或 < 或 <= 其中一个实现 ==上下文环境中的布尔值__bool__
class Person:def __init__(self, age, height):self.age = ageself.height = heightdef __eq__(self, other):print("eq")return self.age == other.agedef __ne__(self, other):passdef __gt__(self, other):passdef __ge__(self, other):passdef __lt__(self, other):print(self.age)print(other.age)return self.age < other.agedef __le__(self, other):passp1 = Person(18, 190)
p2 = Person(19, 190)
print(p1 < p2)
print(p1 <= p2)
print(p1 == p2)
print(p1 != p2)
print(p1 <= p2) import functools@functools.total_ordering
class Person:def __lt__(self, other):print("lt")return Falsedef __eq__(self, other):print("eq")passp1 = Person()
p2 = Person()print(p1 <= p2)print(Person.__dict__)class Person:def __init__(self):self.age = 20def __bool__(self):return self.age >= 18passp = Person()if p:print("xx")
遍历操作
怎样让我们自己创建的对象可以使用for in 进行遍历?实现__getitem__方法优先级低每次for in 获取数据时, 都会调用这个方法或者实现__iter__方法优先级高这个方法, 必须返回一个"迭代器"; 即, 具备"__iter__"和"__next__"方法当for in 遍历这个对象时, 会调用这个__iter__方法返回的迭代器对象的__next__方法
怎样让我们自己创建的对象可以使用next函数进行访问?实现__next__方法
补充1. __iter__方法可以恢复迭代器的初始化值, 复用迭代器2. "可迭代" 与 "迭代器"必须实现的方法3. iter方法的使用
class Person:def __init__(self):self.result = 1def __getitem__(self, item):self.result += 1if self.result >= 6:raise StopIteration("停止遍历")return self.resultpassp = Person()for i in p:print(i)
class Person:def __init__(self):self.result = 1def __iter__(self):print("iter")self.result = 1return self def __next__(self):self.result += 1if self.result >= 6:raise StopIteration("停止遍历")return self.resultp = Person()
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))result = next(p)
while result:print(result)result = next(p)class Person:def __init__(self):self.age = 1def __getitem__(self, item):return 1def __iter__(self):self.age = 1 return selfdef __next__(self):self.age += 1if self.age >= 6:raise StopIteration("stop")return self.agenext()
p = Person()for i in p:print(i)
print(p.age)
for i in p:print(i)import collections
print(isinstance(p, collections.Iterator))
print(isinstance(p, collections.Iterable))
class Person:def __init__(self):self.age = 1def __getitem__(self, item):self.age += 1if self.age >= 6:raise StopIteration("stop")return self.agedef __iter__(self):self.age = 1 return selfdef __next__(self):self.age += 1if self.age >= 6:raise StopIteration("stop")return self.agedef __call__(self, *args, **kwargs):self.age += 1if self.age >= 6:raise StopIteration("stop")return self.age
p = Person()pt = iter(p)
pt = iter(p.__next__, 4)
pt = iter(p, 4) print(pt is p)for i in pt:print(i)l = [1, 2, 3]
lt = iter(l)
print(lt)
描述器
概念可以描述一个属性操作的对象对象属性的操作增/改删查描述
作用可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等如果一个类属性被定义为描述器,那么以后对这个类属性的操作(读写删), 都将由这个描述器代理
定义定义方式1property定义方式2三个方法__get____set____delete__
调用细节使用实例进行调用最多三个方法都会被调用使用类进行调用最多会调用get方法不能够顺利转换的场景新式类和经典类描述器仅在新式类中生效方法拦截一个实例属性的正常访问顺序实例对象自身的__dict__字典对应类对象的__dict__字典如果有父类, 会再往上层的__dict__字典中检测如果没找到, 又定义了__getattr__方法, 就会调用这个方法而在上述的整个过程当中, 是如何将描述器的__get__方法给嵌入到查找机制当中?就是通过这个方法进行实现__getattribute__内部实现模拟如果实现了描述器方法__get__就会直接调用如果没有, 则按照上面的机制去查找
注意"资料描述器"和"非资料描述器"如果实现了_get__如果实现了__get____set__描述器和实例属性同名时, 操作的优先级问题资料描述器 > 实例字典 > 非资料描述器
help(Person)class Person:def __init__(self):self.__age = 10@propertydef age(self):return self.__age@age.setterdef age(self, value):if value < 0:value = 0self.__age = value@age.deleterdef age(self):print("del age")del self.__agep = Person()
p.age = 19
del p.age
print(p.age)class Age:def __get__(self, instance, owner):print("get")def __set__(self, instance, value):print("set")def __delete__(self, instance):print("delete")class Person:age = Age() def __init__(self):self.__age = 10def get_age(self):return self.__age@age.setterdef set_age(self, value):if value < 0:value = 0self.__age = value@age.deleterdef del_age(self):print("del age")del self.__ageage = property(get_age, set_age, del_age)p = Person()
p.age = 10
print(p.age)
del p.age
class Age(object):def __get__(self, instance, owner):print("get")def __set__(self, instance, value):print("set")def __delete__(self, instance):print("delete")class Person(object):age = Age()def __getattribute__(self, item):print "xxxxx"p = Person()p.age = 10
print(p.age)
del p.ageprint(Person.age)
Person.age = 19
del Person.age
class Age(object):def __get__(self, instance, owner):print("get")def __set__(self, instance, value):print("set")def __delete__(self, instance):print("delete")class Person(object):age = Age()def __init__(self):self.age = 10p = Person()p.age = 10
print(p.age)
del p.ageprint(p.__dict__)
class Person:def __init__(self):self.__age = 10def get_age(self):return self.__agedef set_age(self, value):if value < 0:value = 0self.__age = valuedef del_age(self):print("del age")del self.__ageage = property(get_age, set_age, del_age)p = Person()
p.age = 10
print(p.age)
del p.ageclass Age(object):def __get__(self, instance, owner):print("get")return instance.vdef __set__(self, instance, value):print("set", self, instance, value)instance.v = valuedef __delete__(self, instance):print("delete")del instance.vclass Person(object):age = Age()p = Person()
p.age = 10
print(p.age)
del p.agep2 = Person()
p2.age = 11
print(p2.age)
print(p.age)
装饰器
使用类当做装饰器来使用
class check:def __init__(self, func):self.f = funcdef __call__(self, *args, **kwargs):print("登录验证")self.f()@check
def fashuoshuo():print("发说说")
fashuoshuo()x = "abc"
y = [x]
z = [x, y]
import objgraph
objgraph.show_refs(z, filename="test.png")