Python之面向对象和类

一.类

1.类的定义:

class 类名:

"""注释 """

pass

2.实例的创建:

实例 = 类名(parameterlist)

parameterlist:定义类时__init__()方法的参数,如果该方法只有一个self参数,parameterlist可以省略

python 复制代码
class Goose():
    """定义了鹅类"""
    pass

goose =  Goose()
print(goose)#<__main__.Goose object at 0x00000229213C6900>

3.创建类的构造函数方法:init()方法

定义类时,通常会包含一个__init__()方法。该方法是构造函数方法,每当创建一个类的新实例时,Python都会自动执行它。

1.init()方法用来初始化新创建对象,在一个对象被创建以后会立即调用。

  1. init()方法必须包含一个self参数,并且必须是第一个参数。self参数是一个指向实例本身的引用,用于访问类中的属性和方法。(相当于JAVA中的this)

3.当__init__()方法只有一个参数时,在创建类的实例时,不需要指定实际参数。

4.init()方法的名称是以两个连续下划线开头和结尾,这是一种约定,用于区分Python默认方法和普通方法。

5.init()方法可以分为无参构造方法和有参构造方法。当使用无参构造方法创建对象时,所有对象的属性都有相同的初始值;当使用有参构造为法创建对象时,对象的属性可以有不同的初始值;

6.如果你写多个构造方法,但是你在调用的时候,后写的构造方法会取代前面的构造方法(无论这两者参数上是否有区别),这点与JAVA不一样,所以一般一个类只有一个构造方法。

7.一般来说,构造方法里面写初始化内容

python 复制代码
class Goose():
    def __init__(self):
        print ("self:",self) #self: <__main__.Goose object at 0x0000022CD8766900>
        print("type of self:",type(self))#type of self: <class '__main__.Goose'>
        print("我是鹅类,我会自动执行该语句")           
g=Goose()

在__init__()方法中,除了self参数外,还可以自定义一些参数,参数间使用逗号","进行分隔。

python 复制代码
class Goose:
    '''鹅类'''
    def __init__(self,beak,wing,claw):
        print("我是鹅类!我有以下特征:")
        print(beak)
        print(wing)
        print(claw)
beak_1 = "喙的基部较高,长度和头部的长度几乎相等"
wing_1 = "翅膀长而尖"
claw_1 = "爪子是蹼壮的"
wildGoose = Goose(beak_1,wing_1,claw_1)

当然,也可以不用构造函数(一般不推荐这样)

python 复制代码
class Rect1():
    def getPeri(self,a,b):
        print("周长为:",(a+b)*2)
    def getArea(self,a,b):
        print("面积为:",a*b)
r1=Rect1()
r1.getPeri(3,4)
r1.getArea(3,4)
print(r1.__dict__)


class Rect2():
    def __init__(self,a,b):
        self.a=a
        self.b=b
    def getPeri(self):
        print("周长为:",(self.a+self.b)*2)
    def getArea(self):
        print("面积为:",self.a*self.b)
r2=Rect2(5,6)
r2.getPeri()
r2.getArea()
print(r2.__dict__)

二.类的成员

1.类的成员,静态定义

定义属性并访问

数据成员是指在类中定义的变量,即属性,根据定义位置,又可以分为类属性和实例属性。

① 类属性

类属性是指定义在类中,并且在函数体外的属性。

类属性可以在类的所有实例之间共享值,也就是在所有实例化的对象中公用。

类属性可以通过类名称或者实例名访问。

python 复制代码
class Goose:
    '''鹅类'''
    neck = "脖子较长"
    wing = "振翅频率高"
    leg = "腿位于身体的中心支点,行走自如"
    def __init__(self):
        print("我属于鹅类!我有以下特征:")
        print(self.neck)
        print(self.wing)
        print(self.leg)
geese = Goose()

2.动态添加属性

在Python中除了可以通过类名称访问类属性,还可以动态地为类和对象添加属性

python 复制代码
class Goose:
    '''鹅类'''
    neck = "脖子较长"
    wing = "振翅频率高"
    leg = "腿位于身体的中心支点,行走自如"
    def __init__(self):
        print("我属于鹅类!我有以下特征:")
        print(Goose.neck)
        print(Goose.wing)
        print(Goose.leg)

geese = Goose()
#在类外,动态的为对象添加属性
geese.beak = "喙的基部较高,长度和头部的长度几乎相等"
print("鹅的喙:",geese.beak)

3.实例属性

实例属性,在JAVA中类似于对象的属性(官方不是这个叫法),实例属性是指在类的方法中的属性,就是__init__()构造方法中的参数,只作用于当前实例中。

