类的静态成员
类的静态属性
我们先来看一个例子:
class UserInfo(object):
company = "PoEdu"
user_info = UserInfo()
user_info.company
'PoEdu'
UserInfo.company
'PoEdu'
这个company是什么呢?更为奇怪的是我们可以直接拿着类名来访问company这个属性!
我们将这样的属性称为类的静态属性
静态属性是属于类的,而并不是属于类的某一个函数。
class UserInfo(object):
company = "PoEdu"
user_info = UserInfo()
user_info.company
'PoEdu'
UserInfo.company
'PoEdu'
user_info_2 = UserInfo()
user_info_2.company
'PoEdu'
user_info.company = "poedu"
user_info.company
'poedu'
user_info_2.company
'PoEdu'
UserInfo.company
'PoEdu'
UserInfo.company = "poedu"
user_info.company
'poedu'
user_info_2.company
'poedu'
UserInfo.company
'poedu'
UserInfo.company = "PoEdu"
UserInfo.company
'PoEdu'
user_info.company
'poedu'
user_info_2.company
'PoEdu'
这个例子说明了类的静态属性的以下几个特点:
- 每个对象中都会有一个静态属性
- 对象中的静态属性是可以被更改的,但是它对于其它对象以及类中的静态属性没有任何影响
- 类中的静态属性也是可以被更改的,但是它的更改就会影响所有的对象中的静态属性
- 当类中再次修改回来时,user_info对象自己修改过后的company静态属性就再也不会修改回来了(可以说已经失去了UserInfo类中的静态属性company了)
从上面可以看出,Python中的静态属性并不想其它语言中的静态属性定义的那么严格,静态属相属于类里面的一个属性,但是对象会拥有这个变量,实用类来修改这个属性的话,所有的对象中(自身修改过静态属性的对象除外)的这个属性都会发生改变,而对象中修改这个静态属性只是修改了对象本身的静态属性。
上面的特点我们可以从Python中的动态绑定可以看出来,实际上对象在给静态属性赋值的时候,已经把原来的静态属性给覆盖掉了。
对于类中的静态函数也是一样的,这里就不多说了,可以自己做实验看看效果!!!
这种动态既有优点,又有缺点。这里我们说一下如何避免这种缺点。
动态绑定的限制
我们可以使用‘slot()’函数来限制只允许动态绑定哪些属性。
demo_1.company = "PoEdu"
class Demo(object):
__slots__ = ("username", "password")
demo_1 = Demo()
demo_1.username = "root"
demo_1.password = "root"
demo_1.name = "admin"
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Demo' object has no attribute 'name'
这样可以避免类中动态绑定带来的问题!
类的高级特性
像上一篇中我们使用setter和getter函数可以对隐藏的属性进行设置和访问,但是总是感觉还是没有那么的好用,我们能不能就可以隐藏属性,又可以直接使用(.)点来点出来呢?可以的!!!
‘@property特性’
这个特性是设置隐藏属性的访问
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
@property
def username(self):
return self.__username
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1.username)
user_info_1.print()
if __name__ == "__main__":
main()
结果如下:
root
User Name:root Password:root Salary:3000 Balance:1600
但是我们现在还不能给username赋值,不信的话可以试试,反正我是信了。
如果想要修改,我们还需要写一个函数:
这里写代码片
‘@property特性’
这个特性是设置隐藏属性的修改
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
@property
def username(self):
return self.__username
@username.setter
def username(self, username):
self.__username = username
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1.username)
user_info_1.username = "admin"
print(user_info_1.username)
user_info_1.print()
if __name__ == "__main__":
main()
结果如下:
root
admin
User Name:admin Password:root Salary:3000 Balance:1600
__str__()
特性
我们经常会看到这样的一种需求,使用print函数直接打印一个对象,而不是调用对象本身定义的print函数,我们这样该如何实现呢?
我们先直接打印一下看看
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
@property
def username(self):
return self.__username
@username.setter
def username(self, username):
self.__username = username
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1)
if __name__ == "__main__":
main()
结果如下:
<__main__.UserInfo object at 0x00000232AED3E7B8>
这不是我们想要的结果!
因为print函数需要接收一个str对象,所以我们只需要实现__str__()
函数即可
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
def __str__(self):
user_info = str.format("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
return user_info
@property
def username(self):
return self.__username
@username.setter
def username(self, username):
self.__username = username
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1)
user_info_1.print()
if __name__ == "__main__":
main()
结果如下:
User Name:root Password:root Salary:3000 Balance:1600
User Name:root Password:root Salary:3000 Balance:1600
打印结果一样!
__repr__()
上面的结果是我们使用print函数的时候打印的,我们知道print函数在调用我们对象的时候,会做一些转换,如果我们在调试状态下想输出对象信息该怎么办呢?先看一个简单的例子
class Demo(object):
def __str__(self):
return "Demo.__str__()"
demo = Demo()
print(demo)
Demo.__str__()
demo
<Demo object at 0x000002C2EE72AF98>
说明在调试的时候,并没有一个强转的功能,我们需要__repr__()
函数来进行强转
class Demo(object):
def __repr__(self):
return "Demo.__str__"
demo = Demo()
print(demo)
Demo.__str__
demo
Demo.__str__
此时无论使用print函数还是在控制台调试输出,都会直接打印对象的信息。
__iter__()和__next__()
实现对象的课迭代来进行遍历
import random
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def __iter__(self):
print("UserInfo.__iter__()")
return self
def __next__(self):
print("UserInfo.__next__()")
ret = random.randint(1, 10)
self.__loop -= 1
if not self.__loop:
raise StopIteration()
return ret
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
for i in user_info_1:
print(i)
if __name__ == "__main__":
main()
结果如下:
UserInfo.__iter__()
UserInfo.__next__()
6
UserInfo.__next__()
3
UserInfo.__next__()
1
UserInfo.__next__()
10
UserInfo.__next__()
5
UserInfo.__next__()
8
UserInfo.__next__()
2
UserInfo.__next__()
8
UserInfo.__next__()
6
UserInfo.__next__()
这样就和list有点儿相似了,我们可以利用这个特点依次来返回我们的每个属性,但是它和list还不一样,因为list还有切片、取下标等操作。
__getitem__()
函数实现取下标功能
如果我们想要实现取下标的功能,该怎么做呢?
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def __getitem__(self, item):
return item
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1[10])
if __name__ == "__main__":
main()
打印结果:
10
说明下标函数调用成功。
__getitem__()
函数实现切片功能
我们直接使用切片看看结果:
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def __getitem__(self, item):
return item
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1[10:100])
if __name__ == "__main__":
main()
打印结果如下:
slice(10, 100, None)
但是结果不对!
还是使用__getitem__()
函数进行切片,我们就需要做一些判断
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def __getitem__(self, item):
if isinstance(item, int):
return "int"
elif isinstance(item, slice):
return "slice"
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
print(user_info_1[1])
print(user_info_1[10:100])
if __name__ == "__main__":
main()
结果如下:
int
slice
__call__()
函数
对象可以直接被当成函数来调用,此时就会调用__call__()
函数。
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def __call__(self):
print("Demo.__call__()")
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
user_info_1()
if __name__ == "__main__":
main()
结果如下:
Demo.__call__()
这种用法非常适合敏捷开发,因为敏捷开发的需求是在不停地变化的。它可以在所有的方法之前加上一个功能(比如验证功能),我们不可能把我们写过的每一个方法加上一个验证的函数。
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def __call__(self):
print("Demo.__call__()")
class CheckFoo(object):
def __init__(self, foo):
self.__foo = foo
def __call__(self):
print("check")
self.__foo()
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
check_foo = CheckFoo(user_info_1.print)
check_foo()
if __name__ == "__main__":
main()
打印结果:
check
User Name:root Password:root Salary:3000 Balance:1600
这就是函数适配器的用法!
在stl中经常使用这个函数适配器!!!
__del__()
函数
我们称__del__()
为析构函数__init__()
为构造函数
class UserInfo(object):
def __init__(self, username, password, salary, balance):
self.__username = username
self.__password = password
self.__salary = salary
self.__balance = balance
self.__loop = 10
def print(self):
print("User Name:%s Password:%s Salary:%d Balance:%d"
% (self.__username, self.__password, self.__salary, self.__balance))
def __call__(self):
print("Demo.__call__()")
def __del__(self):
print("UserInfo.__del__()")
class CheckFoo(object):
def __init__(self, foo):
self.__foo = foo
def __call__(self):
print("check")
self.__foo()
def main():
user_info_1 = UserInfo("root", "root", 3000, 1600)
check_foo = CheckFoo(user_info_1.print)
check_foo()
if __name__ == "__main__":
main()
结果如下:
check
User Name:root Password:root Salary:3000 Balance:1600
UserInfo.__del__()
我们看到Python中有这么多好用的函数,但是又好像还缺少些什么,仔细一想,哦~原来是枚举!!!
实际上是有枚举类的。
枚举类
枚举类是需要导入的,方法如下from enum import Enum
。
我们可以直接使用枚举类
from enum import Enum
def main():
color = Enum("Color", ("red", "green", "blue"))
print(color["red"])
if __name__ == "__main__":
main()
结果如下:
Color.red
我们也可以自己定义一个枚举类
from enum import Enum, unique
#枚举类,unique是用来检测重复的,如果有重复的则编译不通过
@unique
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
COLOR = "clr"
def main():
color1 = Color("clr")
print(color1)
color2 = Color(2)
print(color2)
if __name__ == "__main__":
main()
结果如下:
Color.COLOR
Color.GREEN
枚举可以将一些数值赋予一些意义,这对于通信将会有很大的帮助。