如何定义一个类?
class 类名:
pass
怎样通过类,创建出一个对象?
根据类创建对象
one = Money()
执行流程
1. 类的定义
2. 根据类,创建出一个对象
3. 将对象的唯一标识返回
class Money :
pass
print ( 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 = 18
del p. age
print ( p. age)
补充:
查看对象的所有属性?
对象.__dict__
不同对象之间不能互相访问对方的属性
_* _ encoding: utf- 8 _* _
class Person :
pass
p1 = Person( )
p2 = Person( )
p1. age = 18
p2. address = "上海"
print ( p1. __dict__)
print ( p1. address)
类属性
万物皆对象,类也是一个对象
比如,生产月饼的模板,对于月饼来说它是“类”
但模板本身是不是也是一个具体的东西,也是由其他的东西创建出来的??
怎样让一个类拥有属性?(增)
方式1
类名.类属性 = 值
方式2
class Dog:
dogCount = 0
class Money :
pass
Money. count = 1
Money. age = 18
Money. num = 666
print ( Money. count)
print ( Money. __dict__)
class Money :
age = 18
count = 1
num = 666
怎样查询一个类的属性?(查)
通过类访问
类名.类属性
通过对象访问
对象.类属性
注意:
为什么可以通过对象访问到类属性?
答:和Python对象的属性查找机制有关
优先到对象自身去查找属性
找到则结束
如果没有找到
则根据__class__找到对象对应的类
到这个类里面查找
class Money :
age = 18
count = 1
num = 666
one = Money( )
print ( one. __class__)
print ( one. age)
print ( one. count)
print ( one. num)
class Test :
sex = "男"
class Money :
age = 18
count = 1
num = 666
one = Money( )
one. sex = "女"
one. __class__ = Test
print ( one. __class__)
print ( one. sex)
print ( one. age)
怎样修改一个类的属性?(改)
通过类名改
语法如同给类增加一个属性的方式1
系统也会自动检测
不存在,则新增
存在,则修改
类名.属性 = 值
能否通过对象改?
不能!
class Money :
age = 18
count = 1
num = 666
Money. age = 22
one = Money( )
one. xxx = 999
print ( one. xxx)
one. age = 13
print ( one. age)
print ( Money. age)
print ( one. __dict__)
怎样删除一个类的属性?(删)
通过类名删除
del 类名.属性
能否通过对象删除?
不能!
del 语句只删除直系属性
class Money :
age = 18
count = 1
num = 666
one = Money( )
del one. age
注意
类属性的内存存储问题
一般情况下,属性存储在__dict__的字典当中
有些内置对象没有这个__dict__属性
一般对象可以直接修改__dict__属性
但类对象的__dict__为只读;默认无法修改
可以通过setattr方法修改
类属性被各个对象共享
类属性修改之后,所有的对象访问到的类属性都会跟着修改
class Money :
age = 18
name = "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 ( "这是一个实例方法" )
@classmethod
def leifangfa ( cls) :
print ( "这是一个类方法" , cls)
@staticmethod
def 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:
@classmethod
def countPerson(cls):
pass
类调用
不用手动传递第一个参数,会自动的把调用的类本身给传递过去
对象调用
不用手动传递第一个参数,会自动的把调用的对象对应的类给传递过去
注意
一般使用类来调用
class Person :
@classmethod
def 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:
@staticemethod
def countPerson():
pass
类调用
直接调用就可以, 不需要考虑第一个参数
对象调用
直接调用就可以
注意
具体使用谁来调用,根据场景,哪个比较适合方便就使用哪个
class Person :
@staticmethod
def jingtai ( ) :
print ( "这是一个静态方法" )
Person. jingtai( )
p = Person( )
p. jingtai( )
func = Person. jingtai
func( )
不同类型的方法访问不同类型的属性的规律
class Person :
age = 0
def shilifangfa ( self) :
print ( self)
print ( self. age)
print ( self. num)
@classmethod
def leifangfa ( cls) :
print ( cls)
print ( cls. age)
print ( cls. num)
@staticmethod
def jingtaifangfa ( ) :
print ( Person. age)
p = Person( )
p. num = 10
p. shilifangfa( )
Person. leifangfa( )
Person. jingtaifangfa( )
print ( Person. age)
print ( p. age)
print ( p. num)
补充
函数和方法的区别?
是否有宿主
函数都是独立的个体,函数之间几乎没有共享的数据
方法有宿主
self-注意点
代表调用的对象
补充
类相关补充
元类
概念
创建类对象的类
对象怎样产生的?
由类创建出来的
类是不是对象?
是
所以,类对象是不是由另外一个类创建出来的?
是
元类
结构图
num = 10
print ( num. __class__)
s = "abc"
print ( s. __class__)
class Person :
pass
p = 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 = 0
def run ( self) :
pass
num = 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) :
pass
class Dog ( Animal) :
__metaclass__ = xxx
pass
print ( Person. __metaclass__)
元类的应用场景
1) 拦截类的创建
2) 修改类
3) 返回修改之后的类
后面补充
类的描述
目的
方便理清逻辑思路
方便多人合作开发时的沟通
方便生成项目文档
...
描述方式
直接在类的下方,使用三个 "双引号"对就可以
需要注明类的作用, 以及类属性描述
至于方法, 则直接在方法下,使用三个"双引号"对描述即可
作用
参数
返回值
class Person :
"""
关于这个类的描述, 类的作用, 类的构造函数等等; 类属性的描述
Attributes:
count: int 代表是人的个数
"""
count = 1
def run ( self, distance, step) :
"""
这个方法的作用效果
:param distance: 参数的含义, 参数的类型int, 是否有默认值
:param step:
:return: 返回的结果的含义(时间), 返回数据的类型int
"""
print ( "人在跑" )
return distance / step
def __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
使用三方模块
Sphinx
epydoc
doxygen
具体步骤
目前感兴趣了可以先自行研究
后续讲完"包和模块"之后,会进行补充
属性相关补充
私有化属性
概念
是指将一些原本公开的属性设置权限, 只能小范围访问, 其他地方访问不了
意义
保证数据的安全性
提高代码的可维护性
注意
Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果
类属性(方法)和实例属性(方法)遵循相同的规则
x
公有属性
类内部访问 【√】
子类内部访问 【√】
模块内其他位置访问 【√】
类访问
父类
派生类
实例访问
父类实例
派生类实例
跨模块访问 【√】
import形式导入
from 模块 import * 形式导入
class Animal :
x = 10
def test ( self) :
print ( Animal. __x)
print ( self. __x)
pass
class 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
import 私有化属性
print ( a)
from 私有化属性 import *
print ( a)
_x
受保护属性
类内部访问 【√】
子类内部访问 【√】
模块内其他位置访问 【警告】
类访问
父类
派生类
实例访问
父类实例
派生类实例
跨模块访问
import形式导入 【警告】
from module import * 形式导入
有__all__指明对应变量 【警告】
没有__all__指明对应变量 【会报错】
class Animal :
_x = 10
def test ( self) :
print ( Animal. _x)
print ( self. _x)
pass
class 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 = 10
def test ( self) :
print ( Animal. __x)
print ( self. __x)
pass
class 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 = 18
def setAge ( self, value) :
if isinstance ( value, int ) and 0 < value < 200 :
self. __age = value
else :
print ( "你输入的数据有问题, 请重新输入" )
def getAge ( self) :
return self. __age
p1 = 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 = 18
def getAge ( self) :
return self. __age
p1 = Person
print ( p1. getAge( ) )
class Person ( object ) :
def __init__ ( self) :
self. __age = 18
@property
def age ( self) :
return self. __age
p1 = 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 ) :
pass
print ( Person. __bases__)
class Person ( object ) :
def __init__ ( self) :
self. __age = 18
def get_age ( self) :
print ( "----, get" )
return self. __age
def set_age ( self, value) :
print ( "----, set" )
self. __age = value
age = 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
@property
def age ( self) :
print ( "----- get" )
return self. __age
@age. setter
def age ( self, value) :
print ( "----- set" )
self. __age = value
p = Person( )
print ( p. age)
p. age = 10
print ( p. age)
class Person :
def __init__ ( self) :
self. __age = 18
def get_age ( self) :
print ( "----, get" )
return self. __age
def set_age ( self, value) :
print ( "----, set" )
self. __age = value
age = property ( get_age, set_age)
p = Person( )
print p. age
p. age = 19
print p. age
print p. __dict__
class Person :
def __init__ ( self) :
self. __age = 18
@property
def age ( self) :
print "-----get"
return self. __age
@age. setter
def age ( self, value) :
self. __age = value
p = 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 = 19
def __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 = 18
def __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 = n
self. age = a
def __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 = n
self. age = a
def __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 datetime
t = 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)
pass
p = 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 functools
gangbiFunc = functools. partial( createPen, p_type= "钢笔" )
gangbiFunc( "红色" )
gangbiFunc( "黄色" )
gangbiFunc( "绿色" )
class PenFactory :
def __init__ ( self, p_type) :
self. p_type = p_type
def __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] = 666
p["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] = value
def __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.x
1. 实现三个内置方法
__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] = value
def __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_ordering
2. 实现
> 或 >= 或 < 或 <= 其中一个
实现 ==
上下文环境中的布尔值
__bool__
class Person :
def __init__ ( self, age, height) :
self. age = age
self. height = height
def __eq__ ( self, other) :
print ( "eq" )
return self. age == other. age
def __ne__ ( self, other) :
pass
def __gt__ ( self, other) :
pass
def __ge__ ( self, other) :
pass
def __lt__ ( self, other) :
print ( self. age)
print ( other. age)
return self. age < other. age
def __le__ ( self, other) :
pass
p1 = 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 False
def __eq__ ( self, other) :
print ( "eq" )
pass
p1 = Person( )
p2 = Person( )
print ( p1 <= p2)
print ( Person. __dict__)
class Person :
def __init__ ( self) :
self. age = 20
def __bool__ ( self) :
return self. age >= 18
pass
p = 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 = 1
def __getitem__ ( self, item) :
self. result += 1
if self. result >= 6 :
raise StopIteration( "停止遍历" )
return self. result
pass
p = Person( )
for i in p:
print ( i)
class Person :
def __init__ ( self) :
self. result = 1
def __iter__ ( self) :
print ( "iter" )
self. result = 1
return self
def __next__ ( self) :
self. result += 1
if self. result >= 6 :
raise StopIteration( "停止遍历" )
return self. result
p = 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 = 1
def __getitem__ ( self, item) :
return 1
def __iter__ ( self) :
self. age = 1
return self
def __next__ ( self) :
self. age += 1
if self. age >= 6 :
raise StopIteration( "stop" )
return self. age
next ( )
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 = 1
def __getitem__ ( self, item) :
self. age += 1
if self. age >= 6 :
raise StopIteration( "stop" )
return self. age
def __iter__ ( self) :
self. age = 1
return self
def __next__ ( self) :
self. age += 1
if self. age >= 6 :
raise StopIteration( "stop" )
return self. age
def __call__ ( self, * args, ** kwargs) :
self. age += 1
if 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)
描述器
概念
可以描述一个属性操作的对象
对象
属性的操作
增/改
删
查
描述
作用
可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等
如果一个类属性被定义为描述器,那么以后对这个类属性的操作(读写删), 都将由这个描述器代理
定义
定义方式1
property
定义方式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
@property
def age ( self) :
return self. __age
@age. setter
def age ( self, value) :
if value < 0 :
value = 0
self. __age = value
@age. deleter
def age ( self) :
print ( "del age" )
del self. __age
p = 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 = 10
def get_age ( self) :
return self. __age
@age. setter
def set_age ( self, value) :
if value < 0 :
value = 0
self. __age = value
@age. deleter
def del_age ( self) :
print ( "del age" )
del self. __age
age = 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. age
print ( 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 = 10
p = Person( )
p. age = 10
print ( p. age)
del p. age
print ( p. __dict__)
class Person :
def __init__ ( self) :
self. __age = 10
def get_age ( self) :
return self. __age
def set_age ( self, value) :
if value < 0 :
value = 0
self. __age = value
def del_age ( self) :
print ( "del age" )
del self. __age
age = 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" )
return instance. v
def __set__ ( self, instance, value) :
print ( "set" , self, instance, value)
instance. v = value
def __delete__ ( self, instance) :
print ( "delete" )
del instance. v
class Person ( object ) :
age = Age( )
p = Person( )
p. age = 10
print ( p. age)
del p. age
p2 = Person( )
p2. age = 11
print ( p2. age)
print ( p. age)
装饰器
使用类当做装饰器来使用
class check :
def __init__ ( self, func) :
self. f = func
def __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" )