属性访问函数
注意函数参数中的属性需要用"" 括起来。
class Person:
height = 100
def __init__(self):
self.name = "ice"
self.age = 19
self.sex = "man"
hasattr()
用于判断属性是否存在。
print(hasattr(ps, "name"))
print(hasattr(Person, "height"))
getattr
得到属性值,没有则报错。
name2 = getattr(ps, "name")
print(name2)
setattr
设置属性值
setattr(ps, "name", "冰鸽")
print(ps.name)
setattr(ps, "height", 180)
print(ps.height)
delattr
删除属性
delattr(ps, "height")
print(hasattr(ps, "height"))
delattr(ps, "height")
所以我们可以使用hasattr() 函数防止报错,这里就不做演示了。
对象的关系方法
1.子类判断
issubclass 用来判断一个类是不是另一个类的子类。如下,Person类是object类的子类。
print(issubclass(Person, object))
2.实例判断
isinstance 用来判断一个对象是不是一个类的实例化对象。
ps = Person()
print(isinstance(ps, Person))
print(5, (int, float))
一些魔法方法
1.new函数
def __new__(cls, *args, **kwargs):
print("该方法在实例化之前自动执行")
由于方法在实例化前自动执行,所以该方法的第一个参数是cls,而不是self。并且调用new函数时将不会有实例化对象产生。当然也可以创建实例化对象,此时就需要调用object类的new方法:
def __new__(cls, *args, **kwargs):
print("该方法在实例化之前自动执行")
return super().__new__(cls)
因为object类的new方法是可以创建实例对象,但注意需要使用return返回。
2.单例模式
无论进行多少次实例化,得到的对象永远是唯一的一个。结合所学的hasattr函数可以完成所述操作。
def __new__(cls, *args, **kwargs):
print("该方法在实例化之前自动执行")
if not hasattr(cls, "instance") :
cls.instance = super().__new__(cls)
return cls.instance
解析:每次进行实例化前都会执行new函数返回instance变量,但是在第二次调用时其返回的instance变量是第一次的结果,所以每次实例化的对象总是同一个。
3.重写输出方法
使用str函数可以实现,重写输出方法。
def __str__(self):
return "这是重写的输出方法"
print(ps)
4.查看类的函数
使用dir函数可以查看到某个类的所有函数。
print(dir(Person))
其中若含有__iter__ 该方法则代表该类可以被迭代,显然Person类是不能被迭代的。
协议与合同
协议需要两个或以上的魔法方法组成。 可迭代对象有:列表、元组、字符串,而迭代协议就是魔法方法__iter__
1.序列协议
序列协议需要len 方法
class Person:
def __init__(self, *args):
self.args = args
def __len__(self):
return len(self.args)
ps = Person(1, 4, 5, 2, 4, 7)
print(len(ps))
实际上len获取到的长度就是传入元组的长度。但是此时Person类还不能像列表那样进行下标取值。这需要签订getitem 协议。
def __getitem__(self, item):
return self.args[item]
print(ps[0])
2.迭代器协议
上面已经提到了该协议需要__iter__ 方法。当然其实还需要__next__ 协议才能迭代。
li = [1, 2, 3]
f = li.__iter__()
print(next(f))
print(next(f))
print(next(f))
print(next(f))
以上是列表的例子,学习他我们编写自己的协议。
class Number:
def __init__(self, end):
self.start = -1
self.end = end
def __iter__(self):
return self
def __next__(self):
self.start += 1
if self.start >= self.end:
raise StopIteration
return self.start
num = Number(10)
for i in num:
print(i)
3.上下文协议
enter和exit 方法是该协议需要的方法,enter方法在程序执行之前就会执行,而exit方法在程序结束的时候才会自动执行。并且程序需通过with触发上下问协议。
import time
class Runtime:
def __init__(self):
pass
def __enter__(self):
self.start = time.time()
return self.start
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.time()
self.run = self.end - self.start
print(f"程序运行了{self.run}")
with Runtime():
for i in range(10000):
pass
上次练习答案
class Account:
def __init__(self):
self.account = None
self.password = None
self.money = 0
def creat_account(self, account, password):
self.account = account
self.password = password
self.money = 0
def deposit(self, money, password):
if self.password == password:
self.money += money
def draw_money(self, money, password):
if self.password == password and self.money >= money:
self.money -= money
def query(self, password):
if self.password == password:
return self.money
def cancel(self, password):
if self.password == password:
return f"{self.account}被删除了"
del self
def __del__(self):
pass
def toString(self):
return f"account = {self.account}, money = {self.money}."
a = Account()
b = Account()
c = Account()
a.creat_account(1, 1)
b.creat_account(2, 2)
c.creat_account(3, 3)
print(a.toString())
b.deposit(100, 2)
print(b.toString())
print(c.cancel(3))
练习
- 测试使用列表推导式和不使用列表推导式哪个速度更快。(尽量写大一点)
- range不可以使用小数做步长,实现一个可迭代对象,可以实现小数步长。
结束语
ps:现在关注我,以后就是老粉啦!!!
下篇预告
在协议中介绍了迭代器协议,但是需要定义类,那么只用函数可以生成嘛?
|