类: 用来描述具有相同的属性和方法的对象的集合—>车类
对象: 通过类定义的数据结构实例—>我的车
属性: 对象的描述信息---->车的零部件
方法: 对象的行为—>车的功能(将零部件组装,实现某种功能)
方便版本迭代更新, 程序结构清晰明了
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
在python中用双下划线开头的方式将属性设置成私有的。
好处:1. 将变化隔离;2. 便于使用;3. 提高复用性;4. 提高安全性。
代码的重用
class Animal:
species = 'Animal'
count = 0
def __init__(self):
self.name = "animal"
Animal.count += 1
print("初始化Animal")
def breath(self):
print("i can breath")
def eat(self):
print('i can eat')
class Person(Animal):
species = 'Person' # 重写了父类的属性
class Dog(Animal):
def __init__(self):
print("i am dog")
def eat(self):
print("dog is eating")
class Pig(Animal):
count = 0
def __init__(self):
super().__init__() # 子类访问父类的init方法,建议放在最前面,否则跟父类的属性冲突了会覆盖
self.name = "pig"
Pig.count += 1
print("初始化pig。。。。")
print("实例化Animal".center(50, '*'))
animal = Animal()
print(animal.count)
print("实例化Person".center(50, '*'))
person = Person()
print(person.count, person.species, Person.count)
# 对象的属性查找,先去对象实例空间查找,没有就去类空间查找
# 类空间没有就去父类空间查找,层层递归往上查找
print("实例化dog".center(50, '*'))
d = Dog()
d.eat()
print("实例化pig".center(50, '*'))
pig = Pig()
print(Animal.count, pig.count, pig.name)
实现接口的重用
python里不支持多态,python处处是多态
不支持多态是语法上的多态,不需要额外的实现多态的代码
按照多态语法来说,不属于多态(父类作为参数,传递子类对象)
python 里处处是多态,本身实现了多态
class Alipay():
def pay(self):
print("支付宝的pay")
class WeChat():
def pay(self):
print("微信的pay")
class WangYi():
def pay(self):
print("WangYi的pay")
zhi = Alipay()
wei = WeChat(
wang = WangYi()
def paymethod(obj): # 不关心是什么类,只关心有没有pay()这个行为
obj.pay()
paymethod(wang)
paymethod(zhi)
类创建的时候会生成类空间
实例化对象的时候会生成实例空间,不同的实例空间都是独立的
实例查找属性方法的时候,先在自己的实例空间找,找不到就去类空间查找
类空间找不到就去父类找,一层一层往上找
创建实例的时候,会有一个类对象指针,通过这个指针,实例就能访问类的属性和方法了
初始化实例的方法 (静态方法)
实例对象的构造方法(初始化方法)
实例化对象的时候会自动调用__init__ 方法
创建实例的方法(实例方法)
没有的话默认会继承object类的new方法,一般不需要重写
总结:
__ new__是创建实例的方法
__ init__ 对创建的实例进行初始化工作的方法
__ new__方法必须要传入一个参数(cls),代表当前类
__ init__ 必须要返回一个实例化对象
__ init__ 的self就表示__new__方法返回的实例,__ init__ 就对这个实例进行初始化
子类没有定于__ new__ 就会去找父类的__ new__
新式类才有 __ new__
如果实例化对象和本身class不一致,__ init__就不会执行
无论实例化多少次,都只会返回同一个实例对象
通过重写new方法实现
class Student:
obj = None
def __new__(cls, *args, **kwargs):
if cls.obj:
cls = object.__new__(cls)
return cls.obj
a = Student()
b = Student()
c = Student()
print(id(a), id(b), id(c))
self代表类的实例,而非类
实例方法里面,第一个参数就代表实例本身,所以不一定非写成self
如果要通过实例调用,第一个参数必须要传,因为实例调用底层实现是Person.info( p ), p是必传参数
可以Peson.info()方法调用
class Person:
name = "hejin"
def info(self):
print(f'i am {self.name}')
print(self)
print(type(self))
p = Person()
p.info() # 底层解释器 Person.info(p),因为实例空间是没有info方法,
# 执行类里面的Person.info(p)是这里的p 就代表实例本身
关系判断
print(isinstance(person,Person),isinstance(person,Animal)) #True True 判断是否是类的实例
print(type(person)) # 只能判断当前类
print(Pig.__base__) # 查找父类
class Iterator1():
def __init__(self, it):
self.index = 0
self.it = it
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.it):
print("迭代结束")
else:
self.index += 1
return self.it[self.index - 1]
lst = [1, 2, 3, 4, 5, 6]
str1 = "abcdef"
itera = Iterator1(str1)
print(itera.__next__())
print(itera.__next__())
class Fibonacci():
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
f = Fibonacci()
for i in range(9):
print(f.__next__(), end=' ')
python2—经典类、新式类
只有显示地继承了object的类称为新式类,其他都是经典类
继承了python内置类的类称为新式类,其他都是经典类
python3—新式类
默认都是继承object,所有都是新式类
#类的定义
class A():
pass
class B:
pass
class C(object):
pass
# 在python2种 A、B 两类都属于经典类,只有C是新式类
# 在python3中 默认会继承object类,所有A、B、C都是新式类
经典类和新式类的最大区别就是有没有继承object类,还有继承顺序的区别
>>> class A:pass # Python2
...
>>> a = A()
>>> type(a) #通过type查看到的实例类型都叫做instance
<type 'instance'>
>>> a.__class__ # 实例和类之间只能通过__class__ 属性进行关联
<class __main__.A at 0x7f931dc95ec0>
>>> class A:pass # Python3
...
>>> a = A()
>>> type(a) #通过type查看到的实例类型就是类名
<class '__main__.A'>
>>> a.__class__
<class '__main__.A'>
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): # MOR
def test(self):
print("from F")
f = F()
f.test()
经典类:F——D——B——A——E——C(深度优先)
新式类:F——D——B——E——C——A(c3 算法,非广度有限)
c3算法总结:
首先将自身类加入到本序列,然后对继承序列的元素依次判断;
若某元素不在其他序列或者它是所有继承序列的第一个,那么就把这个元素提取到本序列;
举例:
A ——【A,Object】
B ——【B,A,Object】
D —— 【D,B,A,Object】
C —— 【C,A,Object】
E ——【E,C,A,Object】
F ——【F】+【D,B,A,Object】+【E,C,A,Object】
最后变成:【F,D,B】 因为A在【E,C,A,Object】在这个序列里面,所以A丢掉
静态属性:类属性
普通属性:实例属性
class A():
name = '长沙' # 静态属性
def __init__(self):
self.country = "china" # 普通属性
# 普通(实例)方法
# 接收的第一个参数,就代表实例本身
def normal_method(self, name):
print("normal".center(20, '*'))
print(self.name, name)
# 使用classmethod修饰的方法,称为类方法
# 接收的第一个参数,就代表类本身
@classmethod
def class_method(cls, name):
print("class_method:".center(20, '*'))
print(type(cls), cls)
print(cls.name, name) # 访问不了实例属性
# 使用staticmethod修饰的方法,称为静态方法
# 可以接收参数也可以不接,参数不代表实例和类本身
@staticmethod
def static_method(name):
print("static_method:".center(20, '*'))
print(A.name, name) # 通过类名访问属性
# 通过实例调用实例、静态、类方法
a = A()
a.normal_method("实例调用实例方法")
a.class_method("实例调用类方法")
a.static_method("实例调用静态方法")
# 通过类调用实例、静态、类方法
# 通过类调用实例方法的时候,一定要传一个实例进去
A.normal_method(a, "类调用实例方法")
A.class_method("类调用类方法")
A.static_method("类调用静态方法")
结果:
*******normal*******
长沙 实例调用实例方法
***class_method:****
<class 'type'> <class '__main__.A'>
长沙 实例调用类方法
***static_method:***
长沙 实例调用静态方法
*******normal*******
长沙 类调用实例方法
***class_method:****
<class 'type'> <class '__main__.A'>
长沙 类调用类方法
***static_method:***
长沙 类调用静态方法
• dir(Person):了解Person类里的变量和方法
• dir( p ) 或 p.__dir__() :查看对象的属性和方法
• Person.__dict__ :可以了解哪些是变量哪些是方法
查看文档注释
第一个用三引号引起来的字符串
print(Parent.__doc__)
查看帮助文档
print(help(Parent))
查看对象和类空间
print(p.__dict__) #类的属性(包含一个字典,由类的数据属性组成)
print(Parent.__dict__) # 了解哪些是变量哪些是方法
查看对象属于那个类
print(p.__class__)
print(Parent.__name__) 查看类名
查看父类
print(Child.__bases__) 查看 继承的所有父类
print(Child.__base__)
print(Parent.__base__)
print(Parent.__bases__)
查看对象的哈希值
print(Parent.__hash__)
查看类定义所在的模块
print(a.__module__)
print(A.__module__)
不能被模糊导入
双下划线开头 只有类对象自己可以调用
class Parent:
tmp = "tmp"
_min = 1 # 保护成员
__max = 10 # 私有属性
def __init__(self):
self.name = 'hejin'
self._age = 18
self.__desc = 'it' # 实例的私有属性,在类的内部调用
def __make(self):
print("这是一个私有方法")
print(self.__desc)
def _protectmake(self):
print("这是一个保护方法")
def show(self):
print(self.__max, self.__desc) # 只能在类的内部调用
print("这是一个普通方法")
class Child(Parent):
def show(self):
print(self.__max)
p = Parent()
c = Child()
# print(p.tmp, c.tmp)
# print(p._min, c._age, c._min)
# p._protectmake()
# c._protectmake()
# print(p.__max)
# p.show()
# c.show()
# 查看实例空间有哪些属性
print(p.__dict__) # self.__desc——》 _Parent__desc _类名__属性/方法名
# print(p.__desc)
print(p._Parent__desc) # 伪私有,双下划线开头的标识符改了名字
在Python中,所有以双下划线__包起来的方法,统称为Magic Method(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。
魔术方法在类或对象的某些事件出发后会自动执行,让类具有神奇的“魔力”。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。
Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的
__new__ :创建实例
__init__ :初始化实例
__del__:在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭 打开的临时文件
class ATM:
def __del__(self): # 析构函数 再销毁之前需要做的事情
print("执行del") # 这里做的收尾工作
def __call__(self, name, age):
print(f"my name is {name},my age is {age}")
a = ATM()
del a # 关键字
__call __ :把类实例化后的对象当做函数来调用的时候自动被调用
a("sc", 18) # 结果:my name is sc,my age is 18
__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:")
self.data[key] = value
def __delitem__(self, key):
print("delete data:")
del (self.data[key])
a = A()
a["name"] = "hejin" #set data:
print(a.data) #{'name': 'hejin'}
print(a["name"]) #get data: hejin
del a["name"] #delete data:
print(a.data) #{}
*• __eq__(self, other) 定义了等号的行为, ==
•__ne__(self, other) 定义了不等号的行为, !=
• __lt__(self, other) 定义了小于号的行为, <
• __gt__(self, other) 定义了大于等于号的行为, >=
•__add__(self, other) +运算
• __mul__(self, other) 运算
•__len__(self, other) 获得长度
class LenError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
lst = [1, 2, 3, 4, 5]
try:
if not 8 <= len(lst) <= 10:
raise LenError("长度不在8-10之间")
except LenError as er:
print(er)
在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
自省有4个方法 :
print(hasattr(math, "xx")) # 判断math有没有xx属性
print(hasattr(math, "sin"))
print(math.sin(90))
print(setattr(math, "xx", 1)) # None 设置math的xx属性为1
print(getattr(math, "xx")) # 1 获取math的xx属性
print(delattr(math, "xx")) # None 删除math的xx属性
import math
class A:
name = "sc"
__max = "max"
def f1(self):
print("i am f1")
a = A()
print(hasattr(a, "name")) #True
if hasattr(a, "f1"):
print(getattr(a, "name")) #sc
if hasattr(a, "f1"):
print(getattr(a, "f1")()) #i am f1 和None
def f2():
print("i am f2")
setattr(a, "f3", f2)
a.f3() #i am f2