一.类
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()方法用来初始化新创建对象,在一个对象被创建以后会立即调用。
- 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(注解),来表明这是一个静态方法,可以无参数,
调用方式:
推荐 类名.方法名调用,
不推荐 对象名.方法名
-
作用:
-
与类相关,但不依赖类或实例的状态(即不访问
self
或cls
)。 -
类似于普通函数,但逻辑上属于类。
-
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
的方法,可以:-
调整继承顺序:
class Person(Teacher, Student)
-
直接指定:
Teacher.showinfo(p)
-
在子类中重写方法并手动选择调用哪个父类的方法是
-
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) # 输出: 猫吃鱼