python 复制代码
class Goose:
    '''鹅类'''
    neck = "脖子较长"
    wing = "振翅频率高"
    leg = "腿位于身体的中心支点,行走自如"
    def __init__(self,name):
        self.name = name
        print("我属于鹅类!我有以下特征:")
        print(self.neck)
        print(self.wing)
        print(self.leg)
        print("实例属性,geese特有:",name)

geese = Goose("娃哈哈")

4.实例属性和类属性的区别

python 复制代码
class Dog:
    # 类属性(所有狗共享)
    species = "Canis familiaris"

    def __init__(self, name):
        # 实例属性(每个狗独立)
        self.name = name

# 创建两个实例
dog1 = Dog("Buddy")
dog2 = Dog("Max")

# 访问类属性(通过类名或实例名)
print(Dog.species)          # 输出: Canis familiaris
print(dog1.species)         # 输出: Canis familiaris

# 访问实例属性(只能通过实例名)
print(dog1.name)            # 输出: Buddy
print(dog2.name)            # 输出: Max

# 尝试通过类名访问实例属性(报错!)
#print(Dog.name)             # AttributeError: type object 'Dog' has no attribute 'name'

# 修改类属性
Dog.species = "Canis lupus"
print(dog1.species)         # 输出: Canis lupus(所有实例同步更新)
print(dog2.species)         # 输出: Canis lupus

# 通过实例修改"类属性"(实际是创建同名实例属性)
dog1.species = "Golden Retriever"
print(dog1.species)         # 输出: Golden Retriever(仅影响dog1)
print(dog2.species)         # 输出: Canis lupus(dog2不受影响)

# 类属性本身未被修改
print(Dog.species)          # 输出: Canis lupus

总结如下:

特性 类属性 实例属性
定义位置 类内部,__init__ 方法之外 通常在 __init__ 方法内
归属 属于类 属于实例
访问方式 类名或实例名均可访问 只能通过实例名访问
共享性 所有实例共享 每个实例独立
修改影响 修改后影响所有实例 修改仅影响当前实例

5.访问限制

为了保证类内部的某些属性或方法不被外部所访问,可以在属性或方法名前面添加单下划线(_foo)、双下划线(__foo)或首尾加双下划线(foo),从而限制访问权限。

其中,单下划线、双下划线、首尾双下划线的作用如下:

首尾双下划线表示定义特殊方法,一般是系统定义名字,如__init__(),一般自定义不推荐这种定义

以单下划线开头的表示protected(保护)类型的成员,只允许类本身和子类进行访问,但

不能使用"from module import *"语句导入

双下划线表示private(私有)类型的成员,只允许定义该方法的类本身进行访问,而且也
不能通过类的实例进行访问,但是可以通过"类的实例名._类名_xxx"方式访问。

python 复制代码
class MyClass:
    def __init__(self):
        self.public_value = "Public"       # 公开属性,可任意访问
        self._protected_value = "Protected"  # 保护属性(单下划线开头)
        self.__private_value = "Private"    # 私有属性(双下划线开头)
    
    def public_method(self):
        print("This is a public method.")
    
    def _protected_method(self):
        print("This is a protected method.")
    
    def __private_method(self):
        print("This is a private method.")
    
    def __special_method__(self):
        print("This is a special method (magic method).")

class SubClass(MyClass):
    """
    继承MyClass类
    """
    def show_protected(self):
        print("接受保护属性 :", self._protected_value)
    
    def try_private(self):
        # 直接访问私有属性会报错
        # print(self.__private_var)  # 报错:AttributeError
        # 但可以通过 _类名__私有属性 的方式访问
        print("Accessing private from subclass:", self._MyClass__private_var)

# 实例化
obj = MyClass()
sub_obj = SubClass()

# 1. 公开成员(无下划线)
print(obj.public_value)            # 输出: Public
obj.public_method()              # 输出: This is a public method.

# 2. 保护成员(单下划线开头)
print(obj._protected_value)        # 输出: Protected(可以访问但不推荐)
obj._protected_method()          # 输出: This is a protected method.
sub_obj.show_protected()         # 输出: Accessing protected from subclass: Protected

# 3. 私有成员(双下划线开头)
# print(obj.__private_var)       # 报错:AttributeError
# obj.__private_method()         # 报错:AttributeError
print(obj._MyClass__private_var) # 输出: Private(通过名称重整访问)
obj._MyClass__private_method()   # 输出: This is a private method.
sub_obj.try_private()            # 输出: Accessing private from subclass: Private

# 4. 特殊方法(首尾双下划线)
obj.__special_method__()         # 输出: This is a special method (magic method).

三.类的方法

1.实例方法

实例方法是指在类中定义的函数。该函数是一种在类的实例上操作的函数。同__init__()方法一样,实例方法的第一个参数必须是self,并且必须包含一个self参数.

