黑马程序员技术交流社区

标题: 【上海校区】Python 关于面向对象 [打印本页]

作者: 不二晨    时间: 2018-10-30 09:44
标题: 【上海校区】Python 关于面向对象
面向对象具有三大特征

(一)、封装

把很多数据封装到一个对象中,把固定功能的代码封装到⼀个代码块函、数、对象, 打包成模块,这都属于封装的思想。

在Python语言中,所谓的私有,不过是一种假象。当我们在类中定义私有成员时,在程序内部会将其处理成_类名 + 原有成员名称的形式。也就是会将私有成员的名字进行一下伪装而已,如果我们使用处理之后的名字,还是能够进行访问的.程序:私有的伪装

xx: 公有变量
_x: 保护变量,只能在类的内部和类的子类,实例中使用
__xx: 私有变量,双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访 问(名字重整所以访问不到)
__xx__: 双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字(通过name mangling(名字重整(目的就是以防子类意外重写基类的方法或者 属性)如:_Class__object)机制就可以访问private了)
xx_: 单后置下划线,用于避免与Python关键词的冲突
class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age


p = Person('Tom', 22)
# print(p.__name) # 报AttributeError异常
print(p.get_name())  # Tom
print(p.get_age())  # 22

# _Class__object任然可以获取属性
print(p._Person__name)  # Tom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(二)、继承

继承可以使子类拥有父类的属性和方法,并且可以重写这些方法,加强代码的复用性,python中子类可以有多个父类,但是不建议这样使用,一般会产生重复调用的问题,Super().方法名,可以调用父类的方法(不用传参,作用是调用父类的方法,传的是子类实例的值)

class Animal:
    def eat(self):
        print('Animal eat')

    def run(self):
        print('Animal run')


class Dog(Animal):
    def dog_call(self):
        print('dog_call')


class Cat(Animal):
    def cat_call(self):
        print('cat_call')


d = Dog()
d.dog_call()  # dog_call
d.eat()  # Animal eat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(三)、多态

指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式

因为Python是鸭子类型,因此,多态在Python中体现的不明显

class Animal:
    def eat(self):
        print('Animal eat')

    def run(self):
        print('Animal run')


class Dog(Animal):
    def call(self):
        print('Dog call')


class Cat(Animal):
    def call(self):
        print('Cat call')


def call(obj):
    obj.call()


c = Cat()
d = Dog()
call(c)  # Cat call
call(d)  # Dog call
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
类成员

描述:

属性
普通属性
静态属性
方法
普通方法
类方法
静态方法
property属性
代码演示:

class Simple:
    # 静态字段
    static_field = '这是一个静态字段'

    def __init__(self, normal_field):
        # 普通字段
        self.normal_field = normal_field

    # 普通方法
    def method(self):
        print('这是一个普通方法')

    # 类方法
    @classmethod
    def class_method(cls):
        print('这是一个类方法')

    # 静态方法
    @staticmethod
    def static_method():
        print('这是一个静态方法')

    # 定义属性:获取数据
    @property
    def prop(self):
        return self.__value

    # 设置数据
    @prop.setter
    def prop(self, value):
        self.__value = value

    # 删除数据
    @prop.deleter
    def prop(self):
        del self.__value


s = Simple('这是一个普通字段')
print(s.normal_field)
print(s.static_field)
s.method()
Simple.class_method()
Simple.static_method()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
输出信息

这是一个普通字段
这是一个静态字段
这是一个普通方法
这是一个类方法
这是一个静态方法
1
2
3
4
5
普通属性属于对象
静态属性属于类
普通方法:由对象调用,有self参数,调用方式时,将调用方法的对象赋值给self
类方法:由类调用,有cls参数,调用方法事件,将调用方法的类赋值给cls
静态方法:由类调用,无默认参数
property属性:在普通方法上添加@property装饰器,setter装饰器赋值,getter装饰器取值
内置方法

描述:

类的内建属性和方法        说明        触发方式
init        构造初始化函数        创建实例后,赋值时使用,在__new__后
new        生成实例所需属性        创建实例时
class        实例所在的类        实例.class
str        实例字符串表示,可读性        print(类实例),如没实现,使用repr结果
repr        实例字符串表示,准确性        类实例 回车 或者 print(repr(类实例))
del        析构        del删除实例
dict        实例自定义属性        vars(实例.dict)
doc        类文档,子类不继承        help(类或实例)
getattribute        属性访问拦截器        访问实例属性时
bases        类的所有父类构成元素        类名.bases
说明:

__getattr__:当一般位置找不到attribute的时候,会调用getattr,(有返回值)返回一个值或AttributeError异常.
__getattribute__:无条件被调用,通过实例访问属性.

代码演示:

class Person:
    # 构造方法
    def __new__(cls, *args, **kwargs):
        print('__new__')
        return super().__new__(cls)  # 如果没有调用父类的构造函数,初始化函数是不会被调用的

    # 初始化方法
    def __init__(self, name, age):
        print('__init__')
        self.name = name
        self.age = age

    # 对象输出
    def __str__(self):
        return '我的名字%s,年龄%d' % (self.name, self.age)

    # 对象当函数调用时执行
    def __call__(self, *args, **kwargs):
        print('__call__')
        return self.name

    # 释放对象时执行
    def __del__(self):
        print('__del__')


p = Person('Tom', 22)
print(p)
print(p())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
输出信息

__new__
__init__
我的名字Tom,年龄22
__call__
Tom
__del__
1
2
3
4
5
6
__getattr__和__getattribute__关系

当访问某个实例属性时, getattribute会被无条件调用,如未实现自己的getattr方法,会抛出AttributeError提示找不到这个属性,如果自定义了自己getattr方法的话,方法会在这种找不到属性的情况下被调用 。

一般重写__getattr__方法

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

    def __getattribute__(self, item):
        print('item:%s' % item)
        if item == 'name':
            return '调用getattribute'
        else:
            return object.__getattribute__(self, item)

    def __getattr__(self, item):
        print('__getattr__')
        return 'default'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
测试一:

p = Person()
print(p.name)

输出信息:
item:name
调用getattribute
1
2
3
4
5
6
测试二:

p = Person()
print(p.name2)

输出信息:
item:name2
__getattr__
default
1
2
3
4
5
6
7
__getattribute__的坑

class Person:
    def __getattribute__(self, item):
        print('__getattribute__')
        if item.startswith('a'):
            return 'hahaha'
        else:
            return self.test # 这里会陷入递归调用

p = Person()
print(p.b)
---------------------
【转载】
作者:xiangxiongfly915
原文:https://blog.csdn.net/qq_14876133/article/details/81135005



作者: 不二晨    时间: 2018-10-31 14:29

作者: 梦缠绕的时候    时间: 2018-11-1 14:35

作者: 魔都黑马少年梦    时间: 2018-11-1 16:14





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2