Python - 类的定义与使用详解(附样例)
面向对象编程(oop)是一种程序设计思想。oop 把对象作为程序的基本单元,一个对象包含数据和操作数据的函数。同样作为面向对象编程语言,Python 的类提供了面向对象编程的所有标准特性:
(2)下面是对这个自定义类的简单实用样例:
(2)实例变量不是说一定要在 __init__ 构造方法中定义,在类的其他自定义方法中也可以定义。甚至可以直接使用 objname.attr = attr_value 的方式给对象绑定属性(新增属性):
(2)类方法的调用注意如下事项:
(2)下面定义两个类并在父类中添加一个私有属性进行测试:
(2)实例化一个 Father 类并进行测试,可以看到外部无法访问私有属性:
- 类继承机制允许多个基类,派生类可以覆盖它基类的任何方法,一个方法可以调用基类中相同名称的的方法。
- 对象可以包含任意数量和类型的数据。
- 和模块一样,类也拥有 Python 天然的动态特性:它们在运行时创建,可以在创建后修改。
1,类的定义
(1)定义类使用 class 关键字,class 后面紧接类名,无类继承时类名后可以加括号也可以不加括号:
注意:在定义实例变量、实例方法时的第一个参数必须是 self。self 其实就相当于 C++ 或者 Java 中的 this,不过在 python 中 self 不是关键词,我们可以定义成 a 或 b 或其它名字都可以,只是约定成俗都使用了self。
#定义一个Person类 class Person: #定义一个类属性 legs = 2 #定义一个实例方法 def run(self): print('running...')
(2)下面是对这个自定义类的简单实用样例:
注意:第 16 行代码 person1.legs = 1 对实例对象 person1 的 legs 属性进行赋值后,就相当于覆盖了类对象 Person 的 legs 属性。而 person2 对象的 legs 没有赋值覆盖,因此引用的就是类对象的 legs 属性。
print("--- 访问类属性 ---") print("Person.legs:", Person.legs) print("--- 实例化对象 ---") person1 = Person() person2 = Person() #访问对象属性 print("person1.legs:", person1.legs) print("person2.legs:", person2.legs) #访问对象方法 person1.run() person2.run() print("--- 修改对象属性、类属性 ---") person1.legs = 1 Person.legs = 3 print("person1.legs:", person1.legs) print("person2.legs:", person2.legs)
2,类属性
Python 作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性除了可以在类定义时就绑定,也可以在运行时任意阶段进行绑定(增加属性,删除属性):
#定义一个Person类 class Person: #定义一个类属性 legs = 2 #定义一个实例方法 def run(self): print('running...') #在运行时添加类属性 Person.hangs = 2 #实例化对象 person = Person() print("person.legs:", person.legs) print("person.hangs:", person.hangs)
3,实例属性
(1)如果某个属性对于每个实例都是独有的,通常我们会在 __init__ 构造方法中将其定义为实例变量:
提示:在类中可以使用“self.实例属性名”来调用实例属性,在类外可以使用“实例名.实例属性名”来调用实例属性。
#定义一个Person类 class Person: #定义一个类属性 legs = 2 #构造方法 def __init__(self,name,age): self.name = name self.age = age #定义一个实例方法 def run(self): print('%s is running...' % self.name) #实例化对象 person = Person("hangge", 100) print("person.legs", person.legs) print("person.name", person.name) print("person.age", person.age) person.run()
(2)实例变量不是说一定要在 __init__ 构造方法中定义,在类的其他自定义方法中也可以定义。甚至可以直接使用 objname.attr = attr_value 的方式给对象绑定属性(新增属性):
#定义一个Person类 class Person: #定义一个属性 legs = 2 #设置姓名 def setName(self,name): self.name = name #定义一个方法 def run(self): print('%s is running...' % self.name) #实例化对象 person = Person() person.setName('hangge') person.age = 99 print("person.legs", person.legs) print("person.name", person.name) print("person.age", person.age) person.run()
4,类方法
(1)类方法和实例方法类似,不同之处在于:
- 类方法需要使用修饰语句:@classmethod
- 类方法至少需要包含一个参数,与实例方法不同的是该参数并非 self,而是 python 程序员约定俗成的参数:cls(cls 表示当前类对象)
- 类方法中是不能调用实例变量的,但是可以调用类变量
#定义一个Person类 class Person: #定义一个类属性 legs = 2 #定义一个实例方法 def run(self): print('running...') #定义一个类方法 @classmethod def info(cls): print("legs:", cls.legs)
- 类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)
- Python 会自动将类本身绑定到 cls 参数(非实例对象),故在调用类方法时,无需显式为 cls 参数传递参数。
Person.info()
5,静态方法
(1)静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,它仅仅托管于某个类的名称空间中,便于使用和维护。定义一个静态方法要注意如下事项:
- 类静态方法需要使用 @staticmethod 修饰
- 类静态方法没有 self、cls 这样的特殊参数,故 Python 解释器不会对其包含的参数做任何类或对象的绑定
- 类静态方法中无法调用任何类和对象的属性和方法,类静态方法与类的关系不大
#定义一个Person类 class Person: #定义一个静态方法 @staticmethod def say(name, words): print('%s: %s' % (name, words))
(2)静态方法的调用,既可以使用类名,也可以使用类对象:
Person.say('hangge', 'Welcome to hangge.com')
6,继承、共有属性、私有属性
(1)类的公有属性在任何地方都能访问。而私有属性只有在类的内部才能访问(即使是子类内部也不能访问父类的私有属性)。要定义一个私有属性,只需在名称前面加两个下划线。
注意:Python 并没有真正的私有化属性,尽管通过前面加下划线的方式将属性私有化了,但其实是伪私有。我们仍然可以通过“对象._类名__私有字段名”(如:son._Father__info)来强制访问私有属性。不过这种方式并不推荐,建议通过 getter 方法或者 @property 的方式来获得私有属性。
(2)下面定义两个类并在父类中添加一个私有属性进行测试:
#定义一个Father类 class Father: #定义一个公有属性 info = "public" #定义一个私有属性 __info = "private" def __init__(self,name): self.name = name def get_name(self): return self.name def printInfo(self): print("--- Father Info ---") print("Father.info: %s" % Father.info) print("Father.__info: %s" % Father.__info) #定义一个Son类,继承Father类 class Son(Father): def __init__(self,name,age): self.age = age super().__init__(name) def get_age(self): return self.age def printInfo(self): print("--- Son Info ---") print("Son.info: %s" % Son.info) print("Son.__info: %s" % Son.__info)
(2)实例化一个 Father 类并进行测试,可以看到外部无法访问私有属性:
#实例化一个Father类 father = Father("Father") father.printInfo() print(father.info) print(father.__info)
(3)实例化一个 Son 类进行测试,发现子类内部也是无法访问父类的私有属性:
#实例化一个Son类 son = Son("Son",18) print(Son.info) son.printInfo()
附:多继承会调用哪个父类的函数?
(1)Python 是支持多继承的,也就是说一个子类可以同时有多个基类。如果继承了多个父类,且父类都有同名方法,则默认只执行第一个父类的方法:
#定义两个父类 class A: def get(self): print("get A") class B: def get(self): print("get B") #定义一个子类 class C(A, B): def __init__(self): print("this is class C") #开始测试 c = C() c.get()
(2)对于 __init__ 构造方法也是同理,如果子类无 __init__,则会调用 第一个父类的 __init__:
#定义两个父类 class A: def __init__(self): print("this is class A") class B: def __init__(self): print("this is class C") #定义一个子类 class C(A, B): def get(self): print("get C") #开始测试 c = C() c.get()