面向对象进阶

本文详细介绍了Python面向对象编程中的对象属性的增删改查,包括使用`getattr`和`setattr`函数、内置属性如`__dict__`、`__class__`、`__name__`等,以及如何进行私有化。此外,还讲解了类的继承、`super`的使用以及运算符重载。文章最后探讨了内存管理和拷贝的概念,包括浅拷贝与深拷贝的区别。
摘要由CSDN通过智能技术生成

面向对象进阶

对象属性的增删改查

class Student:
    def __init__(self, name, gender='男', age=18, tel=''):
        self.name = name
        self.gender = gender
        self.age = age
        self.tel = tel

    def __repr__(self):
        return str(self.__dict__)


stu1 = Student('小明', '男', 18, '110')

1.查 - 获取属性的值
对象.属性 - 获取执行属性对应的值,如果属性不存在报错
getattr(对象, 属性名) - 获取执行属性对应的值,如果属性不存在报错
getattr(对象, 属性名, 默认值) - 获取执行属性对应的值,如果属性不存在不报错,直接返回指定的默认值

print(stu1.name)
print(getattr(stu1, 'name'))

方法二可以动态确定需要获取的内容

# value = input('学生的哪个信息: name? age? tel? gender?:')
# # print(stu1.value)
# print(getattr(stu1, value))

# print(stu1.score)    # AttributeError: 'Student' object has no attribute 'score'
print(getattr(stu1, 'score', 0))

2.增、改
对象.属性 = 值 - 如果属性存在就是修改,属性不存在就是添加
setattr(对象, 属性名, 值) - 如果属性存在就是修改,属性不存在就是添加

stu1.name = '小花'
print(stu1)

stu1.score = 100
print(stu1, stu1.score)

setattr(stu1, 'height', 170)
print(stu1)

setattr(stu1, 'age', 30)
print(stu1)

  1. del 对象.属性
    delattr(对象, 属性名)
del stu1.gender
print(stu1)
# print(stu1.gender)  # AttributeError: 'Student' object has no attribute 'gender'

delattr(stu1, 'tel')
print(stu1)

内置属性

class A:
    x = 10

    def __init__(self, m=10, n='hello', p=True):
        self.m = m
        self.n = n
        self.p = p
        self.name = '小花'

    def f1(self):
        print(f'对象方法: {self.m}')

    @classmethod
    def f2(cls):
        print(f'类方法:{cls.x}')

    @staticmethod
    def f3():
        print('静态方法')


a = A()

1.内置属性 - 创建类的时候系统自动添加的属性就是内置属性
1)_dict_
类._dict_ - 将类转换成字典,将所有的类属性名作为键,类属性对应的值作为值
对象._dict_ - 将对象转换成字典,对象属性名是键,对象属性对应的值是值

print(A.__dict__)
print(a.__dict__)       # {'m': 10, 'n': 'hello', 'p': True}

2._class_

对象._class_ - 获取对象对应的类,功能和type一样

print(a.__class__, type(a))

3._name_

类._name_ - 获取类名

print(A.__name__)    # 'A'

4._doc_

类._doc_ - 获取类的说明文档

print(int.__doc__)

5._module_

类._module_ - 获取定义指定类的模块名

print(A.__module__, int.__module__)

类._base_ - 获取当前类的父类
类._bases_ - 获取当前类所有的父类

print(A.__base__)   # <class 'object'>
print(A.__bases__)  # (<class 'object'>,)

私有化

1.访问权限(面向对语言通用)

公开的:属性和方法在类的内部、类的外部都可以使用,也可以被继承 (python中所有的属性和方法都是公开的)
保护的:属性和方法在类的内部可以使用,也可以被继承
私有的:属性和方法只能在类的内部使用

2.python私有化是假的: 在名字前加__

class A:
    num = 18
    __x = 20

    def __init__(self):
        self.__name = '小明'

    def f1(self):
        print(A.num)

    @classmethod
    def f2(cls):
        print('内部:', A.__x)
        A.__f3()

    @staticmethod
    def __f3():
        pass

# print(A.num)


A.f2()
# print('外部:', A.__x)
# print(A.__dict__)
print('外部:', A._A__x)

a = A()
# print(a.__name)

# A.__f3()

类的继承

1.什么继承

继承就是让子类直接拥有父类所有的属性和方法。
子类 - 继承者
父类 - 被继承者,又叫超类

2.继承的语法

class 类名(父类1, 父类2, 父类3,…):
类的内容

注意:如果在定义类的时候没有添加继承关系,那么这个类默认继承Python的基类object

class Person:
    num = 61

    def __init__(self):
        self.name = '小明'
        self.age = 18
        self.gender = '男'

    def eat(self, food):
        print(f'{self.name}在吃{food}')


class Student(Person):
    pass


print(Student.num)

stu = Student()
print(stu.name, stu.age, stu.gender)

stu.eat('面条')
  1. 在子类中添加属性和方法

1)添加类属性和方法
在子类中直接定义新的类属性和新的方法

2)添加对象属性
类中的方法的调用过程:先看当前类中是否有对应的方法,如果有就直接调用自己类中的这个方法;如果没有就去看父类中有没有,如果有直接调用,没有看父类的父类…以此类推,如到找object都没有找到相应的方法,才会报错。

继承的时候,子类之所以可以继承父类的对象属性,是因为继承了父类的_init__方法。如果子类中有_init,那么父类的__init__就不会被继承,那么对象属性就不会被继承。

总结:在子类添加__init__的同时用super()去调用父类的__init__方法

