Python全栈(一)基础之13.面向对象(2)

一、特殊方法

class Person:
    name = 'Tom'

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
p2.speak()

打印Hello,I'm Tom
类中没有定义属性时,手动添加属性

class Person:
    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
#手动向对象添加属性
p1.name = 'Tom'
p2.name = 'Jerry'
p1.speak()
p2.speak()

打印

Hello,I'm Tom
Hello,I'm Jerry

如未手动添加属性时,

class Person:
    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
p1.speak()
p2.speak()

便会报错:AttributeError: 'Person' object has no attribute 'name'
在上例中,对于Person这个类name属性是必须的,并且对于每一个对象name属性的值是不一样的,讲name属性手动添加,很容易出错。

1.特殊方法:

即魔术方法,都是以__开头、__结尾的方法。
特殊方法不需要我们调用,会在特殊的时候自己调用。
学习特殊方法:
※特殊方法什么时候调用;
※特殊方法有什么作用。

class Person:
    def __init__(self):
        print('hello')

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p1.__init__()

打印

hello
hello

hello打印了两次,因为类的实例创建时,会自动调用了一次,再手动调用了一次,所以调用了两次。

class Person:
    def __init__(self):
        print('hello')

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
p3 = Person()
p4 = Person()

打印

hello
hello
hello
hello

可以说,每创建一个实例对象,特殊方法就执行一次。

对象的创建流程

p1 = Person()

(1)创建了一个变量;
(2)在内存中创建了一个新的对象;
(3)执行类中的代码块的代码,并且只在类中执行一次
(4)__init__()方法执行。
即如类的定义中除特殊方法还有别的代码语句,则其他语句先执行,如,

class Person:
    print('In class Person')
    def __init__(self):
        print('hello')

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
p3 = Person()
p4 = Person()

打印

In class Person
hello
hello
hello
hello

__init__()方法会在对象创建以后立即执行,向新创建的对象初始化属性,

class Person:
    def __init__(self):
        print(self)

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p2 = Person()
p3 = Person()
p4 = Person()

打印

<__main__.Person object at 0x000002E1EEC36708>
<__main__.Person object at 0x000002E1EEC36EC8>
<__main__.Person object at 0x000002E1EEC36F08>
<__main__.Person object at 0x000002E1EEC36F48>

即打印self即打印出对象,self代表对象本身。

class Person:
    def __init__(self):
        self.name = 'Tom'

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p1.speak()

打印Hello,I'm Tom
为了解决之前出现过的问题,可以在__init__()方法中添加参数,通过self向新建的对象初始化对象。

class Person:
    def __init__(self,name):
        self.name = name

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person()
p1.speak()

初始化时未添加name,会报错
TypeError: __init__() missing 1 required positional argument: 'name'
所以必须在初始化时即添加,

class Person:
    def __init__(self,name):
        self.name = name

    def speak(self):
        print('Hello,I\'m %s'%self.name)

p1 = Person('Tom')
print(p1.name)
p2 = Person('Jerry')
print(p2.name)
p1.speak()
p2.speak()

打印

Tom
Jerry
Hello,I'm Tom
Hello,I'm Jerry

2.类的基本结构:

class 类名([父类]):
    公共属性
    #对象的初始化方法
    __init__(self,...):
        ...
    #其他的方法
    def method(self,...):
        ...

二、练习

要求:尝试定义一个车的类。

class Car():
    '''属性:name、color
    方法:run()、didi()'''
    def __init__(self,name,color):
        self.name = name
        self.color = color

    def run(self):
        print('Car in running...')

    def didi(self):
        print('%s didi'%self.name)

c = Car('daben','white')
print(c.name,c.color)
c.run()
c.didi()

打印

daben white
Car in running...
daben didi

定义对象时,希望对象能发挥一些作用,应该保证数据的安全性和有效性,

class Car():
    '''属性:name、color
    方法:run()、didi()'''
    def __init__(self,name,color):
        self.name = name
        self.color = color

    def run(self):
        print('Car in running...')

    def didi(self):
        print('%s didi'%self.name)

c = Car('daben','white')
#修改属性
c.name = 'aodi'
print(c.name,c.color)
c.run()
c.didi()

结果就会改变

aodi white
Car in running...
aodi didi

要增加数据的安全性,要做到:
1.属性不能随意修改,有确实要改的需要才改,没有真实的需要才改;
2.属性不能改为任意的值,要保证有效。

三、封装

封装是面向对象的三大特性之一(另外两个是继承、多态)。
封装指的是隐藏对象中一些不希望被外部访问到的属性和方法。

class Dog:
    def  __init__(self,name):
        self.name = name

d = Dog('erha')
d.name = 'kaisa'
print(d.name)

打印kaisa
此例中name属性即未被隐藏,会被任意修改。
如何修改对象中的一个属性:
将对象的属性名修改为外部不知道的名字。

class Dog:
    def  __init__(self,name):
        self.hidden_name = name

    def speak(self):
        print('Hello,I\'m %s'%self.hidden_name)

d = Dog('erha')
d.name = 'kaisa'
d.speak()

打印Hello,I'm erha
此时不能修改,要想修改,

