Python类和对象

在 Python 中,类(Class)和对象(Object)是面向对象编程(OOP)的两个主要方面。

一、类(Class)

类是创建对象的蓝图。我们可以把类想象成一个模板,它定义了一种新的数据类型。一旦定义了类,我们就可以根据该类创建对象。
类由一组属性(用来描述对象的特性,例如颜色、大小等)和一组方法(用来描述对象的行为,例如跑、跳等)组成。

# 定义一个简单的类
class Dog:
    def __init__(self, name):
        self.name = name

    def bark(self):
        return "Woof!"

在这个例子中,Dog就是一个类。它有一个属性(name)和一个方法(bark),__init__是这个类的构造方法用于初始化一些属性或完成一些初始化的任务。

二、对象(Object)


对象是类的实例。基于类的定义,我们可以创建出多个具有相同属性和方法的对象。

# 创建一个Dog类的对象
my_dog = Dog("Fido")

# Accessing the 'name' attribute of the 'my_dog' object
print(my_dog.name)  # 输出: Fido

# Calling the 'bark' method of the 'my_dog' object
print(my_dog.bark())  # 输出: Woof!

在这个例子中,my_dog 就是一个对象,它是 Dog 类的一个实例。我们可以访问它的属性 name,并调用它的方法 bark。
要注意的是,每个对象都拥有自己的属性和方法,这些属性和方法都是独立于其他对象的。也就是说,如果我们创建了一个新的 Dog 对象 another_dog = Dog("Spot"),another_dog 的 name 属性就会有自己独立的值,不会影响到 my_dog 的 name 属性的值,反之亦然。

三、类方法

在 Python 中,类方法是那些被类对象而非其实例对象调用的方法。Python 的类层级结构中的每层类定义都可以增加正常的方法和类方法。类方法在 Python 中使用 @classmethod 装饰器和特殊的第一参数来声明。(其实就是java的静态方法)调用不需要对类进行初始化。

class MyClass:
    @classmethod
    def class_method(cls, arg1, arg2):
        print(f"Calling class_method with {arg1} and {arg2}")


# 调用类方法
MyClass.class_method("Hello", "World")

这里的 class_method() 是一个类方法,第一个参数 cls 是类本身,和实例方法中的 self 类似。@classmethod 是一个装饰器,用来指示 class_method() 是一个类方法。

类方法的一个常见用途是定义可以创建类实例的工厂方法。例如:

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

    @classmethod
    def from_birth_year(cls, name, birth_year):
        return cls(name, datetime.date.today().year - birth_year)


person = Person.from_birth_year("Bob", 1990)

在这个示例中,from_birth_year() 是一个类方法,它使用人的出生年份计算年龄,然后创建并返回一个 Person 类的实例。

四、魔术方法

Python中的魔术方法(Magic Methods)是一种特殊的方法,它们以双下划线开头和结尾,例如__init__,__str__,__add__等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。

以下是一些常用的Python魔术方法:

__init__(self, ...): 初始化对象,通常用于设置对象的属性。
__str__(self): 定义对象的字符串表示形式,可通过str(object)或print(object)调用。例如,您可以返回一个字符串,描述对象的属性。
__repr__(self): 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)调用。
__len__(self): 定义对象的长度,可通过len(object)调用。通常在自定义容器类中使用。
__getitem__(self, key): 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]。
__setitem__(self, key, value): 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value。
__delitem__(self, key): 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]。
__iter__(self): 定义迭代器,使对象可迭代,可用于for循环。
__next__(self): 定义迭代器的下一个元素,通常与__iter__一起使用。
__add__(self, other): 定义对象相加的行为,使对象可以使用+运算符相加。例如,object1 + object2。
__sub__(self, other): 定义对象相减的行为,使对象可以使用-运算符相减。
__eq__(self, other): 定义对象相等性的行为,使对象可以使用==运算符比较。
__lt__(self, other): 定义对象小于其他对象的行为,使对象可以使用<运算符比较。
__gt__(self, other): 定义对象大于其他对象的行为,使对象可以使用>运算符比较。

下面是一个简单的例子:

class ComplexNumber:
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag

    def __add__(self, other):
        return ComplexNumber(self.real + other.real, self.imag + other.imag)

    def __repr__(self):
        return f"ComplexNumber({self.real}, {self.imag})"


# 使用自定义的 `__add__` 魔术方法
c1 = ComplexNumber(1, 2)
c2 = ComplexNumber(2, 3)
c3 = c1 + c2  # ComplexNumber(3, 5)

# 使用自定义的 `__repr__` 魔术方法
print(c1)  # ComplexNumber(1, 2)

在这个例子中,我们定义了一个表示复数的 ComplexNumber 类,并为它定义了一些魔术方法:__init__ 构造函数用于初始化,__add__ 实现了加法操作,__repr__ 则用于显示实例的字符串表示。

五、继承

