Python中的类和实例属性
在Python编程语言中,类和实例是面向对象编程中最关键的两个概念。类是模板,实例是根据类创建的独特对象。所有对象的程序相同,但数据可能不同。
在本教程中,我们将学习Python中的类,如何实例化它们,什么是属性,以及Python中类属性和实例属性的区别。让我们从定义开始:
什么是类?
在Python中,类提供了一种将数据和功能捆绑在一起的方法。创建新类会创建一种新类型的对象,允许创建该类型的新的实例。Python中的每个类实例都可以附加属性来维护其状态。类实例也可以具有方法(由其类定义)来修改其状态。
什么是实例?
对象或实例
Python是一种面向对象的编程语言,它强调对象,即它主要强调函数。在Python中,对象基本上是将数据变量和作用于该数据的方法封装到单个实体中。Python中几乎所有东西都是对象,都有其属性和方法。即使运行“x = 5”,实际上也是从'int'类创建了一个对象。
Python的类属性是在类中包含的属性/变量。也就是说,它的作用域在Python类中。
Python中的类属性只创建单个副本,此单个副本由该特定类中的所有函数和对象共享和使用。
语法
class ClassName: some_string = 'test' # this is a class attribute
对于该类的所有实例,它都将相同。让我们从此类创建两个对象,并查看输出。
示例
o1 = ClassName() o2 = ClassName() print(ClassName.some_string) print(o1.some_string) print(o2.some_string)
输出
# test # test # test
正如观察到的那样,类属性在所有从中创建的对象之间是共享的。此外,类属性可以通过类名.属性名以及对象.属性名来访问。也可以使用类名.属性名 = '新值'来更改属性值。
Python的实例属性是局部属性/变量,其作用域在使用该属性的特定函数中。
每次创建对象时,实例属性都会创建自己的新副本。实现此行为最常用的函数是__init__()方法。
语法
class SomeClass: def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2
可以将任意数量的属性传递给构造函数。每个对象如何获得自己的属性可以通过“self”在创建时引用对象来理解,因此“self”永远无法直接从类中访问。
示例
obj1 = SomeClass('test', 10) obj2 = SomeClass('hello', 15) print(obj1.attr1, obj1.attr2) print(obj2.attr1, obj2.attr2)
输出
# test 10 # hello 15
在这里我们可以看到每个对象都有其自己的属性值,并且只有对象本身可以访问它们。
因此,更改一个对象的属性不会影响其他对象。
实例属性使用与类属性相同的点(.)表示法进行访问。可以使用对象名.属性名 = '新值'来更改或重新赋值它们。
更改类属性值
更改它们的方式可能与更改实例属性的方式相同,毕竟为什么不呢?一个字,继承。
让我们来看一个示例,在这个示例中,我们定义一个函数,每次调用该函数时都会将类属性的值乘以5。
示例
class ClassA: some_string = 'test' # this is a class attribute class_val = 2 # this is also a class attribute def update(self): ClassA.class_val *= 5 o1 = ClassA() o2 = ClassA() o1.update() print(ClassA.class_val) o2.update() print(ClassA.class_val)
输出
# 10 # 50
现在让我们创建一个从该类继承的新类。
示例
class ClassB(ClassA): pass new_obj = ClassB() print(ClassA.class_val, ClassB.class_val) new_obj.update() print(ClassA.class_val, ClassB.class_val)
输出
# 50 50 # 250 250
为什么新类对象可以更改其父类的属性及其自身的属性?更重要的是,如何修复它?
我们编写的内容有两个主要问题:
ClassB定义中的“pass”关键字
以下代码:
def update(self): ClassA.class_val *= 5
简单地放置“pass”意味着ClassB没有自己的属性,它只是指向其父类。其次,由于我们的尝试,我们对类名进行了硬编码。
此外,调用此函数需要先创建一个对象,因为它需要“self”引用。相反,我们可以使用所谓的“类方法”,它具有相同名称的装饰器。以下是它应该的样子:
@classmethod def update(cls): cls.class_val *= 5
它基本上表示我们只想更改从其调用的特定类的属性。让我们来看一个例子,使事情更清楚。
最后,我们的两个类应该如下所示:
示例
class OldClass: some_string = 'test' # this is a class attribute class_val = 2 # this is also a class attribute @classmethod def update(cls): cls.class_val *= 5 class NewClass(OldClass): class_val = 2 # this is different from the parent class
现在是时候分别从两个类调用更新函数了。
print("Initially:", OldClass.class_val, NewClass.class_val) OldClass.update() print("After calling update on old class once:", OldClass.class_val, NewClass.class_val) NewClass.update() NewClass.update() print("After calling update on new class twice:", OldClass.class_val, NewClass.class_val)
输出
# Initially: 2 2 # After calling update on old class once: 10 2 # After calling update on new class twice: 10 50
因此,现在我们可以更改Python中的类属性而无需创建对象,即使在从父类继承之后,类方法也会知道要更改哪个类的属性。