Python编程_Lesson016_类的高级用法

来源:互联网 发布:宝日龙梅 知乎 编辑:程序博客网 时间:2024/06/06 03:01

类的静态成员

类的静态属性

我们先来看一个例子:

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()

结果如下:

rootUser 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()

结果如下:

rootadminUser 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:1600User 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__demoDemo.__str__

此时无论使用print函数还是在控制台调试输出,都会直接打印对象的信息。

__iter__()和__next__()实现对象的课迭代来进行遍历

import randomclass 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 retdef 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__()6UserInfo.__next__()3UserInfo.__next__()1UserInfo.__next__()10UserInfo.__next__()5UserInfo.__next__()8UserInfo.__next__()2UserInfo.__next__()8UserInfo.__next__()6UserInfo.__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 itemdef 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 itemdef 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()

结果如下:

intslice

__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()

打印结果:

checkUser 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()

结果如下:

checkUser Name:root Password:root Salary:3000 Balance:1600UserInfo.__del__()

我们看到Python中有这么多好用的函数,但是又好像还缺少些什么,仔细一想,哦~原来是枚举!!!
实际上是有枚举类的。

枚举类

枚举类是需要导入的,方法如下from enum import Enum
我们可以直接使用枚举类

from enum import Enumdef main():    color = Enum("Color", ("red", "green", "blue"))    print(color["red"])if __name__ == "__main__":    main()

结果如下:

Color.red

我们也可以自己定义一个枚举类

from enum import Enum, unique#枚举类,unique是用来检测重复的,如果有重复的则编译不通过@uniqueclass 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.COLORColor.GREEN

枚举可以将一些数值赋予一些意义,这对于通信将会有很大的帮助。

原创粉丝点击