面向对象编程(Object-Oriented Programming,OOP)是一种常用的编程思想,它将计算机程序组织为对象的集合,这些对象可以相互交互完成任务。
面向对象编程的核心思想就是将数据和操作数据的方法(函数)组合成一个称为对象的独立单元,每个对象都有自己的属性和方法,通过定义和实例化类,我们可以创建多个相似结构的对象以重复使用。面向对象的三大特性:封装,继承,多态。
类是一种用户自定义的数据类型,它由数据和方法组成。数据表示属性,方法表示行为,其中属性是类的成员变量,方法是一组操作数据的代码,具体格式如下:
class 类名:
类属性 = 值
class ATM:
def __init__(self):
self.__user = {}
atm = ATM()
print(type(atm))# <class '__main__.ATM'>
对象就是类的实例化结果,它具有特定的状态和行为,如果说类是我们描述对象的模版和蓝图,那么对象就是继承了类的属性和定义的方法的实例,我们可以通过操作对象来实现各种功能:
class Human:
text = 'Hello'
def __init__(self, name):
self.name = name
def say_hello(self):
print(self.text, end='')
print(self.name)
p = Human(name='张三')
print(p.text) # Hello
p.say_hello() # Hello张三
我们可以通过p.text
直接调用Human类中的text数据,并且同时也能够使用Human类中的方法say_hello()
我们可以用__init__
方法初始化属性后,再由实例化将其赋予新的数据,具体格式如下:
class P:
类属性 = 值
def init(self, 参数1):
self.属性1 = 参数1
p = P(参数1=自定义数据)
class Human:
text = 'Hello'
def __init__(self, name):
self.name = name
p = Human(name='张三')
print(p.name) # 张三
方法(Method)是类中定义的函数成员,用于描述对象的行为和操作。方法提供了一种封装数据和操作数据的方式,使得相关的功能可以组织在一起。
self
,它表示当前的对象实例。通过 self
,我们可以访问和操作对象的属性和其他方法。class Person:
def __init__(self, name):
self.name = name
def say_hello(self):
print(f"Hello, my name is {self.name}")
# 创建对象
person = Person("Alice")
# 调用对象的方法
person.say_hello() # 输出:Hello, my name is Alice
class MyClass:
def instance_method(self):
# 实例方法,通过 self 访问对象的属性
print("This is an instance method.")
@staticmethod
def static_method():
# 静态方法,无需访问对象的属性
print("This is a static method.")
# 创建对象
obj = MyClass()
# 调用实例方法
obj.instance_method() # 输出:This is an instance method.
# 调用静态方法
MyClass.static_method() # 输出:This is a static method.
封装是指将数据和行为打包到一个类中,并可以控制外部访问的级别。封装可以保护数据和方法的访问,并且提高代码的可维护性。
具体隐藏操作可以在参数前面加上两个下划线(__
),参数和方法都是同理
class MyClass:
__name = '张三'
__age = 17
def __fun1(self):
print(self.__name)
p = MyClass()
p.fun1() # AttributeError: 'MyClass' object has no attribute 'fun1'
print(p.age) # AttributeError: type object 'MyClass' has no attribute 'age'
现在外部已经无法正常调用fun1
函数以及其他类属性了,但我们依然可以在类中使用被封装的数据,如果想在外部调用,我们可以调用未被封装的方法:
class MyClass:
__name = '张三'
__age = 17
def __fun1(self):
print(self.__name)
def fun2(self):
self.__fun1()
p = MyClass()
p.fun2() # 张三
继承(Inheritance)是面向对象编程中的一个重要概念,它允许我们创建一个新类(称为子类或派生类),从现有的类(称为父类或基类)继承属性和方法。
以下是继承的一些重要特点:
class Animal:
def __init__(self, name):
self.name = name
def say(self):
print("这是Animal")
class Dog(Animal):
def __init__(self, name):
super().__init__(name)
def say_dog(self):
print(f'{self.name},汪汪')
class Cat(Animal):
def __init__(self, name):
super().__init__(name)
def say_cat(self):
print(f'{self.name},喵喵')
d = Dog(name="这是狗")
c = Cat(name="这是猫")
d.say() # 这是Animal
c.say() # 这是Animal
d.say_dog() # 这是狗,汪汪
c.say_cat() # 这是猫,喵喵
对于一个父类中的函数,我们想让他在各个子类中都能实现,并且在实现过程中具有子类的独特含义,此时便需要引入多态的概念。
class Animal:
def __init__(self, name):
self.name = name
def cry(self):
print("动物的叫声")
class Dog(Animal):
def cry(self):
print(f'{self.name},汪汪')
class Cat(Animal):
def cry(self):
print(f'{self.name},喵喵')
d = Dog(name="这是狗")
c = Cat(name="这是猫")
d.cry() # 这是狗,汪汪
c.cry() # 这是猫,喵喵
抽象类是一个不能被实例化的类,它仅用作其他类的基类或父类,如果强行实例化会报错。
抽象类的主要目的是为了提供一个通用的接口或协议,规范其子类应该实现的方法,子类必须实现抽象类中的所有抽象方法否则也会报错。
python中我们必须使用abc
模块来创建抽象类,抽象类则要继承ABC
类,并使用@abstractmethod
装饰器来标记抽象方法,具体如下:
from abc import ABC, abstractmethod
class Parent(ABC):
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print('run')
def walk(self):
print('walk')
@abstractmethod
def eat(self):
pass
class Son(Parent):
def run(self):
print('no run')
def walk(self):
print('no walk')
def eat(self): # 如果这里不重写run方法也回报错
print("eat")
s = Son(name='ni', age=11)
# p = Parent(name='a',age=10) :TypeError: Can't instantiate abstract class Son with abstract method eat
s.eat() # eat
鸭子类型是python中的一种编程思想,他并不是指代具体的代码,而它的概念也来源于一句诗句:
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” —— 詹姆斯·惠特科姆·莱利
这种概念在编程中也是如此,如果你有鸭子的函数,那你就是鸭子类。
这与java中的概念大相径庭,在java中如果你不是鸭子类型或是它的子类,即使你有同名的鸭子函数,你也不是鸭子类型。
话不多说直接上代码:
首先定义一个鸭子类型,真正的鸭子会’嘎嘎嘎’和走鸭步
class Duck:
def duck_cry(self):
print('嘎嘎嘎')
def duck_walk(self):
print('走鸭步')
接下来我们定义一个检查类,类中的check
方法会接受一个实例化对象,然后用该对象调用鸭子类型中的函数,如果程序没有报错,则证明它既会嘎嘎叫也会走鸭步(即 它就是一只鸭子)
class Check:
def check(self, duck):
duck.duck_cry()
duck.duck_walk()
print("检查完毕,是只鸭子")
这时我们将鸭子类型的实例化对象放入检查类中检查,结果是显而易见的
class Duck:
def duck_cry(self):
print('嘎嘎嘎')
def duck_walk(self):
print('走鸭步')
class Check:
def check(self, duck):
duck.duck_cry()
duck.duck_walk()
print("检查完毕,是只鸭子")
duck = Duck()
p1 = Check()
p1.check(duck)
"""
嘎嘎嘎
走鸭步
检查完毕,是只鸭子
"""
这时来了条狗,它既不会走鸭步也不会学鸭叫,那么程序就会报错
class Dog:
def dog_cry(self):
print("我是狗,我只会汪汪叫")
def dog_walk(self):
print('走狗步')
class Check:
def check(self, duck):
duck.duck_cry()
duck.duck_walk()
print("检查完毕,是只鸭子")
dog = Dog()
p1 = Check()
p1.check(dog) # AttributeError: 'Dog' object has no attribute 'duck_cry'. Did you mean: 'dog_cry'?
然而,重点来了,现在来了一只小鸡,它即会学鸭叫也会走鸭步,那么这个时候检查类不会管他到底是鸡还是鸭,只要你会这俩技能就能放行
class Chicken:
def __init__(self):
print("其实我是鸡")
def duck_cry(self):
print('嘎嘎嘎')
def duck_walk(self):
print('走鸭步')
class Check:
def check(self, duck):
duck.duck_cry()
duck.duck_walk()
print("检查完毕,是只鸭子")
chicken = Chicken()
p1 = Check()
p1.check(chicken)
"""
其实我是鸡
嘎嘎嘎
走鸭步
检查完毕,是只鸭子
"""
这就证明了在python中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定的。
鸭子类型作为程序设计中的一种类型推断风格,适用于大部分脚本语言 / 动态语言 (如 Python、Ruby、Perl、Julia、JavaScript 等) 和 某些静态语言 (如 Golang,通常静态类型语言在编译前便已显式指定变量类型,而 Golang 却则在编译时推断变量类型)。
支持鸭子类型的语言,其解释器/编译器将会在解释/解析 (Parse) 或编译时推断对象类型。
__init__
初始化
class Dog:
def __init__(self, name):
self.name = name
d = Dog(name='小黑')
print(d.name) # 小黑
__name__
类的名字(字符串)
print(__name__) # __main__
由此引申出判断当前模块是否为主函数
# module.py
if __name__ == '__main__':
print("这是主函数")
else:
print("这不是主函数")
如果在当前模块执行该代码则会打印
这是主函数
如果在其他文件调用module.py
则会打印
这不是主函数
__doc__
类的文档字符串,也就是查看"""
三引号的注释
def greet(name):
"""
这是注释
"""
print("Hello")
print(greet.__doc__)
# 这是注释
__base__
类的第一个父类
class Animal:
pass
class Mammal:
pass
class Dog(Animal, Mammal):
pass
print(Dog.__base__)
# <class '__main__.Animal'>
__bases__
类所有父类构成的元组
class Animal:
pass
class Mammal:
pass
class Dog(Animal, Mammal):
pass
print(Dog.__bases__)
# (<class '__main__.Animal'>,<class'__main__.Mammal'>)
__dict__
类的字典属性
class Dog:
name = "小黄"
def __init__(self, age):
self.age = age
d = Dog(age=19)
print(d.__dict__)
# {'age': 19}
print(Dog.__dict__)
# {'__module__': '__main__', 'name': '小黄', '__init__': <function Dog.__init__ at 0x000002756A31DA80>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
__module__
类定义所在的模块
class Dog:
name = "小黄"
def __init__(self, age):
self.age = age
d = Dog(age=19)
print(d.__module__) # __main__
print(Dog.__module__) # __main__
__class__
实例对应的类(仅新式类中)
class Dog:
name = "小黄"
def __init__(self, age):
self.age = age
d = Dog(age=19)
print(d.__module__) # <class '__main__.Dog'>
@classmethod
将方法转换为类方法,用cls
访问类属性
class MyClass:
name = 'Tony'
@classmethod
def my_class_method(cls):
print(cls.name)
MyClass.my_class_method() # Tony
@staticmethod
将方法转换为静态方法,与类和对象的属性无关,也不能通过self
或cls
调用
class MyClass:
name = 'Tony'
@staticmethod
def my_static_method():
print("我是静态方法")
MyClass.my_static_method() # 我是静态方法
@property
将一个方法转换为属性,前提是有返回值,可直接通过.对象名
调用
class MyClass:
name = 'Tony'
@property
def get_name(self):
return self.name
m = MyClass()
print(m.get_name)
@setter
通过@property
将方法转换成属性后并不能直接对其进行修改值操作 否则会直接报错
class MyClass:
name = 'Tony'
@property
def get_name(self):
return self.name
m = MyClass()
m.get_name = 'Tom'
# AttributeError: property 'get_name' of 'MyClass' object has no setter
解决办法很简单,只要用@setter
包裹即可
class MyClass:
def __init__(self, name):
self.name = name
@property
def get_name(self):
return self.name
@get_name.setter
def get_name(self, value):
print(self.name) # Tony 由此可见self调用的是get_name中的name
self.name = value
m = MyClass(name="Tony")
print(m.get_name) # Tony
m.get_name = 'Tom'
print(m.get_name) # Tom
@deleter
deleter可以删除类属性
class MyClass:
def __init__(self, name):
self.name = name
@property
def get_name(self):
return self.name
@get_name.setter
def get_name(self, value):
print(self.name)
self.name = value
@get_name.deleter
def get_name(self):
del self.name
print('get_name原属性已被删除')
m = MyClass(name="Tony")
print(m.get_name) # Tony
m.get_name = 'Tom'
print(m.get_name) # Tom
del m.get_name
print(m.get_name) # 报错:AttributeError: 'MyClass' object has no attribute 'name'
并且可以进行其他操作,比如重新赋值
class MyClass:
def __init__(self, name):
self.name = name
@property
def get_name(self):
return self.name
@get_name.setter
def get_name(self, value):
print(self.name)
self.name = value
@get_name.deleter
def get_name(self):
self.name = 'Leven'
print('name原属性已被删除,并赋予新的值', end='')
m = MyClass(name="Tony")
print(m.get_name) # Tony
m.get_name = 'Tom'
print(m.get_name) # Tom
del m.get_name
print(m.get_name) # name原属性已被删除,并赋予新的值Leven