Python编程_Lesson016_类的高级用法

类的静态成员

类的静态属性

我们先来看一个例子:

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

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值