欢迎光临散文网 会员登陆 & 注册

第九章 面向对象-3

2023-07-13 09:40 作者:wangyanhpa  | 我要投稿

我们再定义一个有实际意义的类,员工类Worker,想想要包含哪些属性哪些行为,或者以后我们都采用专业的说法,这个员工类包含哪些数据域和哪些方法。Have a try! 下面是我的程序:

class Worker:

    # Construct a Worker object

    def __init__(self, name="xiaoming",workID="2020011001",department="市场部",age=23,salary=2000):

        self.name = name

        self.department = department

        self.salary = salary

 

def main():

    w1=Worker(name="小红",salary=3000)

    print(w1.salary)

 

main()

 

假设我是小红的朋友,想给小红多点钱,在main函数里加一句代码:

    w1.salary=40000

    print(w1.salary)

或者在程序中还有很多函数f1……f10,每个函数都可以修改小红的薪水,这就导致了混乱。因为修改薪水这件事只能由老板决定,而且还有可能程序修改的薪水值不小心写错成上千万,我们都无法控制这类情况,所以这个问题需要解决。也就是现在存在的问题是直接访问对象的数据域导致数据被篡改,而且类会变得难以维护并且易于出错,因此在Python中引入数据隐藏的概念,目的是防止直接访问数据域。

数据隐藏可以通过定义私有数据域来完成,在Python中,私有数据域使用两个下划线定义,如self.__ salary,还可以以两个下划线开始来定义私有方法。私有数据域只能在类内访问,类外不可以访问。按照数据隐藏的思路,上述程序可以改成下面的样子:

class Worker:

    # Construct a Worker object

    def __init__(self, name="xiaoming",workID="2020011001",department="市场部",age=23,salary=2000):

        self.name = name

        self.department = department

        self.__salary = salary

 

def main():

    w1=Worker(name="小红",salary=3000)

    print(w1.__salary)  #程序运行时此处会出现错误

                    #错误提示:AttributeError: 'Worker' object has no attribute '__salary'

main()

 

错误的原因是因为__salary是私有成员,类外不能访问,而类内可以访问,如setSalary方法中修改了__salary。我把main函数修改成下面这样再运行一下试试:

def main():

    w1=Worker(name="小红",salary=3000)

    w1.__salary=40000

天哪!居然没有错误,Why?

把main函数修改成下面这样再运行一下:

def main():

    w1=Worker(name="小红",salary=3000)

    w1.__salary=40000

    print(w1.__salary)

又出错了,我  我  我 , 

 这是为什么呢?Keep reading!

在Python中,有以下几种方式来定义变量:

Ÿ   xx:公有变量。类内类外均可访问

Ÿ   _xx:单前置下划线,私有化属性或方法,类对象和子类可以访问,禁止导入(我们已经学习过导入,如果想用random里面的方法,就需要导入random)from somemodule import *

Ÿ   __xx:双前置下划线,私有化属性或方法,无法在外部直接访问(名字重新调整所以访问不到

Ÿ   __xx__:双前后下划线,系统定义名字(不要自己发明这样的名字)

Ÿ   xx_:单后置下划线,用于避免与Python关键词的冲突

名字重新调整所以访问不到” 是什么鬼?就是在类内定义的私有成员如__salary在类外被重新命名为_Worker__salary,所以print(w1.__salary) 会提示没有__salary属性,即类外不提供访问。那既然改了名字,我可以用改过的名字访问吗?回答可以!看看下面的运行结果:

虽然_Worker__salary被高亮显示提示有问题,但是确实输出了结果3000!等一下,再看看有没有问题!给你1分钟时间。

w1.__salary=40000 这行代码为什么没有错误,为什么输出的不是40000?

呃,This is an extraordinarily interesting question.I must think fast.

再加一行代码    print(w1.__salary)    输出试一下,结果如下:

这是因为类的实例可以动态增加属性和方法,也就是说Worker类里面又增加了一个__salary数据域。但是建议不要这样做。由此可见,Python是有多么任性!下面引入一个例子,看一下不明白也没有关系!

 

class Person(object):# object这个问题下一节解释(9.2继承与多态)

    count = 0  #此变量为类变量,每个对象都可以访问,类Person也可以访问(深入了解请自学)

    def __init__(self, name):

        self.name = name

 

# 实例化

p1 = Person("tom")

print(p1.name)  # tom

print(p1.count)  # 0

 

p2 = Person("jack")

print(p2.name)  # jack

print(p2.count)  # 0

#

# 通过对象修改类变量

print("*******通过对象修改类变量*********")

p1.count = 2

print(p1.count)  # 2

print(p2.count)  # 0

print(Person.count)  # 0

#

# # 通过类修改类变量

print("*******通过对象修改类变量*********")

Person.count = 3

print(p1.count)  # 2

print(p2.count)  # 3

print(Person.count)  # 3

#

# 给对象增加属性

print("*******给对象增加属性age*********")

p1.age = 23

print(p1.age)  # 23

#

# 给对象增加方法

print("*******给对象p1增加方法set_age*********")

def set_age(self, age):

    self.age = age

 

from types import MethodType

p1.set_age = MethodType(set_age, p1)

p1.set_age(25)

print(p1.age)  # 25

 

print("*******对象p2没有方法set_age*********")

# print(p2.age)

# AttributeError: 'Person' object has no attribute 'age'

 

运行结果如下:

tom

0

jack

0

*******通过对象修改类变量*********

2

0

0

*******通过对象修改类变量*********

2

3

3

*******给对象增加属性age*********

23

*******给对象p1增加方法set_age*********

25

*******对象p2没有方法set_age*********

Process finished with exit code 0

 

如果去掉倒数第二行# print(p2.age) 的 # 符号,则运行结果如下:

tom

0

jack

0

*******通过对象修改类变量*********

2

0

0

Traceback (most recent call last):

*******通过对象修改类变量*********

2

3

  File "F:/教学/2019秋/Python code/first.py", line 45, in <module>

3

*******给对象增加属性age*********

    print(p2.age)

23

*******给对象p1增加方法set_age*********

AttributeError: 'Person' object has no attribute 'age'

25

*******对象p2没有方法set_age*********

Process finished with exit code 1

Ok,这个问题就说到这儿,但是还有一个问题,类内不能访问私有成员,那这些私有成员还有什么用?如何使用类的这些成员呢?

注意:是类外不能访问,类内是可以的,所以可以定义方法,一般是一对setter和getter。在方法里访问这些成员,然后类外调用这些方法就可以了。那这不是更费事吗?当然不是。我们可以给允许外界访问的成员定义一对setter和getter,不允许外界修改的就不定义了,所以一切尽在我掌控!

定义有setter和getter方法的Worker类如下,试着理解一下:

class Worker:

    # Construct a Worker object

    def __init__(self, name="xiaoming",workID="2020011001",department="市场部",age=23,salary=2000):

        self.name = name

        self.department = department

        self.__salary = salary

 

def setSalary(self, salary):

        self.__salary = salary

 

    def getSalary(self):

        return self.__salary

def main():

    w1=Worker(name="小红",salary=3000)

    print(w1.name," salary:",w1.getSalary())

    if w1.getSalary()<5000:

        w1.setSalary(5500)

    print("涨工资了!")

    print(w1.name, " salary:", w1.getSalary())

main()


第九章 面向对象-3的评论 (共 条)

分享到微博请遵守国家法律