面向对象是什么?
面向对象(Object-Oriented Programming,简称OOP)是一种编程范式,它使用"对象"来设计应用程序和计算机程序。OOP的核心概念包括类(Class)、对象(Object)、封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)等。
类是什么?
在 Python 中,类是一种创建对象的模板,定义了对象的属性和方法。通过类可以创建具有相同属性和行为的对象实例。
什么是属性?
属性即是特征,比如:人类的名字、年龄、身高、体重...等特征。
什么是方法?
方法即是动作,比如:人类吃饭、搬砖...等行为。
定义类
语法:
class 类名(父类名):
属性
初始化方法
实例方法
......
注意:
类名要满足标识符命名规则,同时要遵循大驼峰命名习惯。类名后面的小括号`()`是写继承的类名的。如果没有继承,可以省略小括号,比如 `class 类名:`
示例:定义类,并使用类创建对象
python
# 创建类
class Test:
# 定义属性
name = "我是变量,在类中我叫属性"
# 定义初始化方法
def __init__(self):
print("我是初始化方法")
# 定义实例方法
def test(self):
print("我是普通函数,在类中我叫实例方法")
# 使用类
# 通过类创建的变量,这里叫做对象
test = Test() # 使用类创建一个对象,这里创建对象时使用的是初始化方法
print(test.name) # 使用类中的属性
print(test.test()) # 使用类中的实例方法
self 讲解
python
class Test:
name = "我是变量,在类中我叫属性"
# self 是指向这个类的对象,用于引用调用类中的属性和方法。
def test(self):
# 比如我在类中想使用类中的属性或者方法。
# print(name) #这种方法语法报错
print(self.name) # self.name 可以调用成功
test = Test()
test.test()
类外面添加对象属性
语法:
对象名.属性名 = 值
示例:
python
class Test:
name = "Tom"
test = Test()
# 添加属性
test.age = 18
# 使用属性
print(test.age)
类里面使用对象属性/方法
语法:
self.属性名
self.方法名()
示例:
python
class Test:
def hello(self):
# 类中使用类外的属性
print(self.age)
test = Test()
# 类外添加属性
test.age = 18
print(test.hello())
魔法方法
在Python中, xx() 的函数叫做魔法方法(Magic Methods),也被称为双下划线方法(Dunder Methods),指的是具有特殊功能的函数,并与 Python 的内置操作符和函数交互。
`init` 初始化方法,构造函数。
python
class Test:
def __init__(self, name, age):
self.name = name
self.age = age
test = Test('Tom', 18)
print(test.name) # Tom
print(test.age) # 18
`dict` 打印对象的所有属性值。vars()也是这个作用。
python
class Test:
def __init__(self, name, age):
self.name = name
self.age = age
test = Test('Tom', 18)
print(test.__dict__) # {'name': 'Tom', 'age': 18}
print(vars(test)) # {'name': 'Tom', 'age': 18}
`str` print 打印对象时以字符串表示形式。同比java中的toString方法
python
class Test:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'Test(name={self.name}, age={self.age})'
test = Test('Tom', 18)
print(test) # Test(name=Tom, age=18)
print(test.__str__()) # Test(name=Tom, age=18)
print(str(test)) # Test(name=Tom, age=18)
`repr` 与 __srt__类似,下面是它们的比较
python
class Test:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'Test(name={self.name}, age={self.age})'
def __repr__(self):
return f'Person({self.name!r}, {self.age!r})'
test = Test('Tom', 18)
print(test) # Test(name=Tom, age=18)
print(repr(test)) # Person('Tom', 18)
`call` 可以让对象像方法一样被调用。作用是可以隐式的调用类中其他的方法,已经由call显示的调用了其他方法。
python
class Test:
name = 'Tom'
def __call__(self):
self.hello()
def hello(self):
print(f"hello {self.name}")
test = Test()
# 我们想调用类中的 hello 方法时,可以直接这样调用,hello已经由call调用了
test() # hello Tom
`del` 析构函数,在对象被垃圾回收(或者我们主动使用del函数)时被调用。用于执行一些清理操作,例如关闭文件、释放资源等。
python
class Test:
name = 'Tom'
def __del__(self):
# 这里可以写一些关闭资源的操作
print(f"对象已经被删除.")
test = Test()
del test # 对象已经被删除.
Python中还有什么很多魔法方法,这里就不一一演示了。
私有属性和私有方法
在Python中,私有权限(Private Access)用于限制类属性和方法的访问,即私有属性和私有方法。使其只能在类内部使用。这是通过命名约定和名称改写(name mangling)机制来实现的。
_ 单下划线 (受保护)
单下划线前缀表示"受保护的"变量或方法。这是一种约定,表示这些变量或方法不应该不推荐在类外部直接使用,虽然它们仍然可以被访问。
示例:
python
class Hello:
def __init__(self):
self._protected_var = "我是受保护的属性"
def _protected_method(self):
return "我是受保护的方法"
hello = Hello()
# 依然可以访问到,但是不推荐不应该访问
print(hello._protected_var) # 输出:我是受保护的属性
print(hello._protected_method()) # 输出:我是受保护的方法
__ 双下划线 (私有)
双下划线前缀用于实现名称改写(name mangling),使得属性或方法在类外部无法轻易访问。Python会将这些名称改写为
_ClassName__variableName
的形式,从而实现基本的私有化。
示例:
get 私有属性
python
class Hello:
__private_var = "我是私有的属性"
def __private_method(self):
return "我是私有的方法"
# 用于访问私有属性
def get_private_var(self):
return self.__private_var
# 用于访问私有方法
def get_private_method(self):
return self.__private_method()
hello = Hello()
# 以下访问会报错
# print(hello.__private_var) # 出异常 AttributeError
# print(hello.__private_method()) # 出异常 AttributeError
# 方式一:
# 通过类内部方法间接访问
print(hello.get_private_var()) # 输出:我是私有的属性
print(hello.get_private_method()) # 输出:我是私有的方法
# 方式二:
# 通过名称改写访问,改写规则是 `_类名__变量方法名`
print(hello._Hello__private_var) # 输出:我是私有的属性
print(hello._Hello__private_method()) # 输出:我是私有的方法
set 私有属性
python
class Hello:
__private_var = "20"
# 获取私有属性值
def get_private_var(self):
return self.__private_var
# 修改私有属性值
def set_private_var(self, __private_var):
self.__private_var = __private_var
hello = Hello()
# 获取修改前的数据
print(hello.get_private_var()) # 20
# 修改数据
hello.set_private_var("10")
# 获取修改后的数据
print(hello.get_private_var()) # 10
类属性和实例属性
类属性
Python类属性就是Java中的常量。
类属性是属于类本身的属性,它被所有该类的实例共享。可以通过类名访问类属性,也可以通过实例访问(如果实例没有同名的实例属性,则会访问类属性)。类属性通常在类的定义体中直接定义,并且在整个类的生命周期中保持不变。类属性可以通过类修改,不能通过实例对象修改,如果使用实例对象修改类属性,表示的是创建了一个和类属性同名的实例属性。
示例:
python
class Hello:
# 类属性
name = "Tom"
# 通过类直接访问
print(Hello.name) # 输出:Tom
# 通过对象访问
hello = Hello()
print(hello.name) # 输出:Tom
实例属性
实例属性是属于类的实例的属性,每个实例都有自己的一组实例属性。通常在实例化对象时通过构造函数
__init__
中初始化实例属性。实例属性是与特定实例相关联的,不同实例的同名实例属性可以有不同的值。
示例:
python
class Hello:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age # 实例属性
tom = Hello("Tom", 18)
jerry = Hello("Jerry", 25)
print(tom.__dict__) # {'name': 'Tom', 'age': 18}
print(jerry.__dict__) # {'name': 'Jerry', 'age': 25}
类方法和静态方法
在Python中,类方法(Class Method)和静态方法(Static Method)是与类相关联的两种特殊类型的方法,它们不同于普通的实例方法,具有特定的使用场景和功能。
类方法
类方法使用
@classmethod
装饰器声明的方法,它第一个参数通常被命名为cls
,表示类本身。类方法可以通过类名调用,也可以通过实例调用。类方法主要有以下特点:
- 类方法可以访问和修改类级别的属性,即类属性。
- 类方法通常用于对类属性进行操作或者返回类的实例。
- 可以在类方法内部通过
cls
参数访问其他类方法或静态方法。
示例:
python
class Car:
car_count = 0 # 类属性
def __init__(self, brand, model):
self.brand = brand # 实例属性
self.model = model # 实例属性
Car.car_count += 1 # 每创建一个实例,类属性加1
@classmethod
def get_car_count(cls):
return cls.car_count
# 调用这个方法,类比在调用初始化方法__init__
@classmethod
def create_instance(cls, brand, model):
return cls(brand, model)
# 使用类方法
print(Car.get_car_count()) # 输出: 0
car1 = Car.create_instance("Benz", "May bach")
print(Car.get_car_count()) # 输出: 1
静态方法
静态方法是使用
@staticmethod
装饰器声明的方法,它与类和实例没有直接的关系,可以在类内部定义的独立函数。静态方法不接受类或实例作为第一个参数,因此它没有访问类属性或实例属性的能力。静态方法主要有以下特点:
- 静态方法通常与类相关联,但不访问类属性或实例属性。
- 可以被类名直接调用,也可以被实例调用,但不会接收类或实例作为参数。
- 通常用于实现与类相关但不依赖于类实例或类属性的功能。
示例:
python
class MathUtils:
@staticmethod
def add(x, y):
return x + y
@staticmethod
def multiply(x, y):
return x * y
# 使用静态方法
print(MathUtils.add(3, 5)) # 输出: 8
print(MathUtils.multiply(3, 5)) # 输出: 15
区别和用途
- 参数 :类方法的第一个参数是
cls
,可以访问类属性;静态方法没有特殊的第一个参数,不能访问类属性或实例属性。- 访问方式:类方法可以通过类名或实例调用;静态方法可以通过类名或实例调用。
- 用途:类方法通常用于修改类属性或返回类的实例;静态方法通常用于实现通用的功能函数,与类和实例无关。