类与对象
- 对象=属性+方法
类就是创建对象的模板,对象就是类的实例;类不但包含方法定义,而且还包含所有实例共享的数据
- 封装:信息隐蔽技术
- 继承:子类自动共享父类之间数据和方法的机制
- 多态:不同对象对同一方法响应不同的行动
使用关键字class
定义类,关键字后面是:类的名称、冒号和类的实现。
引用例子:
class Turtle: # Python中的类名约定以大写字母开头
"""关于类的一个简单例子"""
# 属性
color = 'green'
weight = 10
legs = 4
shell = True
mouth = '大嘴'
# 方法
def climb(self):
print('我正在很努力的向前爬...')
def run(self):
print('我正在飞快的向前跑...')
def bite(self):
print('咬死你咬死你!!')
def eat(self):
print('有得吃,真满足...')
def sleep(self):
print('困了,睡了,晚安,zzz')
tt = Turtle()
print(tt)
# <__main__.Turtle object at 0x0000007C32D67F98>
print(type(tt))
# <class '__main__.Turtle'>
print(tt.__class__)
# <class '__main__.Turtle'>
print(tt.__class__.__name__)
# Turtle
tt.climb()
# 我正在很努力的向前爬...
tt.run()
# 我正在飞快的向前跑...
tt.bite()
# 咬死你咬死你!!
# Python类也是对象。它们是type的实例
print(type(Turtle))
# <class 'type'>
- self就是实例本身,类定义了很多方法,方法的引用需要有一个额外的第一个参数名称,按照惯例是self,在类实例化后调用方法时无需明确提供与参数self相对应的参数。
- python的魔法方法
类有一个名为__init__(self[,param1,param2...]
的魔法方法,该方法在类实例化时自动调用 - 公有和私有
在Python种定义私有变量只需要在变量名或函数名前加上两个下划线
python的私有为伪私有;可以属性私有和方法私有;引用私有可以先在类前加_class__(method,attribution) - 继承
python同样支持类的继承,派生类的定义如下:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
BaseClassName必须与派生类定义在一个作用域内,除了类,还可以用表达式,基类定义在另一个模块中时非常游泳:
class DerivedClassName(modname.BaseClassName): #modname:模块名
<statement-1>
.
.
.
<statement-N>
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。
在初始化子类时候需要引用父类的魔法方法,否则子类方法会将父类方法覆盖。
一种方法是调用未绑定的父类方法Class.init(self);另一种方法是使用super().init()
python虽然支持多继承的形式,但我们一般不使用多继承,因为容易引起混乱。
形式:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
需要注意圆括号中的父类的顺序,若有父类有相同的方法名,而在子类使用时未指定,Python从左至右搜索,即方法在子类中未找到,从左到右查找父类是否包含此方法。
- 组合
类的组合使用例子:
class Turtle:
def __init__(self, x):
self.num = x
class Fish:
def __init__(self, x):
self.num = x
class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))
p = Pool(2, 3)
p.print_num()
# 水池里面有乌龟2只,小鱼3条
- 类、类对象和实例对象
类对象:创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个。
实例对象:就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个。
类属性和实例属性区别
- 类属性:类外面,可以通过实例对象.类属性和类名.类属性进行调用。类里面,通过self.类属性和类名.类属性进行调用。
- 实例属性 :类外面,可以通过实例对象.实例属性调用。类里面,通过self.实例属性调用。
- 实例属性就相当于局部变量。出了这个类或者这个类的实例对象,就没有作用了。
- 类属性就相当于类里面的全局变量,可以和这个类的所有实例对象共享。
注意:
属性和方法名相同,属性会覆盖方法。
- 什么是绑定
python严格要求方法需要有实例才能被调用,这种限制其实就是python所谓的绑定概念。
python对象的数据属性通常存储在名为__dict__
的字典中,可以直接访问也可通过内置函数vars()
获取。 - 一些相关的内置函数(BIF)
issubclass(class,classinfo)
方法用于判断参数class是否是类型参数classinfo的子类- 一个类被认为是其自身的子类
classinfo
可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回Trueisinstance
考虑继承关系hasattr(object,name)
用于判断对象是否包含对应的属性getattr(object,name[,default])
用于返回一个对象属性值setattr(object,name,value)
对应函数getattr()
用于设置属性值,该属性不一定存在delattr(object ,name)
用于删除属性- class property([fget[, fset[, fdel[, doc]]]])用于在新式类中返回属性值。
- fget – 获取属性值的函数
- fset – 设置属性值的函数
- fdel – 删除属性值函数
- doc – 属性描述信息
魔法方法
引用自DataWhale Python编程基础学习笔记
魔法方法总是被双下划线包围,例如,init
魔法方法的第一个参数应为cls
(类方法)或者self
(实例方法)
- 基本魔法方法
__init__(self[, ...])
构造器,当一个实例被创建的时候调用的初始化方法
__new__(cls[, ...])
在一个对象实例化的时候所调用的第一个方法,在调用__init__
初始化前,先调用__new__。
若__new__
没有正确返回当前类cls的实例,那__init__
是不会被调用的,即使是父类的实例也不行,将没有__init__
被调用。
__new__
方法主要是当你继承一些不可变的 class 时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。
__del__(self)
析构器,当一个对象将要被系统回收之时调用的方法
str(self):repr(self):
repr是str的备胎;有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__;repr(obj)内置函数对应的结果是__repr__的返回值;当你使用%r格式化的时候 触发__repr__
str 的意义是得到便于人们阅读的信息,repr 存在的目的在于调试.
- 算术运算符
类型工厂函数,指的是“不通过类而是通过函数来创建对象”。
add(self, other)定义加法的行为:+
sub(self, other)定义减法的行为:-
mul(self, other)定义乘法的行为:*
truediv(self, other)定义真除法的行为:/
floordiv(self, other)定义整数除法的行为://
mod(self, other) 定义取模算法的行为:%
divmod(self, other)定义当被 divmod() 调用时的行为
divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
pow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
lshift(self, other)定义按位左移位的行为:<<
rshift(self, other)定义按位右移位的行为:>>
and(self, other)定义按位与操作的行为:&
xor(self, other)定义按位异或操作的行为:^
or(self, other)定义按位或操作的行为:| - 反算术运算符
反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。
radd(self, other)定义加法的行为:+
rsub(self, other)定义减法的行为:-
rmul(self, other)定义乘法的行为:*
rtruediv(self, other)定义真除法的行为:/
rfloordiv(self, other)定义整数除法的行为://
rmod(self, other) 定义取模算法的行为:%
rdivmod(self, other)定义当被 divmod() 调用时的行为
rpow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
rlshift(self, other)定义按位左移位的行为:<<
rrshift(self, other)定义按位右移位的行为:>>
rand(self, other)定义按位与操作的行为:&
rxor(self, other)定义按位异或操作的行为:^
ror(self, other)定义按位或操作的行为:| - 增量运算符
iadd(self, other)定义赋值加法的行为:+=
isub(self, other)定义赋值减法的行为:-=
imul(self, other)定义赋值乘法的行为:*=
itruediv(self, other)定义赋值真除法的行为:/=
ifloordiv(self, other)定义赋值整数除法的行为://=
imod(self, other)定义赋值取模算法的行为:%=
ipow(self, other[, modulo])定义赋值幂运算的行为:**=
ilshift(self, other)定义赋值按位左移位的行为:<<=
irshift(self, other)定义赋值按位右移位的行为:>>=
iand(self, other)定义赋值按位与操作的行为:&=
ixor(self, other)定义赋值按位异或操作的行为:^=
ior(self, other)定义赋值按位或操作的行为:|= - 一元运算符
neg(self)定义正号的行为:+x
pos(self)定义负号的行为:-x
abs(self)定义当被abs()调用时的行为
invert(self)定义按位求反的行为:~x - 属性访问
getattr(self, name): 定义当用户试图获取一个不存在的属性时的行为。
getattribute(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。
setattr(self, name, value):定义当一个属性被设置时的行为。
delattr(self, name):定义当一个属性被删除时的行为。 - 描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
get(self, instance, owner)用于访问属性,它返回属性的值。
set(self, instance, value)将在属性分配操作中调用,不返回任何内容。
del(self, instance)控制删除操作,不返回任何内容。
8.定制序列
协议(Protocols)与其它编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在 Python 中的协议就显得不那么正式。事实上,在 Python 中,协议更像是一种指南。
容器类型的协议
如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法。
如果你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法。
- 迭代器
- 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 字符串,列表或元组对象都可用于创建迭代器:
- 生成器
- 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
- 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
- 调用一个生成器函数,返回的是一个迭代器对象。