经典类和新式类
-
在Python 2.x及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位 置),都属于“新式类”
-
不由任意内置类型派生出的类,则称之为“经典类”。
-
“新式类”和“经典类”的区分在Python 3.x之后就已经不存在,在Python 3.x之后的版本,因为所有 的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”
-
建议使用新式
经典类与新式类在类型上的区别
经典类
-
所有的类都是classobj类型,而类的实例都是instance类型。
-
类与实例只有通过class属性进行关联
新式类
-
类实例的类型是这个实例所创建自的类(通常是和类实例的class相同)
#经典类
>>> class A:pass
>>> a = A()
>>> type(a)
<type 'instance'>
>>> a.__class__
<class __main__.A at 0x7fef2a9bd258>
#新式类
class A: pass
>>> a = A()
>>> type(a)
class '__main__.A'>
经典类与新式类的继承顺序
Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
多重继承时,继承顺序 经典类和新式类是有区别的
-
经典类 ———深度优先算法
-
新式类 ———C3算法
class A:
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D,E):
def test(self):
print("from F")
f = F()
f.test()
#以上,会先找f自身,如果自身没有就先找D,D没有就找B(经典类和新式类一样)
#B没有,找A(0经典类)
#B没有,找E(新式类)
#mro方法解析序列
#经典类: F -->D -->B -->A -->E -->C
#新式类: F -->D -->B -->E -->C -->A
C3算法
静态方法、类方法、实例方法
属性
-
静态属性(所有的实例共用一份=>引用)
-
普通属性(每个实例都不同的数据=>引用)
方法
-
普通(实例)方法(使用实例中的数据) => 给实例使用(一定要传递一个实例,由实例调用)
-
静态方法(无需使用实例封装的内容@staticmethod)
-
类方法(会自动加当前类的类名 @classmethod) => cls表示类本
各种方法的区别(@staticmethod、@classmethod)
-
实例方法不能通过类名调用,但是静态方法和类方法是可以(不实例化访问)
-
实例方法:可以通过self访问实例属性
-
类方法:可以通过cls访问类属性(希望取的值不受实例影响时使用)
-
静态方法:不可以访问,通过传值的方式
class A:
name = "class A"
def __init__(self):
self.country = "china"
#实例方法
#第一个参数代表实例本身
def normal_method(self,name):
#方法的里面,及可以访问类属性,又可以访问实例属性
print("normal")
print(self.name,name)
#类方法
#第一个参数代表类 cls --类
@classmethod
def class_method(cls,name):
#类方法里面,可以访问类属性
print("classmethod")
print(cls,cls.name)
#静态方法
@staticmethod
def static_method(name):
#静态方法里面,可以通过类名访问类属性
print("static_method:",name,A.name)
a1 = A()
#############静态方法、实例方法、类方法都能通过实例去调用
# a1.normal_method("a1")
a1.class_method("a1")
# a1.static_method("a1")
#也可以通过类调用
# A.normal_method(a1,"A")
# A.class_method("A")
# A.static_method("A")
属性包装(@propert)
-
把函数包装成属性,使用的时候用对象名.属性名
-
Person类中有一个属性为age,控制age的范围只能在0~150之间
属性包装的应用
property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检 查,这样,程序运行时就减少了出错的可能性
python类中的下划线
以下划线开头的标识符是有特殊意义的
以单下划线开头的(_foo)
-
类:这类成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量
-
模块:如果你写了代码“from <模块/包名> import *” ,那么以“_”开头的模块和包都不会被导 入,除非模块或包中的“all”列表显式地包含了模块和包
以双下划线开头的(__foo)
-
类:只有类对象自己能访问,连子类对象也不能访问到这个数据。强行访问“对象名._类名 __xxx“这样的方式
-
模块:不能用“from xxx import *“导入包/模块
以双下划线开头和结尾的( foo )
-
代表Python中特殊方法专用的标识。其实,这只是一种惯例,对Python系统来说,这将确保不会 与用户自定义的名称冲突。
-
例如init()代表类的构造函数。
-
虽然你也可以编写自己的特殊方法名,但不建议用户使用这种命名方式
class P:
"""this is p"""
_min = 1 #保护属性
__max = 10 #私有属性
def __init__(self):
self.name = "sc"
self._age = 4
self.__desc = "it"
def __make(self):
print("这是一个私有方法")
print(self.__desc)
def _protectmake(self):
print("这是一个保护方法")
def show(self):
print(self.__max,self.__desc)
class Child(P):
def show(self):
print(self.__max)
p = P()
c = Child()
print(c._min,p._min,Child._min,P._min)
#子类访问不到私有成员
# c.show()
# print(c.__make)
#类对象也不能访问私有成员
# print(P.__max)
# P.__make()
#私有成员只能在类的内部进行访问
# p.show()
#查看属性
# print(dir(p))
#python 中的似有都是伪私有,其实就是把双下划线开头的标识符,改了一个名字存储 _类名__标识符
# print(p._P__max)
常见的以双下划线和以双下划线结尾的特殊变量
#__dict__查看命名空间
# print(P.__dict__) #类空间
# print(p.__dict__) #实例空间
# __name__类名
print(P.__name__)
# def func1(cls):
# a = cls()
# print(f"{cls.__name__}进行了实例化")
# class A:
# pass
# class B:
# pass
# func1(A)
# func1(B)
#__class__查看对象属于那个类
print(p.__class__)
#__module__查看所在模块
print(P.__module__)
#__doc__查看文档注释
print(P.__doc__) #help自动调用__doc__属性
常用魔术方法和属性
魔术方法:一般以双下划线开头和双下划线结尾,而且是特殊含义的方法,与一般不需要手动去调用,他会在某种特定的场景下自动执行
构造函数(__new__
/__init__
)
-
__new__
:创建实例 -
__init__
:初始化实例 -
析构函数(
__del__
)-
在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭 打开的临时文件
-
-
调用方法(
__call__
) • 把类实例化后的对象当做函数来调用的时候自动被调用 -
获取数据(
__getitem__
)-
a[key]来访问对象,a[1:3]切片时调用
__getitem__
-
-
删除数据(
__delitem__
)-
del r[1] 时调用
__delitem__
方法
-
-
设置数据(
__setitem__
)-
r['e']=213时调用
__setitem__
-
-
获取可迭代(
__iter__
)
class A:
def __del__(self): #
print("this is A.del")
a1 = A()
del a1 #手动释放
print("XXXXXX")
#####__call__
把实例化之后的对象当作函数去调用
class A:
def __call__(self,name):
print(f"i am A.__call__,name is {name}")
a1 = A()
a1("sc")
def func1():
pass
print(dir(func1))
__getitem__
__setitem__
__delitem__
对象以字典的形式去设置或获取参数
class A:
def __init__(self):
self.data = {}
def __getitem__(self,key):
print("get data")
return self.data.get(key,0)
def __setitem__(self,key,value):
print("set data:",key,value)
self.data[key] = value
def __delitem__(self,key):
print("delete data")
del(self.data[key])
a1 = A()
print(a1["key1"])
a1["key1"] = "XXXXXXXX"
del a1["key1"]
-
__str__
-
__repr__
__str__ __repr__ __str__ 给用户看的,调用方式a = A(),没有str就调用repr __repr__给程序员看的 调用方式a 返回对象的描述信息 ie = IndexError("test")
print(ie)
class A:
def __str__(self):
return "this is A"
a1 = A()
print(a1)
查看类属性和方法
-
dir(Person):了解Person类里的变量和方法
-
Person.
__dict__
:可以了解哪些是变量哪些是方法
内置属性及其功能
-
__dict__
:类的属性(包含一个字典,由类的数据属性组成)-
__doc__
:类的文档字符串
-
-
__name__
:类名 -
__module__
:类定义所在的模块 -
__bases__
:类的所有父类构成元素