语法:

def 方法名(self,参数1,参数2....):

方法内容

调用形式:

只能通过类名.方法名(参数)

python 复制代码
class Goose:
    def __init__(self,beak,wing,claw):
        print("我是鹅类!我有以下特征:")
        print(beak)
        print(wing)
        print(claw)
    def fly(self,state):
        print(state)
'''*******************调用方法**********************'''
beak_1 = "喙的基部较高,长度和头部的长度几乎相等"
wing_1 = "翅膀长而尖"
claw_1 = "爪子是蹼壮的"
wildGoose = Goose(beak_1,wing_1,claw_1)
wildGoose.fly("我飞行的时候,一会排成个人字,一会排成个一字")

2.类方法:

在该方法前面必须加上@classmethod(注解,装饰器),来表明这是一个类方法,且必须带一个参数cls(跟类方法的self一样,但是为了区分两者,这里要写作cls)

调用方式:

推荐 类名.方法名调用,

不推荐 对象名.方法名

作用

  • 用于操作类属性(而不是实例属性)

  • 常用于工厂方法(创建类的不同实例)。

python 复制代码
class Dog:
    """
    species为一个类属性
    @classmethod后的类方法一般为了操作类属型(调用修改等等)
    """
    species = "Canine"  # 类属性
    
    def __init__(self, name):
        self.name = name
    
    @classmethod
    def get_species(cls):
        return cls.species  # 访问类属性
    
    @classmethod
    def from_birth_year(cls, name, birth_year):
        age = 2025 - birth_year
        return cls(name)  # 返回一个新的 Dog 实例,并将name传给新的实例(毕竟建造一个实例需要参数)

# 通过类名调用类方法
print(Dog.get_species())  # 输出: Canine

# 类方法作为工厂方法创建实例
dog = Dog.from_birth_year("Max", 2018)
print(dog.name)  # 输出: Max

注意:return cls(name)意味着

返回一个新的 Dog 实例,并将name传给新的实例(毕竟建造一个实例需要参数)

3..静态方法

在该方法前面必须加上@staticmethod(注解),来表明这是一个静态方法,可以无参数,

调用方式:

推荐 类名.方法名调用,

不推荐 对象名.方法名

  • 作用

    • 与类相关,但不依赖类或实例的状态(即不访问 selfcls)。

    • 类似于普通函数,但逻辑上属于类。

python 复制代码
class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def multiply(a, b):
        return a * b

# 通过类名调用静态方法
print(MathUtils.add(3, 7))  # 输出: 10

# 也可以实例化后调用(但不推荐,静态方法不依赖实例)
utils = MathUtils()
print(utils.multiply(2, 4))  # 输出: 8

4.特殊方法:

(1)析构方法__del__()

Python中的垃圾回收主要采用的是引用计数。引用计数是一种内存管理技术,它通过引用计数器记录所有对象的引用数量,当对象的引用计数器数值为0时,就会将该对象视为垃圾进行回收。

getrefcount()函数是 sys模块中用于统计对象引用数量的函数,其返回结果通常比预期的结果大1。这是因为getrefcount()函数也会统计临时对象的引用。当一个对象的引用计数器数值为0时,就会调用_del__()方法,这个方法就是类的析构方法。系统就会销毁这个对象,收回对象所占用的内存空间。

所以析构方法(即__del_()方法)是用于销毁对象时系统自动调用的方法。每个类中也都默认有一个__del__()目方法,可以显式地定义析构方法。
注意:析构方法不是销毁方法,而是在销毁之前释放资源,销毁方法是靠py底层代码来完成

(2)str()

简单来说就是相当于JAVA中的toString方法

若是不重写,就会用py自带的方法

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 25)
print(p)  # 输出: <__main__.Person object at 0x7f8b1c1b3d90>

若是重写:

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"Person(name={self.name}, age={self.age})"

p = Person("Alice", 25)
print(p)  # 输出: Person(name=Alice, age=25)

四.继承:

跟Java一样有object类为总的父类

1.单继承

基本语法:

class 子类名(父类名)

python 复制代码
# 父类
class Animal:
    def speak(self):
        print("动物发出声音")
    def eat(self):
        print("父类动物在吃东西")

# 子类
class Dog(Animal):  # Dog继承Animal
    def speak(self):  # 重写父类方法
        print("汪汪汪!")

# 使用
animal = Animal()
animal.speak()  # 输出:动物发出声音

dog = Dog()
dog.speak()     # 输出:汪汪汪!
dog.eat()       #子类继承父类方法eat

super关键字编程super方法,用法相同

2.多继承

1.在职研究生继承了Student和staff类

