面向对象具有三大特征
(一)、封装
有些时候我们不希望把对象的属性公开,就可以把它设为私有,python并没有像其他语言对成员的权限控制系统,如private和protected,默认情况下,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
(二)、继承
继承可以使子类拥有父类的属性和方法,并且可以重写这些方法,加强代码的复用性,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
(三)、多态
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式
因为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
类成员
描述:
- 属性
- 普通属性
- 静态属性
- 方法
- 普通方法
- 类方法
- 静态方法
- 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()
输出信息
这是一个普通字段
这是一个静态字段
这是一个普通方法
这是一个类方法
这是一个静态方法
- 普通属性属于对象
- 静态属性属于类
- 普通方法:由对象调用,有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())
输出信息
__new__
__init__
我的名字Tom,年龄22
__call__
Tom
__del__
__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'
测试一:
p = Person()
print(p.name)
输出信息:
item:name
调用getattribute
测试二:
p = Person()
print(p.name2)
输出信息:
item:name2
__getattr__
default
__getattribute__的坑
class Person:
def __getattribute__(self, item):
print('__getattribute__')
if item.startswith('a'):
return 'hahaha'
else:
return self.test # 这里会陷入递归调用
p = Person()
print(p.b)