30天学习Python👨💻第八天——面向对象基础
介绍
Python是一种多范式的编程语言,这非常有趣。我意识到JavaScript也是一种多范式的编程语言。
这意味在我们可以有多种思考如何编写构造Python代码的方式。但是这为什么很重要呢?在现实中,当我们开发真实项目时,我们尝试用程序解决复杂的问题,甚至在还没有写一行代码之前就要进行很多次的头脑风暴。好的程序不只是考虑我们如何解决问题,还要考虑代码的可维护性、可扩展性,以及可读性。这种构造和组织代码的方式被称为编程范式。这是一种预先规定好规则,开发者需要遵守以避免混乱的模式。如果每个开发者都用他们自己的方式编写代码,那会让人震惊。
让我们回到Python。
在Python中,一切皆对象。我探讨过的所有数据类型都是对象,它们都有自己的属性和方法。这些对象称为实例,产生于它们的类。这意味着Python中所有的数据类型都有一个已定义的结构或者原型,它们所有的属性和方法都在这里被定义。
print(type(2)) # <class 'int'>
print(type(2.5)) # <class 'float'>
print(type('Python')) # <class 'str'>
print(type(True)) # <class 'bool'>
print(type({})) # <class 'dict'>
print(type([])) # <class 'list'>
print(type(())) # <class 'tuple'>
print(type(None)) # <class 'NoneType'>
和内置的类一样,自定义的类可以代表真实世界中的事物,比如汽车、机器、人类、动物等任何东西。真实世界中的物体以及它们的属性和行为在代码中用类表示,可以作为面向对象编程范式的松散定义。所有的类都可以被用作产生一个实例对象。这些对象可以与其他对象结合以模拟现实世界的功能。
在JavaScript中,自定义类也可以被创建(尽管ES6中的class只是函数原型的高级语法糖)。所以在我的思维模型中,我把它们联系起来。
面向对象基础
但是想要看到Python中面向对象的强大,我们需要深入研究并且编写一些代码。
class Avenger:
def __init__(self, name):
self.name = name
def fight(self):
print('👊')
spiderman = Avenger('Spiderman')
print(type(Avenger)) # <class 'type'>
print(type(spiderman)) # <class '__main__.Avenger'> --> Avenger的实例
在Python中,类的命名可以是驼峰式,而不用像变量那样需要采用蛇形的命令方式。
上面代码中的__init__是一个初始化方法(也称为构造方法)。它用来初始化类的变量。在上面的类定义中,name进行了初始化。这和JavaScript中,类的构造函数非常的相像。
self是Python中的一个关键字,它表示类的实例的引用,用于访问类的变量或属性。在我的认知中,我觉得这和JavaScript中的this很像。
在上面的Avenger 类中,fight 是一个方法,假设当fight 被要求“战斗”(调用)时,它会怎么做?这里它只打印一个表情符号,但其实可以是任何动作。
用Avenger 作为原型,我创建了Spiderman 对象。类似的,这个类可以用于创造任何其他avengers 的对象,但似乎每个人都会做同样的事情,执行fight方法,这一点都没意思。
class Avenger:
def __init__(self, name, weapon):
self.name = name
self.weapon = weapon
def fight(self):
print(self.weapon)
spiderman = Avenger('Spiderman', 'dispatch a web')
thor = Avenger('Thor', 'thunder attack')
spiderman.fight() # dispatch a web
thor.fight() # thunder attack
这样好一些了。每一个avenger 都有不同的表现。这是一个类的最简结构,可以给它添加许多功能让它更加复杂。
当对象被初始化(创建)的时,__init__构造方法每次都会被调用。它还提供了许多进行控制的机制,只允许在满足条件或向参数添加默认值时创建对象。
class MotorBike:
def __init__(self, brand, age):
if(age <= 15):
self.brand = brand
self.age = age
def start(self):
print(f'starting {self.brand}....')
bullet = MotorBike('Royal Enfield Bullet',20)
bullet.start() # 报错. 只要age小于15时对象才会被创建
代码练习
这个任务是创建一个带有name和goals属性的*SoccerPlayer* 类,然后创建三个对象,使用一个函数找出这些对象中goals最大的那个并把它打印出来。
class SoccerPlayer:
def __init__(self, name, goals):
self.name = name
self.goals = goals
def calculateMaxGoals(*args):
print(args)
return max(*args)
messi = SoccerPlayer('messi', 10)
ronaldo = SoccerPlayer('ronaldo',22)
neymar = SoccerPlayer('neymar', 8)
max_goals = calculateMaxGoals(messi.goals, ronaldo.goals, neymar.goals)
print(f'The highest number of goals is {max_goals} goals')
装饰器@classmethod和@staticmethod
方法也可以附加到类,而不需要创建类的实例。
可以通过在方法名的头部添加@classmethod装饰器的方式,给类添加方法。我后面会探讨装饰器的细节,现在只要粗浅的理解为是创建了一个类的方法就可以了。
class Calculator:
def __init__(self,type):
self.type = type
@classmethod
def calculate_sum(cls, num1, num2):
return num1 + num2
# cls就像self一样,它需要放在第一个参数的位置
print(Calculator.calculate_sum(3,5)) # 8
@staticmethod非常像classmethod。只是它不需要传入cls参数。这个方法可以在不需要类实例化的情况下被调用。
class Calculator:
def __init__(self,type):
self.type = type
@staticmethod
def multiply(num1, num2):
return num1 * num2
print(Calculator.multiply(3,5)) # 15
这就是今天全部的内容了。后面我将会探讨面向对象编程的细节,并且通过一些联系来理解这些概念。我们的知识体系正在稳定的扩展,以便于我们可以应对更加高级的内容。
我正在看这个Python创始人问答视频,非常有趣,现在分享给你:)