class Teacher(Person):
    profession = '老师'

    def __init__(self):
        # super().__init__()     # 调用当前类的父类的__init__()
        super(Teacher, self).__init__()
        self.school = '千锋教育'

    def teach(self):
        print('教学')

    @staticmethod
    def message():
        print('教书育人')


print(Teacher.num, Teacher.profession)

t1 = Teacher()
# t1.eat('火锅')
t1.teach()

Teacher.message()

print(t1.school)
print(t1.name, t1.age, t1.gender)

4.super的使用

super(类, 对象).方法 - 调用指定类的父类的方法 (注意:后面的对象必须是前面的类或子类的对象)
super().方法 - 调用当前类的父类的方法

class A:
    def funcA(self):
        print('A')

    def func1(self):
        print('A1')


class B(A):
    def funcB(self):
        print('B')

    def func1(self):
        print('B1')


class C(B):
    def funcC(self):
        print('C')

    def func1(self):
        print('C1')
        # super().func1()
        # super(C, self).func1()
        # super(B, self).func1()
        super(Student, Student()).eat('苹果')


print('==============================================')
c = C()
c.func1()


class Animal:
    def __init__(self, age, gender='雄'):
        self.gender = gender
        self.age = age


class Dog(Animal):
    def __init__(self, name, color, gender='雄'):
        super().__init__(0, gender)
        self.name = name
        self.color = color


a = Animal(2)

d = Dog('大黄', '黄色')

1.魔法方法

类中自带的以__开头并且以__结尾的方法就是魔法方法,所有的魔法方法都不需要程序去调用,会在特定情况下自动调用。
这些魔法方法中有一部分方法是在对象使用运算符的时候会被自动调用。

每一个运算符都有一个固定的魔法方法,某种数据是否支持某种,就看这个数据对应的类中有没有实现对应的魔法方法。

10 + 20         # 10.__add__(20)
'abc' + '234'   # 'abc'.__add__('234')

10.2 > 20py
# {'a': 10} + {'b': 20}   # TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
# class A:
#     def func1(self):
#         print('A')
#
#
# class B:
#     def func1(self):
#         print('B')
#
# x = B()
# x.func1()
  1. 重载运算符 - 在自己的类中通过现实运算的魔法方法来让自己的类的对象支持指定的运算符
    自己定义的类默认支持比较是否相等
from copy import copy


class Student:
    def __init__(self, name='小明', age=18, score=60):
        self.name = name
        self.age = age
        self.score = score

    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}>'

    # self + other, 返回值就是加法运算的结果
    def __add__(self, other):
        # self = stu1, other=stu2
        # return self.age + other.age
        return [self, other]

    def __mul__(self, other: int):
        result = []
        for _ in range(other):
            result.append(copy(self))
        return result

    # self > other
    def __gt__(self, other):
        return self.score > other.score


stu1 = Student()
stu2 = Student('小花', 22, 45)
print(stu1 != stu2)

print(stu1 + stu2)    # stu1.__add__(stu2)
s = stu1 * 3
print(s)
stu1.name = '张三'
print(s)


students = [
    Student('stu1', 23, 98),
    Student('stu2', 18, 87),
    Student('stu3', 25, 99),
    Student('stu4', 22, 80)
]
print(students)

print('======')
print(max(students))
students.sort()
print(students)

def max1(seq):
    m = seq[0]
    for x in seq[1:]:
        if x > m:
            m = x
    return m


"""
seq = students
m = Student('stu1', 23, 98)
x = Student('stu2', 18, 87): if Student('stu2', 18, 87) > Student('stu1', 23, 98): 
"""

拷贝

from copy import copy, deepcopy

1.浅拷贝和深拷贝

不管是浅拷贝还是深拷贝都是将被拷贝的数据复制产生一个新的数据,然后将新的数据的地址返回。
如果被拷贝的对象中有子对象(可变数据),浅拷贝不会对子对象进行拷贝(人变成不一样的人,但是狗还是同一条狗),
深拷贝会对子对象进行拷贝(人变成不一样的人,狗也会变成不一样的狗)

class Dog:
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>'


class Person:
    def __init__(self, name, age, dog=None):
        self.name = name
        self.age = age
        self.dog = dog

    def __repr__(self):
        return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>'


p1 = Person('小明', 18, Dog('大黄', '黄色'))
print('p1:', p1)

# 直接赋值  - 两个变量保存同一个数据的地址
p2 = p1
print('p2:', p2)

# 浅拷贝
p3 = copy(p1)
print('p3:', p3)

# 深拷贝
p4 = deepcopy(p1)
print('p4:', p4)

print('======================修改年龄后==================')
p1.age = 20
p1.dog.name = '旺财'
print('p1:', p1)
print('p2:', p2)
print('p3:', p3)
print('p4:', p4)

内存管理

  1. 内存的申请

当使用变量保存数据的时候系统会自动在堆中申请空间保存数据,同时让变量保存数据在内存中地址(python中的变量全是指针变量)。

如果需要保存的数据是不可变的数据,系统会先检查当前内存中是否已经存在这个数据,如果有直接返回已经保存的数据的地址,
如果没有才会重新申请新的内存保存数据。

a = 100
b = 100
print(id(a), id(b))    # 4428060448 4428060448

x = 'abc'
y = 'abc'
print(id(x), id(y))     # 4445987760 4445987760

m = (10, 20)
n = (10, 20)
print(id(m), id(n))     # 4468933696 4468933696

l1 = [10, 20]
l2 = [10, 20]
print(id(l1), id(l2))     # 4511662208 4511664384

2.内存释放

原则:如果数据有引用数据就不会被销毁(不会释放),如果数据没有引用(引用计数为0)就会被自动销毁(释放)。

list1 = [10, 20, 30]
list2 = list1
list3 = [1, list1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值