本笔记为阿里云天池龙珠计划SQL训练营的学习内容,链接为:https://tianchi.aliyun.com/specials/promotion/aicampsql
对象
类对象 --> 实例变量
三大性质 :
封装
继承
多态
Python中的类提供了面向对象编程的所有基本功能:
类的继承机制允许多个基类,子类(派生类)可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。
封装
定义
属性 + 方法
class Cat:
color = 'red' # 属性
def what_color(self): # 方法
print(self.color)
1.对象名首字母大写
2.属性 类属性, 局部属性
类属性: 1.由这个类对象创建的所有实例对象共用; 2. 在类层级定义(方法外);
类属性:类外面,可以通过实例对象.类属性
和类名.类属性
进行调用。类里面,通过self.类属性
和类名.类属性
进行调用
实例属性: 1.由实例对象单独拥有,相当于局部变量;2.在方法内定义(包括参数);
实例属性 :类外面,可以通过实例对象.实例属性
调用。类里面,通过self.实例属性
调用。
class Cat:
color = 'red'
def what_color(self, ncolor):
print(self.color)
color 为类属性
ncolor 为局部属性
self.color 是类属性,将在self的使用时讲到
# 创建类对象
class Test(object):
class_attr = 100 # 类属性
def __init__(self):
self.sl_attr = 100 # 实例属性
def func(self):
print('类对象.类属性的值:',Test.class_attr) # 调用类属性
print('self.类属性的值',self.class_attr) # 相当于把类属性 变成实例属性
print('self.实例属性的值',self.sl_attr) # 调用实例属性
# 创建a对象
a = Test()
a.func()
运行结果:
类对象.类属性的值: 100
self.类属性的值 100
self.实例属性的值 100
# 创建b对象
b = Test()
b.func()
运行结果:
类对象.类属性的值: 100
self.类属性的值 100
self.实例属性的值 100
# 通过(实例对象.类属性)修改类属性
a.class_attr = 200
# 通过(实例对象.实例属性)修改实例属性的值
a.sl_attr = 200
a.func()
运行结果:
类对象.类属性的值: 100
self.类属性的值 200
self.实例属性的值 200
# 再次运行b对象
b.func()
运行结果:
类对象.类属性的值: 100
self.类属性的值 100
self.实例属性的值 100
# 通过(类对象.类属性)修改类属性
Test.class_attr = 300
a.func()
运行结果:
类对象.类属性的值: 300
self.类属性的值 200
self.实例属性的值 200
# 此时再执行b对象
b.func()
运行结果:
类对象.类属性的值: 300
self.类属性的值 300
self.实例属性的值 100
3.方法
类方法:在方法前面加上@classmethod 这样的方法称为类方法,类方法可以修改类属性的值。
实例方法:带有self 参数的方法
1.除self参数外与普通函数相同
2. self
1.将方法定义时的第一个参数作为 self参数(self不是关键字,可写成任意参数名称,但一般约定为self)
2.self是对类实例的引用
3.Python 的 self 相当于 C++ 的 this 指针
class Cat:
color = 'red'
age = 99999
def __init__(self, color, age):
self.color = color # 在实例中定义了实例参数self.color
self.age = age
def add_color(self):
self.age += 1
def what_color(self):
print(self.color)
def how_old(self):
print(self.age)
cat1 = Cat('white', 1)
cat1.add_color()
cat1.how_old()
cat1.add_color()
cat1.how_old()
cat1.what_color()
#2
#3
#white
魔法,专有,双下划线方法
在 Python 中,“专有方法”(Special Methods),也称为"魔法方法"(Magic Methods)或"双下划线方法"(Double Underscore Methods)
是一组以双下划线 __
开头和结尾的特殊方法。这些方法在类定义中具有特殊的用途,并由 Python 解释器在特定情况下自动调用。
它们被称为"专有方法"是因为它们提供了一种特殊的、针对特定操作的定制化行为,使得自定义类的对象可以在 Python 中表现得更加像内置类型。
构造方法:用于初始化对象的属性。在创建类的实例时自动调用。
__init__(self[, 变量])
继承
继承是指一个类(子类)可以继承另一个类(父类)的属性和方法。子类继承了父类的特性,这使得子类可以共享父类的功能,并且可以在此基础上添加自己特有的功能。继承提供了代码的重用机制,使得类的设计更加灵活和高效。
class 子类名(父类名):
若是父类中有相同的方法名,而在子类使用时未指定,Python 从左至右搜索,即方法在子 类中未找到时,从左到右查找父类中是否包含方法。
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
#另一个类,多继承之前的准备
class speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
#多继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test = sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中参数位置排前父类的方法
情况一:**子类需要自动调用父类的方法:**子类不重写__init__()方法,实例化子类后,会自动调用父类的__init__()的方法。
情况二:**子类不需要自动调用父类的方法:**子类重写__init__()方法,实例化子类后,将不会自动调用父类的__init__()的方法。
情况三:**子类重写__init__()方法又需要调用父类的方法:**使用super关键词:
多态
在Python中,多态(Polymorphism)是面向对象编程的一个重要特性,它允许使用相同的接口来处理不同类的对象,从而产生不同的行为。多态使得代码更加灵活,能够适应不同类型的对象,同时提高了代码的可复用性和可扩展性。
Python中的多态主要通过两种方式实现:
- 函数多态: Python是一种动态类型语言,函数的参数类型是在运行时确定的,而不是在编译时。因此,Python函数可以接受不同类型的参数,并根据参数类型的不同执行不同的操作,这就是函数多态。例如,一个函数可以接受不同类型的序列(列表、元组等),并对它们执行相同的操作。
def print_element(sequence):
for item in sequence:
print(item)
# 函数可以接受列表或元组,并执行相同的操作
list_data = [1, 2, 3, 4]
tuple_data = (10, 20, 30, 40)
print_element(list_data) # Output: 1 2 3 4
print_element(tuple_data) # Output: 10 20 30 40
- 方法多态: Python的类方法(包括实例方法和类方法)可以通过继承和方法重写实现多态。子类可以继承父类的方法,并根据需要对方法进行重写,从而实现自己特定的行为。当调用方法时,Python会根据对象的实际类型(子类还是父类)来选择执行哪个方法,这就是方法多态。
pythonCopy codeclass Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
print("Woof!")
class Cat(Animal):
def make_sound(self):
print("Meow!")
# 调用make_sound方法时,实际执行的是对应子类的方法
dog = Dog()
cat = Cat()
dog.make_sound() # Output: "Woof!"
cat.make_sound() # Output: "Meow!"
在这个例子中,Dog
和Cat
都继承了Animal
类的make_sound
方法,并对该方法进行了重写,使得每个子类都具有自己的声音。
super
super()
是一个特殊的关键字或函数,用于获取父类(超类)的代理对象。通过这个代理对象,可以调用父类的方法,从而实现对父类功能的继承和扩展。
-
在单继承中使用
super()
函数: 在单继承情况下,通过super()
函数可以在子类中调用父类的方法。通常,这用于在子类的方法中执行父类的逻辑,并在此基础上添加子类特有的行为。使用super()
函数的形式为:super().method()
,其中method
是要调用的父类方法。示例:
class Parent: def show(self): print("Parent") class Child(Parent): def show(self): super().show() # 调用父类的方法 print("Child") child = Child() child.show()
输出结果:
Parent Child
-
在多继承中使用
super()
函数: 在多继承情况下,super()
函数起到协调解决方法调用顺序(Method Resolution Order,MRO)的作用。在多继承时,可能会出现菱形继承等问题,super()
函数会根据类的继承顺序(通过C3线性化算法计算得出)依次调用每个父类的方法。示例:
class A: def show(self): print("A") class B(A): def show(self): print("B") super().show() # 调用父类A的方法 class C(A): def show(self): print("C") super().show() # 调用父类A的方法 class D(B, C): def show(self): print("D") super().show() # 调用父类B的方法 d = D() d.show()
输出结果:
D B C A
super()
函数的调用顺序是根据类的继承顺序(Method Resolution Order,MRO)确定的,可以通过class_name.__mro__
属性查看类的方法解析顺序。在继承链中,super()
函数按照该顺序依次调用各个父类的方法,以达到协调多继承的目的。
需要注意的是,super()
函数不仅可以用于调用父类的方法,
还可以用于调用父类的构造方法,从而实现子类构造方法对父类构造方法的继承。
class a:
def __init__(self):
print('a')
class b(a):
def __init__(self):
super().__init__()
print('b')
b1 = b()
#a
#b
公有和私有
在 Python 中定义私有变量只需要在变量名或函数名前加上“__”两个下划线,那么这个函数或变量就会为私有的了。
- 公有(Public)
- 公有属性和方法可以在类的内部和类的外部访问。
- 在类定义中不使用任何修饰符(即默认情况下),声明的属性和方法都是公有的。
- 公有属性和方法在类的内部通过
self
访问,在类的外部通过对象名访问。
class MyClass:
def __init__(self):
self.public_var = 123 # 公有属性
def public_method(self):
return "This is a public method."
obj = MyClass()
print(obj.public_var) # Output: 123
print(obj.public_method()) # Output: This is a public method.
- 私有(Private)
- 私有属性和方法只能在类的内部访问,对于类的外部是不可见的。
- 使用双下划线
__
开头的属性和方法被认为是私有的,它们不能通过对象名直接访问。 - 可以在类内部通过
self
访问私有属性和方法。
class MyClass:
def __init__(self):
self.__private_var = 456 # 私有属性
def __private_method(self):
return "This is a private method."
def public_method(self):
return self.__private_method()
obj = MyClass()
# 无法直接访问私有属性和方法
# print(obj.__private_var) # Error
# print(obj.__private_method()) # Error
# 可以通过公有方法间接访问私有方法
print(obj.public_method()) # Output: This is a private method.
需要注意的是,虽然使用双下划线 __
开头的属性和方法被认为是私有的,但在 Python 中实际上它们只是进行了名称改写,即在名称前添加了 _类名
,以避免命名冲突。因此,仍然可以通过 _类名__私有属性
和 _类名__私有方法
的形式来访问私有属性和方法,但不推荐这样做,因为这违背了类的封装性原则,使得私有属性和方法不再具有隐藏和保护的效果。(伪私有)
变量解析顺序
在Python 中,当不同范围内有多个同名变量(例如局部变量、实例属性、类属性)时,Python 会按照特定的顺序来解析变量名称。这个顺序被称为“LEGB”规则,其中每个字母代表搜索顺序的一个范围:
- 本地(L):Python首先在本地范围内搜索变量,本地范围指的是定义该变量的当前函数或方法。如果在此范围内找到该变量,Python 将使用它并停止搜索。
def example_function():
x = 10 # Local variable
print(x) # Accessible only inside the function
example_function() # Output: 10
- 封闭 (E):如果在局部作用域中找不到该变量,Python 将在直接封闭函数的作用域中进行搜索(如果当前作用域嵌套在另一个函数内)。它继续搜索多个封闭范围,直到找到变量或到达全局范围。
def outer_function():
y = 20 # Enclosing variable
def inner_function():
print(y) # Accesses the enclosing variable y
inner_function()
outer_function() # Output: 20
- 全局 (G):如果在任何封闭作用域中都找不到该变量,Python 将在全局作用域中查找它。全局作用域是指模块级作用域,其中存储模块顶层定义的变量。
global_var = 30 # Global variable
def my_function():
print(global_var) # Accessing the global variable
my_function() # Output: 30
- 内置 (B):如果在本地、封闭或全局作用域中找不到该变量,Python 最终会在内置作用域中搜索它,该作用域包含所有 Python 内置函数和类型。
print(len([1, 2, 3])) # 'len' is a built-in function
此 LEGB 规则确保 Python 以可预测的顺序搜索变量,并避免变量解析中的歧义。如果同名变量存在于多个作用域中,Python 将根据 LEGB 规则使用第一个匹配作用域中找到的变量。
绑定
Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念。
在 Python 中,绑定(Binding)是将名称(变量名)与对象(值)关联起来的过程。当你创建一个变量并将值赋给它时,就会发生绑定。绑定意味着在内存中创建了一个对象,并将该对象与变量名关联起来,使得你可以通过变量名来引用和操作这个对象。
Python 中的绑定分为两种类型:
-
名称绑定(Name Binding):
- 在 Python 中,给一个变量名赋值就是创建一个名称绑定。这意味着将变量名与特定的对象(值)关联起来。
- 变量名在赋值之前必须先被声明或引用。一旦绑定完成,变量名可以在之后的代码中使用。
示例:
x = 42 # 将整数值 42 绑定到变量名 x y = "Hello" # 将字符串 "Hello" 绑定到变量名 y # 使用已绑定的变量名 print(x) # Output: 42 print(y) # Output: Hello
-
对象绑定(Object Binding):
- 对象绑定是指将一个对象与变量名关联起来,使得该变量名成为该对象的引用。在 Python 中,所有变量都是对对象的引用。
- 多个变量名可以指向同一个对象,因此一个对象可以有多个对象绑定。
示例:
a = [1, 2, 3] # 将列表对象 [1, 2, 3] 绑定到变量名 a b = a # 将变量名 b 绑定到和 a 相同的对象 # 修改 a 所引用的对象,同时 b 也会受影响 a.append(4) print(b) # Output: [1, 2, 3, 4]
在 Python 中,绑定是动态的,变量可以在任何时候指向不同的对象。例如,你可以在运行时更改变量名的绑定对象:
pythonCopy codex = 42
print(x) # Output: 42
x = "Hello"
print(x) # Output: Hello
在这个例子中,变量 x
在不同的时刻绑定了整数 42 和字符串 “Hello”,表现出了 Python 的动态特性。这也是 Python 灵活和易于使用的一个特点。
组合
在面向对象编程中,组合(Composition)是一种将多个类组合在一起以创建更复杂的对象的关系。组合是一种强关联关系,其中一个类(称为容器类)包含另一个类(称为成员类)的对象作为其属性。通过组合,容器类可以使用成员类的功能,从而实现了代码的复用和模块化。
组合和继承是面向对象编程的两种常见的关联方式,它们有不同的特点和适用场景。
在组合中,一个类将另一个类的对象作为属性
而在继承中,一个类继承另一个类的属性和方法
例子第14行
class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower
def start(self):
print("Engine started.")
def stop(self):
print("Engine stopped.")
class Car:
def __init__(self, year, horsepower):
self.year = year
self.engine = Engine(horsepower) # 使用组合,将Engine类的对象作为Car类的属性
def start(self):
print(f"{self.year} is starting.")
self.engine.start()
def stop(self):
print(f"{self.year} is stopping.")
self.engine.stop()
# 创建Car类的对象
car1 = Car(2022, 150)
car2 = Car(2023, 180)
# 调用Car类的方法
car1.start()
car1.stop()
car2.start()
car2.stop()