在 Python 中,继承是面向对象编程的一个基本概念。子类(派生类)可以继承父类(基类)的属性和方法。
以下是 Python 继承的简单示例: 

# 父类
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError("Subclass must implement this abstract method")


# 子类
class Dog(Animal):
    def speak(self):
        return 'Woof!'


# 子类
class Cat(Animal):
    def speak(self):
        return 'Meow!'


a = Animal('Fred')
d = Dog('Fido')
c = Cat('Whiskers')
print(d.speak())  # 输出: 'Woof!'
print(c.speak())  # 输出: 'Meow!'

在这个例子中,Animal 类是 Dog 类和 Cat 类的父类。当你为 Dog 或 Cat 实例调用 speak 函数时,它们会执行属于各自类的 speak 方法。这是因为这些子类重写(override)了父类的 speak 方法。
如果子类没有实现父类的某个方法,那么将会使用父类的实现。这就是继承的一个主要优点:如果所有的动物都有相似的行为,但每种动物执行这些行为的方式又各不相同,那么你可以在父类中定义一个默认行为(可能会抛出 NotImplementedError 异常),并且在每个子类中提供专门的行为。
请注意这个例子还展示了 Python 对于抽象方法的支持。方法 Animal.speak() 等同于一个抽象方法,其目的是要被子类重写。如果有任何未提供 speak() 实现的 Animal 子类实例调用了 speak(),Python 将抛出 NotImplementedError 异常

六、多继承 

在 Python 中,一个类可以同时继承多个父类。这种特性就叫做多重继承。
Python 的多重继承通过在类定义时提供多个父类,且父类之间用逗号分隔即可实现。下面是一个例子:

# 父类 A
class A:
    def __init__(self):
        super().__init__()
        self.name = "Class A"


# 父类 B
class B:
    def __init__(self):
        super().__init__()
        self.name = "Class B"


# 多重继承
class C(A, B):
    def __init__(self):
        super().__init__()


# 创建 C 的对象
object_c = C()

# 输出: Class A
print(object_c.name)

在这个例子中,Class C 继承了 Class A 和 Class B。我们可以看到当 super().__init__() 被调用时,Python 使用一个称为方法解析顺序(Method Resolution Order, MRO)的算法来确定应该首先调用哪个父类的方法。上面的例子中,Class A 在 Class B 之前列出,所以 Class A 的 __init__() 方法被首先调用。
请注意,多重继承有其复杂性,并且可能导致一些难以预见和调试的问题,因此应谨慎使用。如果能采用继承和组合的方式来实现同样的功能,通常建议避免使用多重继承。

七、方法重写

在 Python 中,方法重写是面向对象编程中的一个重要概念。当子类需要改变从父类继承的某个方法的行为时,就需要使用方法重写(也叫方法覆盖)。下面是一个例子:

class Animal:
    def speak(self):
        return '...'


class Dog(Animal):
    def speak(self):
        return 'Woof'


class Cat(Animal):
    def speak(self):
        return 'Meow'


a = Animal()
d = Dog()
c = Cat()

print(a.speak())  # 输出: '...'
print(d.speak())  # 输出: 'Woof'
print(c.speak())  # 输出: 'Meow'

在这个例子中,Dog 类和 Cat 类都重写了从 Animal 类继承的 speak() 方法。
方法重写的一个主要目的是让子类可以展现出与父类不同的行为。在上述例子中,虽然所有的类都有 speak 方法,但每种类 speak 的方式都各不相同。
注意:如果子类想在保持父类方法的基础上添加一些新的行为,你可以使用 super() 函数来调用父类的方法。例如:

class Dog(Animal):
    def speak(self):
        original_speech = super().speak()
        return f'{original_speech} - this is modified by Dog class. Now I say Woof'

在这个重写的 speak() 方法中,我们首先通过 super().speak() 调用 Animal 类的原始 speak 方法,然后返回一个修改后的字符串。

八、私有属性与方法

在 Python 中,按照约定,以单下划线开头的变量和方法被视为私有的。这只是一种约定,并没有真正阻止外部访问,例如:

class MyClass:
    def __init__(self):
        self._my_private_var = 0


obj = MyClass()
print(obj._my_private_var)  # 输出: 0

对于需要严格控制访问的属性或方法,Python 提供了一种方法使其变得“更私有”。这种方法是通过双下划线(__)前缀来实现。例如:

class MyClass:
    def __init__(self):
        self.__my_really_private_var = 0


obj = MyClass()
print(obj.__my_really_private_var)  # 抛出 AttributeError

在这个例子中,试图直接访问变量 __my_really_private_var 将会抛出 AttributeError。Python 实际上修改了变量的名称,你可以通过 obj._MyClass__my_really_private_var 仍然可以访问,但这通常不建议这样做,因为这种方法并不是公开的 API。
这种带有两个下划线的名称修改(name mangling)也适用于方法名称,即如果一个方法以 __ 开头,那么在类外部是无法直接访问的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值