class Dog:
    def  __init__(self,name):
        self.hidden_name = name

    def speak(self):
        print('Hello,I\'m %s'%self.hidden_name)

d = Dog('erha')
d.hidden_name = 'kaisa'
d.speak()

打印Hello,I'm kaisa,这又不是封装,成了最初的形式。
如何获取(修改)对象当中的属性:
通过提供getter()和setter()方法来访问和修改属性。

class Dog:
    def  __init__(self,name):
        self.hidden_name = name

    def speak(self):
        print('Hello,I\'m %s'%self.hidden_name)

    def get_name(self):
        #获取对象的属性
        return self.hidden_name

    def set_name(self,name):
        #修改对象属性
        self.hidden_name = name

d = Dog('erha')
print(d.get_name())
d.set_name('kaisa')
print(d.get_name())
d.speak()

打印

erha
kaisa
Hello,I'm kaisa

使用封装确实在一定程度上增加了程序的复杂性,
但是它确保了数据的安全性
1.隐藏了属性名,使调用者无法任意修改对象中的属性。
2.增加了getter和setter方法,可以很好地控制属性是否是可读的:
如果希望属性是可读的,则可以直接去掉setter方法;
如果希望属性不能被完结访问,则可以直接去掉getter方法。
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的。
虽然性,但是增加了程序的安全性。
4.可以在读取属性和设置属性的方法中做一些其他的操作。

class Dog:
    def  __init__(self,name,age):
        self.hidden_name = name
        self.hidden_age = age

    def speak(self):
        print('Hello,I\'m %s'%self.hidden_name)

    def get_name(self):
        #获取对象的属性
        return self.hidden_name

    def set_name(self,name):
        #修改对象属性
        self.hidden_name = name

    def get_age(self):
        #获取对象的属性
        return self.hidden_age

    def set_age(self,age):
        #修改对象属性
        self.hidden_age = age

d = Dog('erha',5)
print(d.get_age())
d.set_age(-5)
print(d.get_age())

打印

5
-5

显然,把狗的年龄设为负值程序是没报错的,但是是没有实际意义的,所以我们可以增加对数据的判断。

class Dog:
    def  __init__(self,name,age):
        self.hidden_name = name
        self.hidden_age = age

    def speak(self):
        print('Hello,I\'m %s'%self.hidden_name)

    def get_name(self):
        #获取对象的属性
        return self.hidden_name

    def set_name(self,name):
        #修改对象属性
        self.hidden_name = name

    def get_age(self):
        #获取对象的属性
        return self.hidden_age

    def set_age(self,age):
        #修改对象属性
        #判断再处理
        if age > 0:
            self.hidden_age = age

d = Dog('erha',5)
print(d.get_age())
d.set_age(-5)
print(d.get_age())

打印

5
5

四、封装进阶

class Person():
    def __init__(self,name):
        self.hidden_name = name

    def get_name(self):
        return self.hidden_name

    def set_name(self,name):
        self.hidden_name = name

p = Person('Tom')
p.set_name('Jerry')
print(p.get_name())

打印Jerry,即属性值会改变。hidden_name改为__name

class Person():
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name

p = Person('Tom')
print(p.get_name())

打印Tom

class Person():
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name

p = Person('Tom')
print(p.__name)

会报错AttributeError: 'Person' object has no attribute '__name'

class Person():
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name

p = Person('Tom')
p.__name = 'Jerry'
print(p.get_name())

打印还是Tom,没有被修改。
总结:可以为对象的属性使用双下划线开头,__xxx
双下划线开头的属性是悐的隐藏属性,隐藏属性只能在类的内部访问,无法通过外部访问。
隐藏属性是Python自动为属性改了一个名字,实际改的名字是:_类名_属性名_:
__name -> _Person__name

class Person():
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name

p = Person('Tom')
print(p.get_name())
p._Person__name = 'Jerry'
print(p.get_name())

打印

Tom
Jerry

_Person__name又可以对属性进行修改。
在写代码的时候,可以用一个下划线,既容易书写,外部能访问,且不易被修改。
一般情况下:使用_开头的属性都是私有属性,没有特殊情况不要修改。

五、装饰器@property

用来将get()方法转化为对象的属性。
添加property装饰器以后,就可以像调用属性一样调用方法。

class Person():
    def __init__(self,name):
        self._name = name

    def name(self):
        return self._name

p = Person('Tom')
print(p.name())

打印Tom
用了property装饰器以后,

class Person():
    def __init__(self,name):
        self._name = name

    @property
    def name(self):
        print('The method is run')
        return self._name

p = Person('Tom')
print(p.name)

输出结果为:

The method is run
Tom

加入setter后,

class Person():
    def __init__(self,name):
        self._name = name

    @property
    def name(self):
        print('The method is run')
        return self._name

    @name.setter
    def name(self,name):
        self._name = name

p = Person('Tom')
print(p.name)
p.name = 'Jerry'
print(p.name)

打印

The method is run
Tom
The method is run
Jerry
发布了51 篇原创文章 · 获赞 184 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/CUFEECR/article/details/102992075
今日推荐