Unless otherwise specified, the following is based on Python3
Outline:
In the Python Tutorial, class variables and instance variables are described like this:
Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class:
Generally speaking, instance variables are for each instance Unique data, while class variables are properties and methods shared by all instances of the class.
In fact, I prefer to use class attributes and instance attributes to call them, but variable has become a customary term for programming languages. A normal example is:
class Dog: kind = 'canine' # class variable shared by all instancesdef __init__(self, name):self.name = name # instance variable unique to each instance
In class Dog
, the class attribute kind
is shared by all instances; the instance attribute name
is unique to each instance of Dog
.
Everything in Python
is an object; after the class definition is completed, it will be in the current scope Define a name with the class name in it, pointing to the name of the class object. For example,
class Dog:pass
will define the name Dog
in the current scope, pointing to the class object Dog
.
Operations supported by class objects:
In general, class objects only support two operations:
instantiation; use Instance_name = class_name()
is instantiated, and the instantiation operation creates an instance of the class.
Attribute reference; use class_name.attr_name
to reference class attributes.
The instance object is the product of class object instantiation. The instance object only supports one operation:
Attribute reference; in the same way as class object attribute reference, use instance_name.attr_name
.
According to strict object-oriented thinking, all attributes should be instances, and class attributes should not exist. Then in Python
, since class attribute binding should not exist, only the function definition is left in the class definition.
The Python tutorial also says the same about class definitions:
In practice, the statements inside a class definition will usually be function definitions, but other statements are allowed, and sometimes useful.
In practice, the statements in a class definition are usually function definitions, but other statements are also allowed and sometimes useful.
The other statements mentioned here refer to the binding statements of class attributes.
When defining a class, what we usually call defining attributes is actually divided into two aspects:
Class attribute binding
Instance attribute binding
The word binding is more precise; whether it is a class object It is still an instance object, and the properties all exist based on the object.
The attribute binding we are talking about requires a variable object first to perform the binding operation. Use the
objname.attr = attr_value
method to create the object objname
Binding attributesattr
.
There are two situations:
If the attribute attr
already exists, the binding operation will point the attribute name to the new object;
If it does not exist, add a new attribute to the object, and you can reference the new attribute later.
Python
As a dynamic language, both class objects and instance objects can bind any attributes at runtime. Therefore, the binding of class attributes occurs in two places:
when the class is defined;
at any stage during runtime.
The following example illustrates the period when class attribute binding occurs:
class Dog: kind = 'canine'Dog.country = 'China'print(Dog.kind, ' - ', Dog.country) # output: canine - Chinadel Dog.kindprint(Dog.kind, ' - ', Dog.country) # AttributeError: type object 'Dog' has no attribute 'kind'
In the class definition, the binding of class attributes does not Use the method objname.attr = attr_value
. This is a special case. It is actually equivalent to the method of binding attributes using class names later.
Because it is a dynamic language, attributes can be added and deleted at runtime.
Same as class attribute binding, instance attribute binding also occurs in two places:
When the class is defined ;
Any stage during runtime.
Example:
class Dog:def __init__(self, name, age):self.name = nameself.age = age dog = Dog('Lily', 3) dog.fur_color = 'red'print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color))# Output: Lily is 3 years old, it has red fur
Python
Class instances have two special features:
__init__
Executed at instantiation
Python
When an instance calls a method, the instance object will be used as the first parameter Pass
Therefore, self
in the __init__
method is the instance object itself, here is dog
, statement
self.name = nameself.age = age
以及后面的语句
dog.fur_color = 'red'
为实例dog
增加三个属性name
, age
, fur_color
。
属性的引用与直接访问名字不同,不涉及到作用域。
类属性的引用,肯定是需要类对象的,属性分为两种:
数据属性
函数属性
数据属性引用很简单,示例:
class Dog: kind = 'canine'Dog.country = 'China'print(Dog.kind, ' - ', Dog.country) # output: canine - China
通常很少有引用类函数属性的需求,示例:
class Dog: kind = 'canine'def tell_kind():print(Dog.kind) Dog.tell_kind() # Output: canine
函数tell_kind
在引用kind
需要使用Dog.kind
而不是直接使用kind
,涉及到作用域,这一点在我的另一篇文章中有介绍:Python进阶 - 命名空间与作用域
使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:
总是先到实例对象中查找属性,再到类属性中查找属性;
属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。
示例1:
class Dog: kind = 'canine'country = 'China'def __init__(self, name, age, country):self.name = nameself.age = ageself.country = country dog = Dog('Lily', 3, 'Britain')print(dog.name, dog.age, dog.kind, dog.country)# output: Lily 3 canine Britain
类对象Dog
与实例对象dog
均有属性country
,按照规则,dog.country
会引用到实例对象的属性;但实例对象dog
没有属性kind
,按照规则会引用类对象的属性。
示例2:
class Dog: kind = 'canine'country = 'China'def __init__(self, name, age, country):self.name = nameself.age = ageself.country = country dog = Dog('Lily', 3, 'Britain')print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 canine Britainprint(dog.__dict__) # {'name': 'Lily', 'age': 3, 'country': 'Britain'}dog.kind = 'feline'print(dog.name, dog.age, dog.kind, dog.country) # Lily 3 feline Britainprint(dog.__dict__) print(Dog.kind) # canine 没有改变类属性的指向# {'name': 'Lily', 'age': 3, 'country': 'Britain', 'kind': 'feline'}
使用属性绑定语句dog.kind = 'feline'
,按照规则,为实例对象dog
增加了属性kind
,后面使用dog.kind
引用到实例对象的属性。
这里不要以为会改变类属性Dog.kind
的指向,实则是为实例对象新增属性,可以使用查看__dict__
的方式证明这一点。
示例3,可变类属性引用:
class Dog: tricks = []def __init__(self, name):self.name = namedef add_trick(self, trick):self.tricks.append(trick) d = Dog('Fido') e = Dog('Buddy') d.add_trick('roll over') e.add_trick('play dead')print(d.tricks) # ['roll over', 'play dead']
语句self.tricks.append(trick)
并不是属性绑定语句,因此还是在类属性上修改可变对象。
与数据成员不同,类函数属性在实例对象中会变成方法属性。
先看一个示例:
class MethodTest:def inner_test(self):print('in class')def outer_test():print('out of class') mt = MethodTest() mt.outer_test = outer_testprint(type(MethodTest.inner_test)) # <class 'function'>print(type(mt.inner_test)) #<class 'method'>print(type(mt.outer_test)) #<class 'function'>
可以看到,类函数属性在实例对象中变成了方法属性,但是并不是实例对象中所有的函数都是方法。
Python tutorial中这样介绍方法对象:
When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
引用非数据属性的实例属性时,会搜索它对应的类。如果名字是一个有效的函数对象,Python会将实例对象连同函数对象打包到一个抽象的对象中并且依据这个对象创建方法对象:这就是被调用的方法对象。当使用参数列表调用方法对象时,会使用实例对象以及原有参数列表构建新的参数列表,并且使用新的参数列表调用函数对象。
那么,实例对象只有在引用方法属性时,才会将自身作为第一个参数传递;调用实例对象的普通函数,则不会。
所以可以使用如下方式直接调用方法与函数:
mt.inner_test() mt.outer_test()
除了方法与函数的区别,其引用与数据属性都是一样的
虽然Python
作为动态语言,支持在运行时绑定属性,但是从面向对象的角度来看,还是在定义类的时候将属性确定下来。
The above is the detailed content of Python basics-class variables and instance variables. For more information, please follow other related articles on the PHP Chinese website!