面向对象编程(二)——Python
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
Python面向对象自学笔记
接上————在面向对象在Python中的运用,此时表示方法的补充中如下:
补充(34-82)
类相关补充
1、元类(type型):结构图2、生成项目文件/类的描述及生成html(37-38)
属性相关补充
私有化属性
1、概念
2、意义
3、注意
4、x 公有属性
5、_y 受保护属性
6、__z 私有属性
私有属性的实现机制——名字重整(Name Mangling),重改__x为另外一个名称, 如_类名__x
应用场景:
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()
p2 = Person()
p1.setAge(20)
print(p1.getAge())
p2.setAge(240)
print(p2.getAge())
只读属性(主要应用在实例属性)
有些属性, 只限在内部根据不同场景进行修改, 而对外界来说, 不能修改, 只能读取
1、方案一:
私有化的部分:通过"属性前置双下划线"实现
部分公开:优化-加装饰器@property
eg:
class Person(object):
def __init__(self):
self.__age = 18
# 主要作用就是, 可以以使用属性的方式, 来使用这个方法
#将一些"属性的操作方法"关联到某一个属性中
@property
def age(self):
return self.__age
p1 = Person()
# p1._Person__age = 999
p1.__dict__["_Person__age"] = 999
print(p1.age)
print(p1.__dict__)
输出:
999
{’_Person__age’: 999}
经典类和新式类
经典类:没有继承object
新式类:继承object
且:在python2中,定义一个类,没有显式的继承自object,那么这个类就是一个继承类,显式的继承自object,他才是一个新式类。
在python3中,定义一个类,会隐式的继承object,所以默认情况下,就已经是一个新式类。
建议,无论在python2和3,都显式的继承object。
property的作用
将一些"属性的操作方法"关联到某一个属性中,即将一个属性的删改查关联到不同方法里面。
官方文档解释:
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
Property attribute.
fget
function to be used for getting an attribute value
fset
function to be used for setting an attribute value
fdel
function to be used for del'ing an attribute
doc
docstring
property作为函数在新式类的使用方法(用例出自视频)
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__)
输出:
----, get
----, set
----, get
{’_Person__age’: 90}
property作为装饰器在新式类的使用方法(用例出自视频)
官方文档
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
"""
视频用例:
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)
property在经典类中的使用(切换版版本为python2)
在经典类中,property只会关联读取方法,不会关联设置和删除方法。
一般不用
2、方案二:
关键在只读两个要求:(1)可以读取。(2)不能写入
故,引入__setattr__(self, key, value):
有这一步操作
class Person:
# 当我们通过 "实例.属性 = 值", 给一个实例增加一个属性, 或者说, 修改一下属性值的时候, 都会调用这个方法
# 在这个方法内部, 才会真正的把, 这个属性, 以及对应的数据, 给存储到__dict__字典里面
def __setattr__(self, key, value):
print(key, value)
# 1. 判定, key, 是否是我们要设置的只读属性的名称
if key == "age" and key in self.__dict__.keys():
print("这个属性是只读属性, 不能设置数据")
# 2. 如果说不是, 只读属性的名称, 真正的给它添加到这个实例里面去
else:
# self.key = value
self.__dict__[key] = value
p1 = Person()
p1.age = 18
print(p1.age)
print(p1.__dict__)
重点:由上例
if key == “age” and key in self.dict.keys():
解释:self.dict.keys()——字典型
使得一开始该字典中无age然后继续循环故第一次添加成功,后字典中有了age故只读取。
系统内置特殊属性
(1)类属性
__dict__:类属性
__bases__:类的所有父类构成元组
__doc__类的文档字符
__name__类名
__module__类定义所在模块
(2)实例属性
__dict__:类的实例
__class__:实例对应的类
方法相关补充
私有化方法
在函数名前加两个下划线,与属性私有化相同,名字重整机制是相同的。
def __方法():
pass
注意:不要定义 “_类名__方法名” 这种方法
内置特殊方法(完成特定功能)
- 信息格式化操作
(1)、__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)
s = str(p1)
print(s, type(s))
(2)__repr__面向开发人员
def __repr__(self):
return "描述
触发__str__的方法:
直接打印:print(p1)
str方法:s=str(p1) print(s)
触发__repr__的方法:
s=repr(p1) print(s)
在交互模式里面将对象名称写出,敲回车
- 调用操作(
__call__)
使得“对象”具备当做函数,来调用的能力——即将函数变成类的方法
实例:
class Person:
def __call__(self, *args, **kwargs):
print("xxx", args, kwargs)
pass
p = Person()
p(123, 456, name="sz")
输出:
xxx (123, 456) {‘name’: ‘sz’} (元组加字典)
应用场景:
可以将"常变参数"和"不常变参数"进行分离
- 索引操作—— 可以对一个实例对象进行索引操作
(使对象与字典相似)
实例:
class Person:
def __init__(self):
self.cache = {}#初始化一个字典
def __setitem__(self, key, value):
# print("setitem", key, value)
self.cache[key] = value#对字典中的key进行操作
def __getitem__(self, item):
# print("getitem", item)
return self.cache[item]
def __delitem__(self, key):
# print("delitem", key)
del self.cache[key]
p = Person()
p["name"] = "sz"#执行这行代码的时候,会调用第一个方法
print(p["name"])#调用第二个方法
del p["name"]#调用第三个方法
print(p.cache)
输出:
sz
{}
对上述实例的解释:注释掉的那一版操作会有一个后果——就是value传不进sz无法有索引key操作。因此需要一个字典属性,才可以对对象进行索引操作
- 切片操作
主要在python3中,‘切片操作’统一由‘索引操作’进行管理!
def __setitem__(self, key, value):
def __getitem__(self, item):
def __delitem__(self, key):
- 比较操作
可以自定义对象 “比较大小, 相等以及真假” 规则。有六种方法:< , > , == , >= , <= , != .
一、使对象可以像数一样被比较
class Person:
def __init__(self, age, height):
self.age = age
self.height = height#先初始化
def __eq__(self, other):
return self.age == other.age #指定相等的比较通过哪个属性比较,
def __ne__(self, other):
return self.age != other.age #指定相等的比较通过哪个属性比较,
def __gt__(self, other):# >
pass
def __ge__(self, other):# >=
pass
def __lt__(self, other):# <
# print("lt")
print(self.age)
print(other.age)
return self.age < other.age
def __le__(self, other):# <=
pass
p1 = Person(18, 180)
p2 = Person(19, 183)
print(p1 == p2)
#可以通过调换参数的方式定义比较方法,进而简化代码
注意
如果对于反向操作的比较符, 只定义了其中一个方法,但使用的是另外一种比较运算,那么, 解释器会采用调换参数的方式进行调用该方法。
二、也可以通过装饰器自动补全
import functools
@functools.total_ordering
class Person:
def __lt__(self, other):
print("lt")
# pass
return False
def __eq__(self, other):
print("eq")
pass
- 遍历操作
一、创建对象利用for-in循环遍历,可分为:
实现__getitem__方法,优先级低
实例:
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)
实现__iter__方法,优先级高
实例:
class Person:
def __init__(self):
self.result = 1
def __iter__(self):
print("iter")
self.result = 1
# return iter([1, 2, 3, 4, 5])
return self
def __next__(self):
self.result += 1
if self.result >= 6:
raise StopIteration("停止遍历")
return self.result
p = Person()
for i in p:
print(i)
二、通过返回一个迭代器,__next__方法
如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有__next__方法,其是迭代器。可迭代对象包含迭代器。
定义可迭代对象,必须实现__iter__方法;
定义迭代器,必须实现__iter__和__next__方法。
实例:
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)
import collections #导入集合模块
print(isinstance(p, collections.Iterator))
#True是迭代器,即输出bool值判断这个实例是否是迭代器
print(isinstance(p, collections.Iterable))#判断是不是可迭代对象
- 描述器
一、概念:可以描述一个属性操作的对象——即类里面有一个属性,属性指向一个特殊的对象,只要这个对象可以实现三个特殊的实例方法(__set__、__get__、__delete__)这个对象就是一个描述器。
二、作用:可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等。
三、实现:
方式一、用property:
实例:
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
输出:del 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()
p = Person()
p.age = 10
print(p.age)
del p.age
四、调用细节:
1、使用实例进行调用时:最多三个方法都会调用。
2、使用类进行调用时:最多只会调用get方法。
3、描述器只在新式类可以可以生效。
4、方法拦截:__getattribute__通过这个生效,使只能实现get方法。 (此处不太明白,留待后续细看)
资料描述器 get set
非资料描述器 仅仅实现了 get 方法, 那么他就是一个非资料描述器
资料描述器 > 实例属性 > 非资料描述器
五、由描述器的数据存储问题:
先引入实例:
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
p2 = Person()
p2.age = 11
输出结果:
set <main.Age object at 0x000001CDBA867FD0> <main.Person object at 0x000001CDBA867FA0> 10
set <main.Age object at 0x000001CDBA867FD0> <main.Person object at 0x000001CDBA867DC0> 11
由此发现,类属性Age是多个实例对象公用的,因此在set方法里面是对 instance进行操作。
instance.v = value
- 装饰器
使用类当做装饰器来使用。即使用闭包函数进行。
实例:
class check:
def __init__(self, func):
self.f = func
def __call__(self, *args, **kwargs):
print("登录验证")
self.f()
@check
def fashuoshuo():
print("发说说")
# fashuoshuo = check(fashuoshuo)
fashuoshuo()

浙公网安备 33010602011771号