对象属性的增删改查
class Student:
def __init__(self, stu_id, name, age=18):
self.stu_id = stu_id
self.name = name
self.age = age
# 在当前类的对象被打印的时候自动调用,并且将这个方法的返回值作为这类对象的返回结果
# 返回值必须是字符串
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}>'
def show_message(self):
return [self.stu_id, self.name, self.age]
stu1 = Student('000', '小明')
stu2 = Student('001', '小花')
查
- 对象.属性 - 获取对象属性值
- getattr(对象, 属性名) - 获取对象指定属性的值,属性不存在会报错
- getattr(对象, 属性名, 默认值) - 获取对象指定属性的值,属性不存在返回默认值
print(stu1.name) # 小明
print(getattr(stu1, 'name')) # 小明
# print(getattr(stu1, 'gender')) # AttributeError: 'Student' object has no attribute 'gender'
print(getattr(stu1, 'gender', '男')) # 男
增、改
- 对象.属性 = 值 - 当属性存在的时候,修改属性的值,当属性不存在的时候添加属性;
- setattr(对象, 属性, 名值)
print(stu1) # <'stu_id': '000', 'name': '小明', 'age': 18>
stu1.gender = '女'
setattr(stu1, 'age', 100) # 修改年龄为100
print(stu1) # <'stu_id': '000', 'name': '小明', 'age': 100, 'gender': '女'>
删
- del 对象.属性 - 删除指定对象的指定属性
- delattr(对象, 属性名) - 删除指定对象的指定属性
print(stu1) # <'stu_id': '000', 'name': '小明', 'age': 100, 'gender': '女'>
# del stu1.age
delattr(stu1, 'age')
print(stu1) # <'stu_id': '000', 'name': '小明', 'gender': '女'>
内置属性
__slots__
- __slots__属性的值就是当前类的对象最多能够拥有的对象属性;
- 如果为空,那么这个类的对象就不能有对象属性;
- 如果给这个类设置了__slots__属性,那么就不能再使用__dict__属性;
class A:
"""
类说明文档
"""
# __slots__属性的值就是当前类的对象最多能够拥有的对象属性
# 如果为空,那么这个类的对象就不能有对象属性
# 如果给这个类设置了__slots__属性,那么就不能再使用__dict__属性
__slots__ = ('x', 'y', 'z')
def __init__(self, x=10, y=10):
self.x = x
self.y = y
a = A()
# a.m = 300 # TypeError: __init__() missing 2 required positional arguments: 'x' and 'y'
__doc__
- 类说明文档
# print(int.__doc__)
print(A.__doc__) # 类说明文档
__module__
- 获取类所在的模块
print(int.__module__) # builtins
print(A.__module__) # __main__ 当前模块
__class__
- 获取对象的类型,功能和type()
a = A()
print(a.__class__) # <class '__main__.A'>
print(type(a)) # <class '__main__.A'>
__dict__
- 获取类(对象)所有的类(对象)属性和对应的值,以字典的形式返回
print(a.__dict__) # {'x': 10, 'y': 10}
__name__
- 获取类的名字(类属性)
print(A.__name__) # 'A'
__base__ 与 __bases__
-
__base__ - 获取当前类的父类
-
__bases__ - 获取当前类的父类们
print(A.__base__) # <class 'object'>
print(A.__bases__) # (<class 'object'>,)
运算符重载
引言
print(10 + 29)
print('abc' + '34')
print([10, 34] + [235, 0, 'abc'])
# 10 + 29 == 10.__add__(29) # +号本质调用int类中的魔法方法
# 'abc' + '34' == 'abc'__add__('34') # +号本质调用str类中的魔法方法
重载
-
Python中每个运算符都对应一个固定的魔法方法,哪个类型中实现的对应的魔法方法,那个类型的数据就支持对应的运算符;
-
Python中某种数据是否支持某种运算符就看这个类中是否定义了运算符对应的魔法方法;
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __add__(self, other): # 使对象支持+号
return [stu1, stu2]
def __gt__(self, other):
return self.age > other.age
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}>'
stu1 = Student('小明', 18)
stu2 = Student('小花', 20)
a = stu1 + stu2 # a = stu1.__add__(stu2)
print(a) # [<'name': '小明', 'age': 18>, <'name': '小花', 'age': 20>]
# 求年龄最大的学生max高阶用法
print(max(a, key=lambda x: x.age))
# 定制魔法方法实现运算符 > 的功能
print(stu1 > stu2) # False
继承
-
继承就是让子类直接拥有父类的属性和方法
- 子类 - 继承者
- 父类 - 被继承者,又叫超类
-
语法
class 类名(父类, 父类2, 父类3, ...): 说明文档 类的内容
-
注意:如果定义类的时候没有写继承关系,那么这个类默认继承基类object
- class 类名: == class 类名(object):
子类添加新属性和方法
添加方法和添加类属性
- 直接在子类中定义新的类属性和方法
添加对象属性
-
子类添加对象属性后不能直接调用父类的对象属性;
-
在子类对象属性中使用super().__init__()来调用父类的对象属性;
class Person:
num = 99
def __init__(self):
self.name = '张三'
self.age = 20
self.gender = '男'
def eat(self, food):
print(f'在吃{food}')
@staticmethod
def func1():
print('静态方法')
class Student(Person):
x = '学生'
def __init__(self):
# 调用当前类的父类的方法
super().__init__()
self.study_id = '0001'
self.subject = 'Python'
def study(self):
print('天天向上')
@classmethod
def func2(cls):
print('类方法')
# 继承的语法
stu = Student()
print(stu.name, stu.age, stu.gender) # 张三 20 男
stu.eat('包子') # 张三在吃包子
stu.func1() # 静态方法
print(stu.num) # 99
继承细节问题
子类和父类有相同的方法
class A:
def func1(self):
print('A的func1')
class B(A):
def func1(self):
print('B的func1')
B().func1() # B的func1
A().func1() # A的func1
super的用法
- super(类, 对象).方法() - 调用指定类的父类的指定方法
- 注意:()括号中,该对象必须是括号中类的对象
class A:
def func1(self):
print('A的func1')
class B(A):
def func2(self):
super(B, self).func1() # A的func1
print('B的func2') # B的func2
B().func2() # A的func1 B的func2
多继承
- 子类只能继承第一个父类的对象属性,方法和类属性都可以继承
class A:
num = 1
def __init__(self):
self.x = 2
self.y = 3
def func_A(self):
print('对象方法A')
class B:
mess = 'a'
def __init__(self):
self.m = 'b'
self.n = 'c'
def func_B(self):
print('对象方法B')
class C(A, B):
pass
# 类属性
c = C()
print(c.num, c.mess) # 1 a
# 方法
c.func_B() # 对象方法B
c.func_A() # 对象方法A
# 对象属性
print(c.x, c.y) # 2 3
# print(c.m, c.n) # AttributeError: 'C' object has no attribute 'm'
私有化
-
访问权限(属性和方法的权限):公开的、保护的、私有的
- 公开的 - 在类的外部可以使用、类的内部可以使用、也可以被继承
- 保护的 - 在类的外部不能使用、类的内部可以使用、也可以被继承
- 私有的 - 只能在类的内部使用、不能被继承、也不能在外部使用
- python中类的内容的权限只有一种:公开的
-
python中私有化的方法在变量及方法前面加’__’
-
python私有化是一种假私有化,本质就是在存储数据的时候在私有化名字前加’类名’;
-
python中的保护:在名字前加""(一个下划线)
class A:
m = 100
__n = 200
@staticmethod
def func1():
print('公开的')
@staticmethod
def __func2():
print('私有的')
a = A()
print(A.m) # 100
a.func1() # 公开的
# print(A.n) # AttributeError: type object 'A' has no attribute 'n'
# a.func2() # AttributeError: 'A' object has no attribute 'func2'
print(A._A__n) # 200
a._A__func2() # 私有的
拷贝
直接赋值
- 直接将变量中的地址赋值给另外一个变量,赋值后两个变量指向同一块内存区域,并且相互影响
浅拷贝
- 列表切片、列表.copy()、字典.copy()等
- 复制原数据产生一个新的数据,将新的数据的地址返回;如果源数据中有子对象(可变数据),不会复制子对象;
深拷贝
- 复制源数据产生一个新的数据,将新的数据的地址返回,如果原数据中有子对象,子对象也会被复制;
from copy import copy, deepcopy
class Dog:
def __init__(self, name, gender='母'):
self.name = name
self.gender = gender
def __repr__(self):
return str(self.__dict__)
class Person:
def __init__(self, name, age=18, dog=None):
self.name = name
self.age = age
self.dog = dog
def __repr__(self):
return str(self.__dict__)
p1 = Person('小明', dog=Dog('小花'))
p2 = p1
p3 = copy(p1)
p4 = deepcopy(p1)
print(f'p1(源数据):{p1}') # p1(源数据):{'name': '小明', 'age': 18, 'dog': {'name': '小花', 'gender': '母'}}
print(f'p2(赋值后):{p2}') # p2(赋值后):{'name': '小明', 'age': 18, 'dog': {'name': '小花', 'gender': '母'}}
print(f'p3(浅拷贝):{p3}') # p3(浅拷贝):{'name': '小明', 'age': 18, 'dog': {'name': '小花', 'gender': '母'}}
print(f'p4(深拷贝):{p4}') # p4(深拷贝):{'name': '小明', 'age': 18, 'dog': {'name': '小花', 'gender': '母'}}
print('----------------赋值、拷贝、深拷贝前后----------------')
p1.dog.name = '傻逼'
print(f'p1(源数据):{p1}') # p1(源数据):{'name': '小明', 'age': 18, 'dog': {'name': '傻逼', 'gender': '母'}}
print(f'p2(赋值后):{p2}') # p2(赋值后):{'name': '小明', 'age': 18, 'dog': {'name': '傻逼', 'gender': '母'}}
print(f'p3(浅拷贝):{p3}') # p3(浅拷贝):{'name': '小明', 'age': 18, 'dog': {'name': '傻逼', 'gender': '母'}}
print(f'p4(深拷贝):{p4}') # p4(深拷贝):{'name': '小明', 'age': 18, 'dog': {'name': '小花', 'gender': '母'}}
内存管理
内存的申请
- 定义变量保存数据的时候系统会自动申请。
- 定义变量保存的是可变数据,每次都会申请新的内存。
- 如果定义变量保存的是不可变数据,会先检查这个数据是否保存过,如果已经存储过就不会再申请新的内存。
释放
- 如果一个数据的引用计数为0,那么这个数据就会被自动释放;
- 引用:保存数据地址的对象就是这个数据的引用;