创建类的语法
定义python中的类 | 类属性 | 直接定义在类里面的变量 |
实体属性 | 将外部传入的变量进行赋值 | |
实例方法 | 类里面的函数,注意要加self | |
静态方法 | 括号内无变量 | |
类方法 | 括号内为cls |
class Student:
#直接写到类里面的变量,称为类属性
native_place = '湖南'
home = '湖南'
def __init__(self,name,age):
#self.name 和self.age 是实体属性,进行了一个赋值操作,将局部变量的 name 赋值给实体属性
self.name = name
self.age = age
#实例方法:相当于是类里面的函数
def eat(self):
print(self.name + '在吃饭')
#静态方法
@staticmethod
def method1():
print('这里使用了staticmethod进行修饰,所以这是静态方法')
#类方法
@classmethod
def mathod2(cls):
print('这里使用了classmethod进行修饰,所以这是类方法')
创建实例对象
相当于C语言中的结构体
1.创造实例对象
#创造Student类的实例对象
stu1 = Student('张三',20)
stu2 = Student('李四',15)
'''
print(stu1)#<__main__.Student object at 0x000001BD8FD0AE00>
print(type(stu1))#<class '__main__.Student'>
print(id(stu1))#1913673264640 ->输出的是该对象的内存地址
'''
2.实例方法调用
#实例方法的调用
stu1.eat()#张三在吃饭 对象名.方法名()
Student.eat(stu1)#张三在吃饭 类名.方法名(类的对象)
3.实体属性调用
#实体属性的调用
print(stu1.name)#张三
print(stu1.age)#20
4.类属性使用方法
#类属性的使用方式
print(Student.native_place)#湖南
print(stu1.native_place)#湖南
print(stu2.home)#湖南
Student.native_place = '广东'
print(Student.native_place)#广东
print(stu1.native_place)#广东
print(stu2.native_place)#广东
4.类方法和静态方法的使用
#类方法的使用方式
Student.mathod2()#这里使用了classmethod进行修饰,所以这是类方法
#静态方法的使用方式
Student.method1()#这里使用了staticmethod进行修饰,所以这是静态方法
动态绑定属性和方法
1.动态绑定属性
#为stu1动态绑定属性
stu1.gender = '女'
print(stu1.name,stu1.age,stu1.gender)#张三 20 女
2.动态绑定方法
#为stu2动态绑定方法
stu1.eat()
stu2.eat()
#先新定义一个函数
def show():
print('这里我们新定义了一个函数,并将函数绑定给stu2')
stu2.show = show
stu2.show()
面向对象三大特征:封装 继承 多态
封装 | 提高程序的安全性 |
继承 | 提高代码复用性 |
多态 | 提高程序的可扩展性和可维护性 |
封装:
如果不希望在类外使用某一实体属性,可以在实体属性前加__
class Student:
def __init__(self,name,age):
self.name = name
self.__age = age
def printage(self):
print(self.__age)
stu1 = Student('张三',18)
print(stu1.name)
#print(stu1.__age)AttributeError: 'Student' object has no attribute '__age'
继承:
1.继承的实现方法
利用super()函数,调用父类的实例属性
class Person(object):
#定义父类的实体属性
def __init__(self,name,age):
self.name = name
self.age = age
#定义父类的实例方法
def info(self):
print(self.name,self.age)
#定义Person的子类
class Student(Person):
def __init__(self,name,age,num):
#继承父类的实体属性
#super调用父类
super().__init__(name,age)
self. num = num
class Teacher(Person):
def __init__(self,name,age,teachofyear):
super().__init__(name,age)
self.teachofyear = teachofyear
stu = Student('张三',20,100012)
teacher = Teacher('李四',55,35)
stu.info()#张三 20
print(teacher.teachofyear)#35
2.继承的方法重写
利用super()函数调用父类中的实例方法
lass Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print(self.name,self.age)
class Teacher(Person):
def __init__(self,name,age,teachofyear):
super().__init__(name,age)
self.teachofyear = teachofyear
def info(self):
super().info()
print(self.teachofyear)
teacher = Teacher('李四',55,35)
teacher.info()#35
3.重写object类的属性
我们先定义一个Player类,默认父类为object类
class Player:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
print('{}今年{}岁了'.format(self.name,self.age))
player = Player('Messi',35)
#内置函数dir()可以查看指定对象的所有属性
print(dir(player))
#['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
#其中的__str__()方法用于返回对对象的描述,所以我们对str()进行重写
player.__str__()#Messi今年35岁了
多态:
简而言之就是,具有多种形态,指的是在调用函数时,就算不知道参数的数据类型,仍然可以灵活调用对象中的哪个方法。
#父类
class Animal(object):
def eat(self):
print('动物要吃东西')
#子类
class Dog(Animal):
def eat(self):
print('狗吃肉')
class Cat(Animal):
def eat(self):
print('猫吃鱼')
class People(object):
def eat(self):
print('人吃五谷杂粮')
def fun(Animal):
Animal.eat()
fun(Dog())
fun(Cat())
fun(People())
'''
狗吃肉
猫吃鱼
人吃五谷杂粮
'''
具体结构图如下
当调用fun()函数时,传入的参数为Animal类型,但是当我们传入People类型时,因为People类也有.eat的实例方法,所以也可以调用。
特殊属性和特殊方法
特殊属性 | __dict__ | 获得对象的所有属性和方法的字典 |
__class__ | 获得实例对象所属的类型 | |
__subclasses__ | 获得对象的子类的列表 | |
__bases__ | 获得对象所属的所有父类的元组 | |
__mro__ | 获得对象的层次结构 |
print(dir(object))
#['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
class A(object):
pass
class B(object):
pass
class C(A,B):
def __init__(self,name):
self.name = name
class D(A):
pass
x = C('messi')#x为实例对象
print(x.__dict__)#{'name': 'messi'} 输出实例对象的属性字典
print(C.__dict__)#{'__module__': '__main__', '__init__': <function C.__init__ at 0x0000026D502FD900>, '__doc__': None} 输出类的属性和方法
print(x.__class__)#<class '__main__.C'> 输出实例对象所属的类型
print(C.__base__)#<class '__main__.A'> 输出了对象所属的第一个父类
print(C.__bases__)#(<class '__main__.A'>, <class '__main__.B'>) 输出了对象所属的父类的元组
print(C.__mro__)#(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) 输出了对象的层次结构
print(A.__subclasses__())#[<class '__main__.C'>, <class '__main__.D'>] 输出了对象A的子类
特殊方法 | __add__() | 通过重写__add__()方法,让自定义对象有 + 的功能 |
__len__() | 通过重写__len__()方法,让内置函数len()的参数可以是自定义类型(对象) | |
__new__() | 创建对象 | |
__init__() | 对创建的变量进行初始化 |
class Person(object):
def __new__(cls, *args, **kwargs):
print('__new__被调用执行了,cls的id值为{}'.format(id(cls)))
obj = super().__new__(cls)
print('创建的对象的id为{}'.format(id(obj)))
return obj
def __init__(self,name,age):
self.name = name
self.age = age
print('object这个类对象的id为:{}'.format(id(object)))
print('Person这个类对象的id为:{}'.format(id(Person)))
#创建Person类的实例对象
p1 = Person('Messi', 34)
print('p1这个Person类的实例对象的id为:{}'.format(id(p1)))
'''
object这个类对象的id为:140709393938304
Person这个类对象的id为:2182558880432
__new__被调用执行了,cls的id值为2182558880432
创建的对象的id为2182567411472
p1这个Person类的实例对象的id为:2182567411472
'''
类的赋值与浅拷贝深拷贝
1.类的赋值
变量的赋值操作只是形成两个变量,实际上还是指向同一个变量
class Computer(object):
def __init__(self,disk,cpu):
self.disk = disk
self.cpu = cpu
class Disk(object):
pass
class Cpu(object):
pass
disk = Disk()
cpu = Cpu()
computer1 = Computer(disk,cpu)
computer2 = computer1
print(computer1,id(computer1))#<__main__.Computer object at 0x0000016E8172BAF0> 1574129810160
print(computer2,id(computer2))#<__main__.Computer object at 0x0000016E8172BAF0> 1574129810160
#我们可以发现,computer1和computer2的id和value一模一样
#所以变量的赋值操作只是形成两个变量,实际上还是指向同一个变量
2.浅拷贝
浅拷贝时,源对象和拷贝对象会引用同一个子对象
class Computer(object):
def __init__(self,disk,cpu):
self.disk = disk
self.cpu = cpu
class Disk(object):
pass
class Cpu(object):
pass
import copy
computer1 = Computer(disk,cpu)
computer2 = copy.copy(computer1)
print(computer1.cpu,id(computer1))#<__main__.Cpu object at 0x000001AB850BBAC0> 1836183173584
print(computer2.cpu,id(computer2))#<__main__.Cpu object at 0x000001AB850BBAC0> 1836183173248
#我们可以发现,进行浅拷贝的同时,computer1和computer2的id不同,然而computer1和computer2中子对象相同
#所以源对象和拷贝对象会引用同一个子对象
3.深拷贝
在进行深拷贝时,拷贝对象包含子对象,源对象和拷贝对象不相同
class Computer(object):
def __init__(self,disk,cpu):
self.disk = disk
self.cpu = cpu
class Disk(object):
pass
class Cpu(object):
pass
import copy
computer3 = copy.deepcopy(computer1)
print(computer1.cpu,id(computer1))#<__main__.Cpu object at 0x000002627190FAC0> 2621835377104
print(computer3.cpu,id(computer3))#<__main__.Cpu object at 0x000002627190C9A0> 2621835377008
#我们可以发现,进行深拷贝的同时,computer1和computer3的id和子对象都不相同
#所以在进行深拷贝时,拷贝对象包含子对象,源对象和拷贝对象不相同