动态绑定属性
class Student:
# 类属性:定义在类中,方法外的变量
school = '北京xxx教育'
print(type(school)) # 定义在类里面所以属性不变
# 类属性初始化方法
def __init__(self, xm, age): # xm,age是方法的参数,是局部变量,xm,age的作用域整个__init__方法
# 即xm,age只能在类里面使用,要想在其他地方使用需要定义类的实例属性
self.name = xm # 左例是实例属性,xm是局部变量,将局部变量的值xm赋值给实例属性self.name
self.age = age # 实例的名称和局部的可以相同
# 定义在类中的函数,称为方法,自带一个参数self
def show(self):
print(f'我叫:{self.name}.今年:{self.age}岁了')
#创建两个Student类型的对象
stu=Student('xx',10)
stu2=Student('hh',20)
print(stu.name,stu.age)
print(stu2.name,stu2.age)
#为stu2动态绑定一个实例属性
stu2.gender='女'
print(stu2.name,stu2.age,stu2.gender)
#动态绑定的方法
def introduce():
print('普通函数被动绑定成stu2对象的方法')
stu2.fun=introduce
#经过此操作fun就是stu2对象的方法
#对象的方法属于实例方法调用
stu2.fun()
1、单下划线开头的属性或方法表示protected受保护的成员,这类成员被视为仅供内部使用,允许类本身和子类进行访问,但实际它可以被外部代码访问。
2、双下划线开头表示private私有的成员,这类成员只允许定义该属性或方法的类本身进行访问
3、收尾双下划线表示特殊的方法
class Student():
def __init__(self,name,age,gender):
self._name=name #单下划线
self.__age=age
self.gender=gender
def _fun1(self):
print('受保护的')
def __fun2(self):#私有的
print('只有定义的类可以访问')
def show(self):#普通类
self._fun1()
self.__fun2()
stu=Student('xx',10,'女')
#类的外部
print(stu._name)
# print(stu.__age)#AttributeError: 'Student' object has no attribute '__age'. Did you mean: '_name'?
#访问受保护的实例方法
stu._fun1()#子类及本身
#私有方法
# stu.__fun2()#AttributeError: 'Student' object has no attribute '__fun2'. Did you mean: '_fun1'?
#私有的实例属性
print(stu._Student__age)
stu._Student__fun2()
# print(dir(stu))#内置函数
#['_Student__age', '_Student__fun2',
# '__class__', '__delattr__', '__dict__', '__dir__',
# '__doc__', '__eq__', '__format__', '__ge__',
# '__getattribute__', '__getstate__', '__gt__', '__hash__',
# '__init__', '__init_subclass__', '__le__', '__lt__', '__module__',
# '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
# '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
# '_fun1', '_name', 'gender', 'show']
class Student:
def __init__(self,name,gender):
self.name=name
self.__gender=gender#self.__gender 是私有的实例属性
#以上是使用下划线强制访问
#使用装饰器(以@开头的)将方法转成属性使用
@property
def gender(self):
return self.__gender
#将gender修改为可变属性
@gender.setter#不能@property
def gender(self,value):
if value!='男'and value!='女':
print('性别有误,默认为女')
else:
self.__gender=value
stu=Student('xy','女')
print(stu.name,'性别',stu.gender)#属性变成了方法,stu。gender()
#变成方法之后就无法修改属性值
# stu.gender='男'#AttributeError: property 'gender' of 'Student' object has no setter
#要想修改属性为可变属性,应该在前面修改代码12行
stu.gender='男'
print(stu.name,'性别',stu.gender)
Python中面向对象的三大特征:
一个子类可以继承N个父类;一个父类也可以拥有N多个子类;如果一个类没有继承任何类,那么默认继承object类。
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def show(self):
print(f'大家好,我是:{self.name},我今年:{self.age}岁')
#Student 继承Person类
class Student(Person):
#编写初始化的方法
def __init__(self,name,age,stuno):
super().__init__(name,age)#调用父类的初始化方法
self.stuno=stuno
#Doctor继承Person类
class Doctor (Person):
def __init__(self,name,age,department):
super().__init__(name,age)
self.department=department
#编写初始化方法
#创建第一个子类对象
stu=Student('xx',20,'1001')
stu.show()
#创建第二个子类对象
doctor=Doctor('yy',10,'外科')
doctor.show()
class FatherA():
def __init__(self,name):
self.name=name
def showA(self):
print('父类A中的方法')
class FatherB():
def __init__(self,age):
self.age=age
def showB(self):
print('父类B中的方法')
class Son(FatherA ,FatherB):
def __init__(self,name,age,gender):
#需要调用两个父类的初始化方法
FatherA.__init__(self,name)
FatherB.__init__(self,age)
self.gender=gender
son=Son('xx',20,'女')#调用Son类中的__init__执行
son.showA()
son.showB()
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def show(self):
print(f'大家好,我是:{self.name},我今年:{self.age}岁')
#Student 继承Person类
class Student(Person):
#编写初始化的方法
def __init__(self,name,age,stuno):
super().__init__(name,age)#调用父类的初始化方法
self.stuno=stuno
def show(self):
#调用父类中的方法
super().show()
print(f'学号为:{self.stuno}')
#Doctor继承Person类
class Doctor (Person):
def __init__(self,name,age,department):
super().__init__(name,age)
self.department=department
def show(self):
#super().show()#调用父类的show方法
print(f'我叫{self.name},我今年{self.age}岁,我的工作科室是:{self.department}')#不调用父类,隔断的方法
#编写初始化方法
stu=Student('xx',20,'1001')
stu.show()#先调用子类的show方法,子类没有去父类中调用
doctor=Doctor('yy',10,'外科')
doctor.show()#我叫yy,我今年10岁,我的工作科室是:外科
class Person():
def eat(self):
print('人,吃五谷杂粮')
class Cat():
def eat(self):
print('猫,喜欢吃鱼')
class Dog():
def eat(self):
print('狗喜欢啃骨头')
#这三个类都有一个同名的方法,eat
#编写函数
def fun(obj):#obj是函数的形式参数,定义处不用知道这个形参的数据类型
obj.eat()#通过变量obj(对象)调用eat方法
#创建三个类的对象
per=Person()
cat=Cat()
dog=Dog()
#调用fun函数
fun(per)
fun(cat)
fun(dog)
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def show(self):
print(f'我叫{self.name},我今年{self.age}')
#创建Person 类的对象
per=Person('xx',20)
print(dir(per))#查看person类型
#['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'show']
#以上除了'age', 'name', 'show',其他均是由object父类中调用而来
#重写父类的str方法
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
#方法重写
def __str__(self):
return'这是一个具有name和age两个实例属性'#返回值是一个字符串
#创建person类的对象
per=Person('xx',19)
print(per)#__str__方法中的内容 直接输出对象名,实际上是调用__str__方法而不是内存地址
print(per.__str__())
#以上结果均为:
#这是一个具有name和age两个实例属性
#这是一个具有name和age两个实例属性
a=10
b=20
print(dir(a))#使用内置函数查看Python中一切对象
print(a.__add__(b))
print(a.__sub__(b))
print(f'{a}<{b}吗?',a.__lt__(b))
print(f'{a}<={b}吗?',a.__le__(b))
print(f'{a}=={b}吗?',a.__eq__(b))
print('-'*40)
print(f'{a}>{b}吗?',a.__gt__(b))
print(f'{a}>={b}吗?',a.__ge__(b))
print(f'{a}!={b}吗?',a.__ne__(b))
print('-'*40)
print(a.__mul__(b))
print(a.__truediv__(b))
print(a.__mod__(b))
print(a.__floordiv__(b))
print(a.__pow__(2))
class A:
pass
class B:
pass
class C(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建类的对象
a=A()
b=B()
#创建C类对象
c=C('xx',20)
print('对象a的属性字典:',a.__dict__)#对象a的属性字典: {}
print('对象b的属性字典:',b.__dict__)#对象b的属性字典: {}
print('对象b的属性字典:',c.__dict__)#对象b的属性字典: {'name': 'xx', 'age': 20}
print('对象a所属的类:',a.__class__)#对象a所属的类: <class '__main__.A'>
print('对象b所属的类',b.__class__)#对象b所属的类 <class '__main__.B'>
print('对象c所属的的类:',c.__class__)#对象c所属的的类: <class '__main__.C'>
print('A类的父类元组',A.__bases__)
print('B类的父亲元组',B.__bases__)
print('c类的父类元组',C.__bases__)
#A类的父类元组 (<class 'object'>,)
#B类的父亲元组 (<class 'object'>,)
#c类的父类元组 (<class '__main__.A'>, <class '__main__.B'>)
print('A类的父类:',A.__base__)
print('B类的父类:',B.__base__)
print('c类的父亲',C.__base__)#A类,如果继承了N多个父类,结果只是显示第一个父类
# c类的父亲 <class '__main__.A'>
print('A类的层次结构',A.__mro__)
print('B类的子类列表:',B.__mro__)
print('C类的子类列表:',C.__mro__)#C类继承了A类,B类,间接继承了object类
print('A类的子类列表:',A.__subclasses__())#A的子类有C类,A类的子类列表: [<class '__main__.C'>]
print('B类的子类列表:',B.__subclasses__())#B类的子类列表: [<class '__main__.C'>]
print('C类的子类列表:',C.__subclasses__())#C类的子类列表: []
class CPU():
pass
class Disk():
pass
class Computer():
def __init__(self,cpu,disk):
self.cpu=cpu
self.disk=disk
cpu=CPU()#创建了一个CPU对象
disk=Disk()#创建了一个硬盘对象
#创建一个计算机对象
com=Computer(cpu,disk)
#变量(对象)的赋值
com1=com
print(com,'子对象的内存地址:',com.cpu,com.disk)
print(com1,'子对象的内存地址',com1.cpu,com1.disk)
#赋值不会创建新的空间
# ject at 0x0000024FA3AA4B30> 子对象的内存地址: <__main__.CPU object at 0x0000024FA3AA4B90> <__main__.Disk object at 0x0000024FA3AA4B00>
# <__main__.Computer object at 0x0000024FA3AA4B30> 子对象的内存地址 <__main__.CPU object at 0x0000024FA3AA4B90> <__main__.Disk object at 0x0000024FA3AA4B00>
#类对象的浅拷贝
import copy
com2=copy.copy(com)
print(com,'子对象内存地址为',com.cpu,com.disk)
print(com2,'子对象内存地址为',com2.cpu,com2.disk)
#<__main__.Computer object at 0x000001F45ACB4EC0> 内存地址为 <__main__.CPU object at 0x000001F45ACB4F20> <__main__.Disk object at 0x000001F45ACB4E90>
#<__main__.Computer object at 0x000001F45ACB4FE0> 内存地址为 <__main__.CPU object at 0x000001F45ACB4F20> <__main__.Disk object at 0x000001F45ACB4E90>
#产生了一个新的对象,但是子对象不变
#类对象的深拷贝
print('-'*40)
com3=copy.deepcopy(com)#com3新产生的对象,com3的对象,CPU,disk也会重新创建
print(com,'子对象内存地址',com.cpu,com.disk)
print(com3,'子对象内存地址',com3.cpu,com3.disk)
#<__main__.Computer object at 0x0000020B755F5280> 子对象内存地址: <__main__.CPU object at 0x0000020B755F52E0> <__main__.Disk object at 0x0000020B755F5250>
#<__main__.Computer object at 0x0000020B755F53A0> 子对象内存地址 <__main__.CPU object at 0x0000020B755F52E0> <__main__.Disk object at 0x0000020B755F5250>
#创建新对象子对象也会改变
访问私有属性的语法:对象名._类名__属性名