文章目录

  • 1. python类的成员函数为什么都要有self参数?
  • 2. 为何调用类的成员函数,你不必给self赋值?
  • 3. 类变量在不同位置定义有什么区别?
  • (1)类变量
  • (2)实例变量
  • (3)局部变量
  • 4. 实例方法、静态方法和类方法区别?
  • (1)实例方法
  • (2)类方法
  • (3)静态方法


1. python类的成员函数为什么都要有self参数?

在定义类的过程中,无论是显式创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数。例如,定义一个 Person 类:

class Person:
	# 类的构造方法
    def __init__(self):
        print("正在执行构造方法")
    # 定义一个study()实例方法
    def study(self,name):
        print(name,"正在学Python")

事实上,Python 只是规定,无论是构造方法还是实例方法,最少要包含一个参数,并没有规定该参数的具体名称。之所以将其命名为 self,只是程序员之间约定俗成的一种习惯,遵守这个约定,可以使我们编写的代码具有更好的可读性(大家一看到 self,就知道它的作用)。

self 参数的具体作用是 代表 类实例化出的对象的地址。目的是 让每个类对象 只能调用 自己的类变量和类方法

如果你接触过其他面向对象的编程语言(例如 C++),其实 Python 类方法中的 self 参数就相当于 C++ 中的 this 指针。

也就是说,同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法,换句话说,Python 会自动绑定类方法的第一个参数指向调用该方法的对象。如此,Python解释器就能知道到底要操作哪个对象的方法了。

若是去掉self参数,则会报这个错:TypeError: 类成员方法名() takes no arguments (1 given)

2. 为何调用类的成员函数,你不必给self赋值?

例子说明:
创建了一个类MyClass,实例化MyClass得到了MyObject这个对象,然后调用这个对象的方法MyObject.method(arg1,arg2) ,这个过程中,Python会自动转为Myclass.mehod(MyObject,arg1,arg2)

这就是Python的self的原理了。

即使你的类的方法不需要任何参数,但还是得给这个方法定义一个self参数,虽然我们在实例化调用的时候不用理会这个参数,不用给它赋值。

3. 类变量在不同位置定义有什么区别?

(1)类变量

类体中、所有函数之外:此范围定义的变量,称为类属性类变量

所有类的实例化对象都同时共享类变量,也就是说,类变量在所有实例化对象中是作为公用资源存在的(通过类名修改类变量的值,会影响所有的实例化对象)。类方法的调用方式有 2 种,既可以使用类名直接调用,也可以使用类的实例化对象调用(不推荐,见最后阐述)。

(2)实例变量

类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性实例变量

其特点是只作用于调用方法的对象。另外,实例变量只能通过对象名访问,无法通过类名访问。

(3)局部变量

类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量

通常情况下,定义局部变量是为了所在类方法功能的实现。需要注意的一点是,局部变量只能用于所在函数中,函数执行完成后,局部变量也会被销毁

class CLanguage :
    name = "xxx"  #类变量
    add = "http://"  #类变量
    def __init__(self):
        self.name = "C语言中文网"   #实例变量
        self.add = "http://c.biancheng.net"   #实例变量
    # 下面定义了一个say实例方法
    def say(self):
        self.catalog = 13  #实例变量
clang = CLanguage()
#修改 clang 对象的实例变量
clang.name = "python教程"
clang.add = "http://c.biancheng.net/python"
print(clang.name)
print(clang.add)

clang2 = CLanguage()
print(clang2.name)
print(clang2.add)
#输出类变量的值
print(CLanguage.name)
print(CLanguage.add)


程序运行结果:
	python教程
	http://c.biancheng.net/python
	C语言中文网
	http://c.biancheng.net
	xxx
	http://

注意:

  • 通过类对象是无法修改类变量的值的,本质其实是给 clang 对象新添加 name 和 add 这 2 个实例变量。
  • 类中,实例变量和类变量可以同名,但这种情况下使用类对象将无法调用类变量,它会首选实例变量,这也是不推荐“类变量使用对象名调用”的原因。

4. 实例方法、静态方法和类方法区别?

具体区别和用法可阅读 blog

(1)实例方法

通常情况下,在类中定义的方法默认都是实例方法。不仅如此,类的构造方法理论上也属于实例方法,只不过它比较特殊。

实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。实例方法通常会用类对象直接调用

class CLanguage:
    #类构造方法,也属于实例方法
    def __init__(self):
        self.name = "C语言中文网"
        self.add = "http://c.biancheng.net"
    # 下面定义了一个say实例方法
    def say(self):
        print("正在调用 say() 实例方法")


调用方法:
clang = CLanguage()
clang.say()

或

#类名调用实例方法,需手动给 self 参数传值
clang = CLanguage()
CLanguage.say(clang)

(2)类方法

Python 类方法和实例方法相似,它最少也要包含一个参数,只不过类方法中通常将其命名为 cls,Python 会自动将类本身绑定给 cls 参数(注意,绑定的不是类对象)。也就是说,我们在调用类方法时,无需显式为 cls 参数传参

和 self 一样,cls 参数的命名也不是规定的(可以随意命名),只是 Python 程序员约定俗称的习惯而已。

类方法需要使用@classmethod修饰符进行修饰。

class CLanguage:
    #类构造方法,也属于实例方法
    def __init__(self):
        self.name = "C语言中文网"
        self.add = "http://c.biancheng.net"
    #下面定义了一个类方法
    @classmethod
    def info(cls):
        print("正在调用类方法",cls)


调用方式:
#使用类名直接调用类方法
CLanguage.info()
#使用类对象调用类方法(不推荐!!!)
clang = CLanguage()
clang.info()

(3)静态方法

静态方法,其实就是我们学过的函数,和函数唯一的区别是,静态方法定义在类这个空间(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中。

静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法

静态方法需要使用@staticmethod修饰。

像有些 和类紧密相关的外部处理函数 可以 当作静态函数封装到类中。

class CLanguage:
    @staticmethod
    def info(name,add):
        print(name,add)


调用方式:
#使用类名直接调用静态方法
CLanguage.info("C语言中文网","http://c.biancheng.net")
#使用类对象调用静态方法
clang = CLanguage()
clang.info("Python教程","http://c.biancheng.net/python")