面向对象编程


面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
面向对象的设计思想是抽象出Class,根据Class创建Instance。

类和实例

类的定义

类(Class)是面向对象编程(OOP)中的一个核心概念。它是一种数据结构,用于定义对象的蓝图或模板。通过类,可以创建具有特定属性和方法的对象,并对对象进行操作。类不仅定义了对象的属性(通常通过类的变量表示),还定义了对象能执行的行为(通常通过类的方法表示)。

class Person:
    # 类的属性和方法
    pass

class后面紧接着是类名,即Person,类名通常是大写开头的单词

类的属性

类的属性是对象的特征,通常是类中的变量。例如,可以为一个 Student 类添加 name 和 age 属性:

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

初始化方法 init:这是一个特殊的方法,每次创建类的实例时,都会自动调用它。它用于初始化对象的属性。
__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
⚠️特殊方法__init__前后分别有两个下划线!!!

类的方法

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

    def greet(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

在Student类的内部定义访问数据的函数greet,这样,就把“数据”给封装起来了。

创建实例

定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()实现的:

person1 = Person("Alice", 30)  # 创建一个 Person 类的实例
person1 .greet()  # 调用实例方法,调用时self参数不用传递

# 输出结果:
Hello, my name is Alice and I am 30 years old.

类的封装

封装是将数据和操作数据的代码组合在一起,限制对对象内部状态的访问。通过方法来控制外部对对象属性的访问,而不是直接访问属性。
从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的name、age属性:

person1 = Person("Alice", 30)
print(person1 .age)
person1.age = 20
print(person1.age)

30
20

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def greet(self):
        print(f"Hello, my name is {self.__name} and I am {self.__age} years old.")

person1 = Student("Alice", 20)
print(person1.__age)
person1.greet()  # 调用实例方法

# 外部访问student1.__age会报错:
Traceback (most recent call last):
  File "D:\Code\work\pythonProject\test.py", line 12, in <module>
    print(person1.__age)
          ^^^^^^^^^^^^^^
AttributeError: 'Person' object has no attribute '__age' 

# 外部调用Student的方法:
Hello, my name is Alice and I am 20 years old.

这样封装之后外部就不可以修改内部数据。
如果希望外部访问Student类的内部数据或者外部进行更改数据,可以在类里定义相关方法,外部调用方法实现。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def greet(self):
        print(f"Hello, my name is {self.__name} and I am {self.__age} years old.")

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    def set_age(self, age):
        self.__age = age


student1 = Person("Alice", 20)  # 创建一个 Person 类的实例
student1.greet()  # 调用实例方法
print(student1.get_name())
print(student1.get_age())
student1.set_age(25)
print(student1.get_age())


Hello, my name is Alice and I am 20 years old.
Alice
20
25

将修改数据的操作定义在类的方法里可以在方法中对参数进行检查,避免无效数据:

# 将上面的set_age函数添加判断条件:
    def set_age(self, age):
        if age < 0:
            raise ValueError("Age cannot be negative.")
        self.__age = age

调用set_age,传入参数-3:

student1.set_age(-3)
print(student1.get_age())

Traceback (most recent call last):
  File "D:\Code\work\pythonProject\test.py", line 25, in <module>
    student1.set_age(-3)
  File "D:\Code\work\pythonProject\test.py", line 17, in set_age
    raise ValueError("Age cannot be negative.")
ValueError: Age cannot be negative.

类的继承

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。子类继承父类的属性和方法,子类可以扩展或重写父类的方法。

class Student(Person):  # 继承自 Person 类
    def __init__(self, name, age, grade):
        super().__init__(name, age)  # 调用父类的 __init__ 方法
        self.grade = grade  # 新增属性

    def greet(self):
        print(f"Hello, I am {self.name}, {self.age} years old, and I am in grade {self.grade}.")

类的多态

当子类和父类都存在相同的方法时,我们说,子类的方法覆盖了父类的方法,在代码运行的时候,总是会调用子类的方法。这样,我们就获得了继承的另一个好处:多态。

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        print("Woof!")

class Cat(Animal):
    def speak(self):
        print("Meow!")

def make_animal_speak(animal):
    animal.speak()

dog = Dog()
cat = Cat()

make_animal_speak(dog)  # 输出 "Woof!"
make_animal_speak(cat)  # 输出 "Meow!"

实例属性和类属性

给实例绑定属性的方法是通过实例变量,或者通过self变量:

class Student(object):
    def __init__(self, name):
        self.name = name

s = Student('Bob')
s.score = 90

直接在class中定义属性,这种属性是类属性,归Student类所有:

class Student(object):
    name = 'Student'
class Student(object):
    count = 0

    def __init__(self, name):
        self.name = name
        Student.count += 1


# 测试:
if Student.count != 0:
    print('测试失败!')
else:
    bart = Student('Bart')
    print('Students:', Student.count)

    lisa = Student('lisa')
    print('Students:', Student.count)

Students: 1
Students: 2

使用__slots__

slots__只能定义在类定义中,用于限定该类能添加的属性,如果定义了__slots,那么实例化对象只能添加__slots__中定义的属性,否则会抛出AttributeError异常。

class Student(object):
    count = 0
    __slots__ = ('name', 'age')  # 用tuple定义允许绑定的属性名称


class Foo(Student):
    pass
   
s = Student()
s.name = 'Michael'
print(s.name)
print(Student.__slots__)
print(s.__slots__)
stu = Foo()
stu.name = 'test'
print(stu.name)
stu.age = 12
print(stu.age)
stu.score = 99
print(stu.score)
print(stu.__slots__)
print(Student.__slots__)

Michael
('name', 'age')
('name', 'age')
test
12
99
('name', 'age')
('name', 'age')

使用@property

在设置属性值时,既想检查数据正确性又想简便实现,可以使用@property装饰器

class Student(object):
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    @property
    def score(self):
        return self.__score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('成绩必须是整数!')
        if value < 0 or value > 100:
            raise ValueError('成绩必须在0 ~ 100之间!')
        self.__score = value


s = Student('Bob', 59)
print(s.score)  # 输出:59
s.score = 60
print(s.score)  # 输出:60
s.score = 'p'  # ValueError: 成绩必须是整数!
s.score = 120  # ValueError: 成绩必须在0 ~ 100之间!

多重继承

一个子类可以继承多个父类,从而获得多个父类的属性方法。
例如:

class Animal(object):
    pass

# 大类:
class Mammal(Animal):  # 哺乳动物
    pass

class Bird(Animal):  # 鸟
    pass
# 其他功能类:
class Runnable(object):  # 能跑
    def run(self):
        print('Running...')

class Flyable(object):  # 能飞
    def fly(self):
        print('Flying...')

# 各种动物:
class Dog(Mammal, Runnable):  # 狗狗,哺乳动物且能跑
    pass
class Bat(Mammal, Flyable):  # 蝙蝠,哺乳动物且能飞
    pass

class Parrot(Bird, Flyable):  # 鹦鹉,鸟类且能飞
    pass

class Ostrich(Bird, Runnable):  # 鸵鸟,鸟类且能跑
    pass

枚举类

枚举(Enum)类用于定义一组命名的常量,这些常量在逻辑上是相互关联的。
定义一组月份常量:

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
# 枚举所有成员:
for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)
# 输出:
Jan => Month.Jan , 1
Feb => Month.Feb , 2
Mar => Month.Mar , 3
Apr => Month.Apr , 4
May => Month.May , 5
Jun => Month.Jun , 6
Jul => Month.Jul , 7
Aug => Month.Aug , 8
Sep => Month.Sep , 9
Oct => Month.Oct , 10
Nov => Month.Nov , 11
Dec => Month.Dec , 12