2.两者都有showinfo方法,调用对象.方法名,会优先调用第一个继承的父类 的方法,这里即Student类的showinfo方法

  • 若想调用Teacher的方法,可以:

    1. 调整继承顺序:class Person(Teacher, Student)

    2. 直接指定:Teacher.showinfo(p)

    3. 在子类中重写方法并手动选择调用哪个父类的方法是

3. 方法重写(Override)

子类可以重写父类的方法以改变其行为

python 复制代码
# 父类
class Animal:
    def speak(self):
        print("动物发出声音")
    def eat(self):
        print("父类动物在吃东西")

# 子类
class Dog(Animal):  # Dog继承Animal
    def speak(self):  # 重写父类方法
        print("汪汪汪!")

# 使用
animal = Animal()
animal.speak()  # 输出:动物发出声音

dog = Dog()
dog.speak()     # 输出:汪汪汪!

4. super()函数

python 复制代码
# 父类
class Animal:
    def speak(self):
        print("动物发出声音")
    def eat(self):
        print("父类动物在吃东西")

# 子类
class Dog(Animal):  # Dog继承Animal
    def speak(self):  # 重写父类方法
        print("汪汪汪!")
        super().eat()

# 使用
dog = Dog()
dog.speak()     # 输出:汪汪汪!

5.强制转换

对于Python继承机制

python 复制代码
class Animal:
    def eat(self):
        print("动物吃东西")

class Dog(Animal):  # Dog继承自Animal
    def eat(self):
        print("狗吃骨头")
    def bark(self):
        print("汪汪叫")

class Cat(Animal):
    def eat(self):
        print("猫吃鱼")
# 向上转型(自动) - 子类转父类
animal = Dog()  # 狗是动物(自动转换)
animal.eat()    # 输出: 狗吃骨头

def trans(animal,obj):
    if isinstance(animal, obj):
        dog = animal  
        dog.bark()    
    else:
        print("不能将动物转为动物子类")

trans(animal,Dog)
"""狗吃骨头
汪汪叫
"""
dog = Dog()
cat = Cat()
trans(cat,Dog)#不能将动物转为动物子类

动物= 狗可以,动物=猫 可以,但是不能 狗= 动物

要想狗 = 动物必须强制转换,狗 = (狗)动物

python 复制代码
class Animal:
    def __init__(self, name):
        self.name = name

class Dog:
    def __init__(self, animal):  # 构造函数中实现转换
        self.name = animal.name
    def bark(self):
        print(f"{self.name}在汪汪叫")

animal = Animal("旺财")
dog = Dog(animal)  # 强制将Animal转为Dog
dog.bark()         # 输出: 旺财在汪汪叫

五.多态

首先Python中的多态根JAVA不一样,JAVA的多态必须要在继承的基础之上,但是py的多态,根本不关心你是不是继承,是不是相同的数据类型。只要不同的类中有相同的方法,即可实现多态。

所以要定义一个接口,实现类的多态化。

python 复制代码
class Animal:
    def eat(self):
        print("人吃五谷杂粮")

class Dog:
    def eat(self):
        print("狗吃骨头")

class Cat:    
    def eat(self):
        print("猫吃鱼")

def jiekou(obj):
    obj.eat()

# 创建实例
animal = Animal()
dog = Dog()
cat = Cat()

# 多态调用
jiekou(animal)  # 输出: 人吃五谷杂粮
jiekou(dog)     # 输出: 狗吃骨头
jiekou(cat)     # 输出: 猫吃鱼
相关推荐
Deng94520131436 分钟前
基于Python的职位画像系统设计与实现
开发语言·python·文本分析·自然语言处理nlp·scrapy框架·gensim应用
qq_529835354 小时前
ThreadLocal内存泄漏 强引用vs弱引用
java·开发语言·jvm
景彡先生4 小时前
C++并行计算:OpenMP与MPI全解析
开发语言·c++
落笔画忧愁e4 小时前
扣子Coze飞书多维表插件添加数据记录
java·服务器·飞书
量子联盟5 小时前
原创-基于 PHP 和 MySQL 的证书管理系统,免费开源
开发语言·mysql·php
秋千码途6 小时前
小架构step系列08:logback.xml的配置
xml·java·logback
飞翔的佩奇6 小时前
Java项目:基于SSM框架实现的旅游协会管理系统【ssm+B/S架构+源码+数据库+毕业论文】
java·数据库·mysql·毕业设计·ssm·旅游·jsp
时来天地皆同力.6 小时前
Java面试基础:概念
java·开发语言·jvm
hackchen7 小时前
Go与JS无缝协作:Goja引擎实战之错误处理最佳实践
开发语言·javascript·golang