[关闭]
@SuHongjun 2020-11-24T08:52:01.000000Z 字数 3260 阅读 308

Python-Day 18:类和对象 - 基础知识1

Python 2020春季学期


类定义

  1. class 类名(): #class是类定义的关键字
  2. 多个(≥0)类属性...
  3. 多个(≥0)方法...
  4. '''
  5. class 类名: #旧的书写方式
  6. 多个(≥0)类属性...
  7. 多个(≥0)方法...
  8. '''

类中的属性和方法统称为成员

类和对象

类是一个模板,而对象是类的实例。类好比是设计图,而对象是按照设计图生产出来的产品。

  1. class A( ):
  2. pass
  3. x = A( ) #类的实例化, x是class A的一个对象
  4. y = A #不是类的实例化,只是给 class A取了一个别名
  1. class people( ):
  2. '''这里是类的说明文档'''
  3. pass
  4. class C1():
  5. pass
  6. class C2():
  7. a1 = "John" #属性 ,类属性 class attribute
  8. a2 = 27 #属性 ,类属性 class attribute
  9. class C3():
  10. def sayHi(self): #实例方法 instance method
  11. print("Hello")
  12. >>> o=C3() #类的实例化:创建对象
  13. >>> o.sayHi() #实例方法的调用
  14. Hello
  15. >>> o2 = C3 #不是实例化,而是给类起了一个别名
  16. >>> o2.sayHi() #出错:TypeError: sayHi() missing 1 required positional argument: 'self'

python实例化对象时要在类名后加上小括号,如果不带括号则是给类对象起了一个别名,不会创建实例。

类中的变量:属性、局部变量

在类体中,根据变量定义的位置不同,以及定义的方式不同,类中的变量分为 3 种:

类体中,所有函数之外: 此范围定义的变量,称为类属性或类变量;
类体中,函数内部: 以“self.变量名”的方式定义的变量,称为实例属性或实例变量;
类体中,函数内部: 以“变量名=变量值”的方式定义的变量,称为局部变量。

  1. class c5():
  2. a1 = "Jack" #class attribute,类属性
  3. a2 = 21 #class attribute,类属性
  4. def sayHi(self,name='小王'): #instance method,实例方法
  5. self.xm = name # xm: instance attribute, 实例属性
  6. x = 3 # x: 局部变量
  7. print("Hi",self.xm)

类中的函数:方法

类体中的函数叫做方法。
方法分为:

实例方法:通常情况下,在类中定义的方法默认都是实例方法,实例方法至少要有一个参数,按一般惯例第一个参数是self。实例方法通常用类对象直接调用。

类方法:需要使用@classmethod修饰符进行修饰 (以后介绍)
静态方法:需要使用@staticmethod修饰。 (以后介绍)
静态方法,其实就是我们学过的函数,和函数唯一的区别是,静态方法定义在类这个空间(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中。

  1. class Person4( ): #定义类Person4
  2. def say_hi(self, n): #定义实例方法say_hi
  3. self.name = n #创建实例属性,把参数n赋值给实例属性self.name
  4. print('您好, 我叫', self.name)
  5. p4 = Person4() #创建对象
  6. #print(p4.name) #出错,因为还没有调用say_hi(), 而name是在调用say_hi()的时候才创建出来的
  7. p4.say_hi('Alice') #调用对象的实例方法
  8. print(p4.name) #正确
  1. class C:
  2. @staticmethod #静态方法
  3. def f(arg1, arg2, ...): ...
  4. #It can be called either on the class (such as C.f()) or on an instance (such as C().f()).
  5. class C:
  6. @classmethod #类方法
  7. def f(cls, arg1, arg2, ...): ...
  8. #It can be called either on the class (such as C.f()) or on an instance (such as C().f()).
  1. class Foo( ):
  2. classname = "Foo"
  3. def __init__(self, n):
  4. self.name = n #创建实例属性
  5. def f1(self): #实例方法
  6. print(self.classname + ',实例方法') #实例方法中引用类属性
  7. print(self.name + ',实例方法') #引用实例属性
  8. @staticmethod
  9. def f2(): #静态方法
  10. print("static静态方法")
  11. @classmethod
  12. def f3(cls): #类方法
  13. print(cls.classname + ',类方法') #类方法中引用类属性,不能用self.classname
  14. #测试代码
  15. print("用类名调用静态方法、类方法:")
  16. Foo.f2() #用类名调用 静态方法
  17. Foo.f3() #用类名调用 类方法
  18. #Foo.f1() #这样调用将会出错,因为没有了隐式的self参数传递
  19. f = Foo("李晓东")
  20. f.f1() #实例方法调用
  21. print("用对象调用静态方法、类方法:")
  22. f.f2()
  23. f.f3()

输出:
用类名调用静态方法、类方法:
static静态方法
Foo,类方法
Foo,实例方法
李晓东,实例方法
用对象调用静态方法、类方法:
static静态方法
Foo,类方法

Python 也支持使用类名调用实例方法,但此方式需要手动给 self 参数传值。例如:

  1. #类名调用实例方法,需手动给 self 参数传值
  2. clang = CLanguage()
  3. CLanguage.say(clang) #既然叫实例方法,当然是要结合某个实例(对象)才行

在实际编程中,很少用到类方法和静态方法,因为我们完全可以使用函数代替它们实现想要的功能。在一些特殊的设计模式(例如工厂模式)中会用到类方法和静态方法。

有关类属性的一些注意事项:

一般而言,类属性作用于该类的所有对象,但前提是该对象没有同名的实例属性,如果有同名的实例属性,则该对象内会屏蔽掉同名的类属性。

  1. class c( ):
  2. a1 = 5 #类属性
  3. obj1 = c( )
  4. obj2 = c( )
  5. >>> obj1.a1
  6. 5
  7. >>> obj2.a1
  8. 5
  9. >>> c.a1 = 8 #这是正确的修改类属性的方式,类名c不带()
  10. >>> obj1.a1
  11. 8
  12. >>> obj2.a1
  13. 8
  14. >>> c().a1 = 10 #这里试图修改类属性,但其实是创建了一个同名的实例属性,所以没有修改类属性
  15. >>> obj1.a1
  16. 8
  17. >>> obj2.a1
  18. 8
  19. >>> obj1.a1 = 20 #这里并不是修改类属性,而是在obj1对象创建了一个和类属性同名的实例属性
  20. >>> obj1.a1
  21. 20 #和类属性同名的实例属性屏蔽了类属性
  22. >>> obj2.a1
  23. 8 #类属性的值没有变化
  1. class Person3:
  2. count = 0 #定义属性count,表示计数
  3. name = "Jack" #定义属性name1,表示名称
  4. #测试代码
  5. Person3.count += 1 #通过类名访问,将计数加1
  6. print(Person3.count) #类名访问,读取并显示类属性
  7. print(Person3.name) #类名访问,读取并显示类属性
  8. p1 = Person3() #创建实例对象1
  9. p2 = Person3() #创建实例对象2
  10. print((p1.name, p2.name)) #通过实例对象访问,读取成员变量的值
  11. Person3.name = "Tom" #通过类名访问,设置类属性值
  12. print((p1.name, p2.name)) #读取成员变量的值
  13. p1.name = "Alice" #p1.name实际上并没有引用类属性name,而是给p1对象创建了一个新的实例属性name,
  14. #而新的实例属性name屏蔽了同名的类属性name
  15. print((p1.name, p2.name))
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注