value属性则是自动赋给成员的int常量,默认从1开始计数。

从Enum派生出自定义类:

from enum import Enum

class Status(Enum):
    ACTIVE = 1
    INACTIVE = 0
    PENDING = 3
    SUSPENDED = 4
# 通过名称访问
print(Status.ACTIVE)
# 输出: Status.ACTIVE

# 通过值访问
print(Status(1))
# 输出: Status.ACTIVE

print(Status.ACTIVE.name)   # 输出: ACTIVE
print(Status.ACTIVE.value)  # 输出: 1

for status in Status:
    print(status)
# 输出:
Status.ACTIVE
Status.INACTIVE
Status.PENDING
Status.SUSPENDED

简单应用:创建学生实例,不用输入字符串添加学生性别

Gender = Enum('Gender', ('Male', 'Female'))
class Student(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = Gender(gender)
# 测试:
bart = Student('Bart', 1)
print(bart.gender)

#输出:
Gender.Male

元类

元类(Metaclass)是用于创建类的 “类”。简单来说,元类控制类的创建和行为,就像类控制实例的创建和行为一样。通过元类,你可以定制类的创建过程、添加或修改类的属性和方法,以及实现自定义的类行为。

元类的作用

元类的主要作用是在类创建时,自动地对类进行修改或增强。它的常见用途包括:
1.自动注册类:在创建类时自动把类加入某个注册表中。
2.验证类的属性:检查类是否包含某些特定的属性和方法。
3.修改类的属性或方法:在类创建时动态添加或修改类的方法。
4.实现单例模式:通过元类实现类的单例行为。

type()

type 是最常见的元类。我们可以用它动态地创建类,也可以定义自己的元类来定制类的行为。
用 type 动态创建类:

def fn(self, name='world'):  # 先定义函数
    print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
h = Hello()
h.hello()

# 输出:
Hello, world.

要创建一个class对象,type()函数依次传入3个参数:
1.class的名称;
2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。

metaclass

metaclass 是用于定义和控制类创建过程的特殊类。先定义metaclass,就可以创建类,最后创建实例。

# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)
       
class MyList(list, metaclass=ListMetaclass):
    pass
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

勇敢磊磊学IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值