python面向对象
构造方法__init__(self)
类有一个名为 init() 的特殊方法(构造方法),该方法在类实例化时会自动调用,像下面这样:
def__init__(self): self.data = []
声明变量可以隐式声明
class Complex: def __init__(self, realpart, imagpart): self.r = realpart self.i = imagpart
在 Python 中,init 是一个特殊方法,被称为类的构造函数或初始化方法。当创建一个新的对象实例时,Python 会自动调用这个方法来初始化对象的状态。在这段代码中:
def __init__(self) -> None:
super().__init__()
init 方法定义了类的对象实例化时需要执行的一些初始化操作。这里的 self 参数是对当前实例的引用,它是每个类方法的第一个参数,默认指向调用该方法的对象。
-> None 是类型注解,它表明这个方法没有明确的返回值,或者说它的返回类型是 NoneType。虽然在 Python 2.x 中不是必需的,但在 Python 3 中,类型注解可以帮助提高代码的可读性和支持静态类型检查工具的工作。
super().init() 调用了父类的 init 方法。在这个例子中,由于 Module 类继承自 nn.Module,调用 super().init() 实际上是在初始化 nn.Module 类提供的所有基本属性和功能,这对于构建一个有效的 PyTorch 神经网络模块是至关重要的。例如,它可能负责初始化模型参数列表以及其他内部状态等。
self
在Python中,self 是面向对象编程中类的方法(成员函数)的一个特殊参数,它代表的是类的实例自身。在每个类方法定义的第一个参数中,通常都会使用 self 关键字。self 的具体意义和用法包括:
- 指向实例:
当你创建一个类的实例时,self 参数会自动指向这个新创建的对象。例如,当你调用类的一个方法时,Python会隐式地将当前实例作为第一个参数传给方法,这个参数在方法内部被命名为 self。
class MyClass:
def __init__(self, name):
self.name = name
obj = MyClass(‘Alice’)
在这里,‘obj’ 实际上调用了 ‘init’ 方法,并将 ‘obj’ 自身和 ‘Alice’ 作为参数传递
#即 MyClass.init(obj, ‘Alice’)
- 访问实例属性和方法:
self 用于在类的方法内部访问和修改该实例的属性和调用其他方法。
class MyClass:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, {self.name}!")
obj = MyClass('Alice')
obj.greet() # 输出 "Hello, Alice!"
在 greet 方法内部,self.name 就是引用当前实例(这里是 obj)的 name 属性。
3. 约定俗成:
self 是一种命名约定,Python并没有强制要求使用这个名字,但它在Python社区中被广泛采用,以增强代码的可读性和一致性。你也可以选择使用其他名称,但这样做可能会让其他开发者感到困惑,因此强烈建议遵循这一约定。
总结来说,self 关键字的存在是为了在类的方法内部明确地引用当前实例,并通过它来访问和操作实例的状态(属性)以及调用其他方法。在实例化和使用类的过程中,self 赋予了每个实例独特的状态和行为。
显示调用
在Python中,类的方法(成员函数)对self参数的调用通常是隐式的。也就是说,当你通过一个实例对象调用类的方法时,Python会自动将这个实例对象作为第一个参数传递给方法,这个参数在方法内部被命名为self。例如:
class MyClass:
def method(self, arg):
print("Instance ID:", id(self))
print("Argument:", arg)
instance = MyClass()
instance.method("some argument") # 隐式调用:MyClass.method(instance, "some argument")
在这段代码中,当你执行 instance.method(“some argument”) 时,Python自动将 instance 作为 method 方法的第一个参数传递,这就是所谓的隐式调用。
然而,在极少数情况下,你可能需要显式地调用一个方法,这时通常发生在类的内部或者工厂方法中,为了初始化新创建的对象或者在不通过实例调用的情况下操纵类的方法。显式调用时,你需要明确指定实例并传递给self参数:
class MyClass:
def __init__(self, value):
self.value = value
def modify_value(self, increment):
self.value += increment
@classmethod
def create_and_modify(cls, initial_value, increment):
# 显式创建一个实例并调用方法
instance = cls(initial_value)
instance.modify_value(increment=increment) # 显式调用:instance.modify_value(instance, increment)
return instance
result = MyClass.create_and_modify(10, 5)
-
__init__
方法:这是类的构造函数,当创建类的新实例时会被自动调用。在这个方法里,传入的参数value
被赋值给实例的属性self.value
。这意味着每个MyClass
实例都将有一个与初始化时传入的value
相对应的value
属性。 -
modify_value
方法:这是一个实例方法,用于修改当前实例的value
属性。它接受一个参数increment
,并将self.value
增加这个增量。 -
create_and_modify
方法:这是一个类方法,通过装饰器@classmethod
标识。类方法可以直接通过类来调用,而非通过实例,并且其第一个参数是类本身(通常约定为cls
)。在这个方法中:- 首先,它创建了一个新的
MyClass
实例,传入initial_value
作为__init__
方法的参数。 - 然后,它立即调用了新创建的实例的
modify_value
方法,传入increment
作为增量。 - 最后,返回经过初始化和值修改后的实例。
- 首先,它创建了一个新的
现在,当我们调用MyClass.create_and_modify(10, 5)
时:
- 这个调用触发了类方法
create_and_modify
,其中initial_value
是10,increment
是5。 - 方法首先创建了一个
MyClass
实例,其value
属性初始化为10。 - 接着,它调用
modify_value
方法,将实例的value
属性增加5。 - 结果是一个
MyClass
实例,其value
属性现在是15(初始值10加上增量5)。 - 返回的
result
变量就是这个修改后的实例。
在这个例子中,create_and_modify 是一个类方法,它显式地创建了一个 MyClass 的实例,并通过实例调用了 modify_value 方法,这里的 instance.modify_value(increment) 就是显式调用的例子。但注意,即使是显式调用,程序员通常也不会写出 self 参数,因为Python依然会隐式地将 instance 作为第一个参数传递给 modify_value 方法。
魔术方法(特殊方法__getitem__
在Python中,getitem 是一个特殊方法或者说“魔术方法”(magic method),它允许类对象响应索引操作,也就是使用方括号 [] 进行索引时的行为。当你在一个自定义类上调用 my_object[i] 时,Python会自动调用 getitem 方法,并将 i 作为参数传入。
下面是一个简单的例子来说明 getitem 方法的使用:
class MyListLike:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
if isinstance(index, int):
if index >= 0 and index < len(self.data):
return self.data[index]
else:
raise IndexError("Index out of range.")
elif isinstance(index, slice):
# 支持切片操作
return self.data[index]
else:
raise TypeError("Invalid type for indexing.")
示例用法
my_class = MyListLike([1, 2, 3, 4, 5])
print(my_class[0]) # 输出: 1
print(my_class[1:3]) # 输出: [2, 3]
在这个例子中,MyListLike 类实现了 getitem 方法,使得它可以像列表那样通过索引或切片获取数据。当尝试访问 my_class[0] 或 my_class[1:3] 时,Python会调用相应的方法来获取结果。由于它是私有的,意味着它不会被类外部直接调用,而是通过内置的机制间接调用。但这里的“私有”并不是指访问权限控制意义上的私有(Python中使用双下划线前缀的变量名才会被视为私有属性或方法),而是指这是一种语言层面的约定,用于实现特殊行为。
call
在Python中,类的__call__方法是一个特殊的方法,它允许类的实例像函数一样被调用。当你在一个类的实例后面加上括号并传入参数时,Python会自动调用这个类的__call__方法。
这里有一个简单的例子,它展示了如何使用__call__方法:
class MyClass:
def __init__(self, value):
self.value = value
def __call__(self, other_value):
return self.value + other_value
创建一个类的实例
my_instance = MyClass(10)
使用这个实例像函数一样进行调用
result = my_instance(5)
print(result) # 输出:15
在这个例子中,MyClass有一个__call__方法,它接收一个参数other_value,然后返回self.value和other_value的和。当我们创建MyClass的一个实例my_instance,并像函数一样调用它时(即my_instance(5)),Python会自动调用__call__方法,并传入我们提供的参数(在这个例子中是5)。
__call__方法的一个常见用途是创建可调用的对象,这些对象的行为类似于函数,但具有更多的状态信息和功能。例如,你可以创建一个代表数学函数的类,这个类有一个__call__方法,用于计算并返回该函数在给定的输入值上的结果。这样,你就可以创建多个该类的实例,每个实例代表一个具有不同参数或状态的函数。
成员方法
类的方法
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
#类定义
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)
p = people('runoob',10,30)
p.speak()
类的继承
class one(fu,fufu):
方法重写
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w) 或super(子类,self).__init__(参数1,参数2,....)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
专有方法
● init : 构造函数,在生成对象时调用
● del : 析构函数,释放对象时使用
● repr : 打印,转换
● setitem : 按照索引赋值
● getitem: 按照索引获取值
● len: 获得长度
● cmp: 比较运算
● call: 函数调用
● add: 加运算
● sub: 减运算
● mul: 乘运算
● truediv: 除运算
● mod: 求余运算
● pow: 乘方
明天一定认真学。
以上。