1.类和对象的基础语法
下面是用Python编写类的基本语法
class class_name:
statements
这里的statements可以包括一个或多个语句。statements不能为空,但可以使用pass关键字来表示没有操作。当你不想对类的行为进行定义时,可以使用pass作为占位符。
可以这样定义Car类:
class Car:
pass
可以这样定义Dog类和Cat类
class Dog:
pass
class Cat:
pass
那我们如何使用Python的类呢?可以创建该类的任意数量的实例。以下语句创建了三个Car类的实例:
car1 = Car()
car2 = Car()
car3 = Car()
也可以创建Dog类的实例:
my_dog = Dog()
yr_dog = Dog()
我们可以为类创建变量,这些变量称为类变量,类的所有实例都共享这些变量。
例如,假设Car类是这样定义的:
class Car:
accel = 3.0
mpg = 25
现在输出Car类的每个实例:
print('car1.accel=',car1.accel)
print('car2.accel=',car2.accel)
print('car1.mpg=',car1.mpg)
print('car2.mpg=',car2.mpg)
输出结果如下:
需要注意的是,Car类的任何实例都可为变量accel赋值。这样做会覆盖类变量的值(这里是3.0)。我们可以创建一个实例my_car,并为类变量accel赋值
my_car = Car()
yr_car = Car()
my_car.accel = 5.0
print(f"my_car.accel={my_car.accel}")
print(f"yr_car.accel={yr_car.accel}")
输出结果如下:
在my_car对象中,accel已经成为实例变量;在yr_car中它仍是一个类变量
2.Python中实例变量
在Python中,实例变量的添加方法有如下几种:
- 在
__init__
方法中初始化
__init__
是类的构造方法,在创建实例时会自动调用,在此方法通过self.变量名
定义的变量,会成为所有实例的"默认实例变量"。
语法
class 类名:
def __init__(self,参数1,参数2, ...):
#self表示当前实例
self.变量名1 = 参数1 #从外部传入的值
self.变量名2 = 参数2
self.变量名3 = 默认值 #固定默认值(无需外部传入)
示例
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
self.score = 0
stu1 = Student("Alice",18)
stu2 = Student("Bob", 19)
print(stu1.age) #输出18
print(stu2.age) #输出19
- 实例创建后动态添加
在实例创建之后,通过实例名.变量名
直接为单个实例绑定新变量
示例
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
self.score = 0
stu1 = Student("Alice",18)
stu1.hobby = "reading"
print(stu1.hobby) #输出reading
- 通过
__setattr__
方法(底层拦截赋值)
__setattr__
是Python的魔法方法,用于拦截所有self.变量名 = 值
或 实例.变量名 = 值
的赋值操作,通过重写该方法,可以自定义实例变量的添加逻辑
示例
class Student:
def __setattr__(self,name,value):
if name == "password":
raise ValueError("禁止添加 'password' 变量!")
super().__setattr__(name,value)
stu1 = Student()
stu1.name = "bob"
stu1.password = "123456" # 报错:ValueError: 禁止添加 'password' 变量!
3.Python中的方法
方法是在类中定义的,这是它们称为方法的根本原因,每次通过类的实例调用方法时,都会传递一个隐藏参数self,它是对实例对象本身的引用。
方法的定义中第一个参数self在方法调用时被隐藏了,因此在方法定义时需要多写一个参数
class Pretty:
def __init__(self,prefix):
self.prefix = prefix
def print_me(self,v1,v2,v3):
print(self.prefix,v1,sep='')
print(self.prefix,v2,sep='')
print(self.prefix,v3,sep='')
printer = Pretty('-->')
printer.print_me(10,20,30)
4.封装
核心思想:
- 就是把类的属性和方法封装类的内部,只能在内部使用,不能在类的外部使用
- 把属性名和方法名前面加两下划线,这个属性和方法就成为了类的私有属性和方法
作用:
- 保护数据安全:防止外部随意修改内部的数据
- 隐藏实现细节:外部只需关注"如何使用",无需了解"内部如何实现"
class Student:
def __init__(self,name):
self.name = name
self.__weight = 199 # __weigth是一个私有属性
def __printer(self): #__printer方法为私有方法
print(f"My name is {self.name}")
stu = Student("bob")
print(stu.name)
#print(stu.__weight) 不能在类的外部访问类的私有属性
#stu.__printer() 不能在类的外部调用私有方法
5.继承
核心思想:
- 让一个类可以继承另一个类的属性和方法,继承的类称为子类,被继承的类称为父类
- 子类可以新增自己的属性和方法或者重写父类的方法
作用:
- 代码复用: 避免重复编写相同的代码,子类直接继承父类的功能
实现方式:
- 定义子类时,在类名后加括号指定父类,如
class 子类名(父类名)
#父类 (基类)
class Animal:
def __init__(self,name):
self.name = name
def eat(self):
print(f"{self.name} 在吃东西")
#子类 继承Animal
class Dog(Animal):
#新增子类独有的方法
def bark(self):
print(f"{self.name} 在汪汪叫")
#重写父类的方法
def eat(self):
print(f"{self.name}在吃狗粮")
Dog1 = Dog("xiaobai")
Dog1.bark() # 调用重写后的方法 xiaobai 在汪汪叫
Dog1.eat() # 调用子类新增方法
6.多态
核心思想:
- 不同的子类,调用相同的父类的方法,产生不同的结果
- 不同的子类继承同一个父类时,子类重写父类中定义的方法,从而代替父类方法的实现
class Animal:
def __init__(self,name):
self.name = name
def food(self):
pass
def eat(self):
self.food()
class Dog(Animal):
def food(self):
print(f"{self.name}吃肉")
class Cattle(Animal):
def food(self):
print(f"{self.name}吃草")
d = Dog("小狗")
c = Cattle("小羊")
d.food() #小狗吃肉
c.food() #小羊吃草
7.类属性和类方法
类属性的定义:
- 类属性是定义在
类内部、方法外部
的属性,类属性定义不需要self
关键字(self
通常用于实例属性,关联到类的具体实例)
类属性的使用:
- 类属性不需要将类实例化为对象,直接通过
类名.属性名的方式来访问和修改
class Animal:
name = "旺财" #这就是类属性,定义在类里、方法之外
def __init__(self):
pass
print(Animal.name) #输出:旺财
类属性与实例属性的区别:
- 类属性:属于类本身,所有类的实例都共享这个属性,如果通过修改类属性,所有实例访问到的该类属性都会改变
- 实例属性:属于类的某个具体实例,每个实例的实例属性互相独立
类方法定义:
类方法是绑定到类本身而不是类的实例方法,它可以访问和修改类的状态,而无需创建类的实例
类方法的特点:
1.使用@classmethod
装饰器定义
2.第一个参数通常是cls
,表示类本身(类似实例方法的self
)
3.可以通过类名或实例调用
4.不能直接访问实例属性,但可以访问类属性
类方法的使用场景:
- 用于创建类的备选构造方法
- 用于操作类属性
- 当方法需要与类本身交互而不是与实例交互时
class Animal:
#类属性
feature = "need food"
count = 0 #记录创建的实例数量
def __init__(self,name, age):
self.name = name
self.age = age
Animal.count += 1 #每次创建实例,计数器加一
# 实例方法
def get_name(self):
return self.name
#类方法, 访问类属性
@classmethod
def get_feature(cls):
return cls.feature
# 类方法 - 修改类属性
@classmethod
def edit_feature(cls,new_feature):
cls.feature = new_feature
# 类方法 - 作为备选构造方法
@classmethod
def alternative_method(cls,name,age):
return cls(name,age)
animal1 = Animal("cat",10)
animal2 = Animal("dog",15)
#使用类方法
print(f"通过类名调用类方法:{Animal.get_feature()}")
#通过实例调用类方法
print(f"通过实例调用类方法:{animal1.get_feature()}")
# 修改类属性
Animal.edit_feature("eat food")
print(f"修改后的特征:{Animal.get_feature()}")
#使用备选构造方法
animal3 = Animal.alternative_method("cattle",20)
print(f"{animal3.name}的年龄是:{animal3.age}")
print(f"创建实例的个数是:{Animal.count}") #3
8.静态方法
在Python中,静态方法可以直接通过类名调用,也可以通过实例调用,但它不会自动接收self
或cls
参数
静态方法的特点:
1.使用staticmethod
装饰器定义
2.无法访问类属性或实例属性
3.调用方式: 类名.方法名()
或 实例名.方法名()
使用场景:
- 方法不需要访问类或任何实例属性
- 作为工具函数,与类相关但不需要类数据
class MathUtils:
#静态方法:计算两个数的和
@staticmethod
def add(a,b):
return a+b
# 静态方法:计算两个数的乘积
def multiply(a,b):
return a*b
#调用静态方法
print(MathUtils.add(1,2))
print(MathUtils.multiply(2,3))
#通过实例调用
math_instance = MathUtils()
print(math_instance.add(2,3))