Python3 面向对象

类定义、类对象与实例对象、方法、继承、多继承、方法重写与类属性。

Beginner
Key Pointsself 是实例本身且必须显式声明;类属性被所有实例共享,实例属性互不干扰;MRO 决定多继承的方法查找顺序。

面向对象技术简介

Object orientation bundles data with the methods that operate on it, and organises systems through encapsulation, inheritance and polymorphism. In Python everything is an object — numbers, strings, functions, classes themselves.

  • Class — a template; Instance — a concrete object built from it
  • Encapsulation — hide internals behind a public interface
  • Inheritance — reuse and extend a parent class
  • Polymorphism — same call, different behaviour per type

类定义

Define a class with class Name:, conventionally PascalCase. __init__ is the constructor, called automatically on instantiation; self is the first parameter standing for the instance and is passed implicitly.

Python
class Employee:
    empCount = 0

    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1

    def display_count(self):
        print("Total Employee:", Employee.empCount)

    def display_employee(self):
        print("Name:", self.name, "Salary:", self.salary)

e1 = Employee("Zara", 2000)
e2 = Employee("Manni", 5000)

e1.display_employee()
e2.display_employee()
e2.display_count()
Output
Name: Zara Salary: 2000
Name: Manni Salary: 5000
Total Employee: 2

类对象

A class is itself an object supporting two operations: attribute reference Obj.name and instantiation Obj(). Class attributes are created at class definition and shared by all instances; reading through an instance falls back to them.

Python
class Employee:
    empCount = 0

    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1

print(Employee.empCount)
e1 = Employee("Zara", 2000)
print(Employee.empCount)
print(e1.empCount)

e1.empCount = 99
print(e1.empCount, Employee.empCount)
Output
0
1
1
99 1
e1.empCount = 99 does not modify the class attribute — it shadows it with a new instance attribute. To change the shared value you must write Employee.empCount = ....

类的方法

Three method kinds: instance methods take self, @classmethod takes the class as cls, and @staticmethod takes nothing implicit. @property exposes a method as a readable attribute.

Python
class Circle:
    pi = 3.14159

    def __init__(self, r):
        self.r = r

    def area(self):
        return Circle.pi * self.r ** 2

    @classmethod
    def unit(cls):
        return cls(1)

    @staticmethod
    def describe():
        return "a circle helper"

    @property
    def diameter(self):
        return self.r * 2

c = Circle(2)
print(round(c.area(), 2))
print(round(Circle.unit().area(), 2))
print(Circle.describe())
print(c.diameter)
Output
12.57
3.14
a circle helper
4

继承

Put the parent class in parentheses to inherit. The child gets the parent's attributes and methods and can reuse them via super(). isinstance() returns true for the parent type too.

Python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def intro(self):
        return "%s, %d" % (self.name, self.age)

class Student(Person):
    def __init__(self, name, age, school):
        super().__init__(name, age)
        self.school = school

    def intro(self):
        return super().intro() + " @ " + self.school

s = Student("Tom", 20, "MIT")
print(s.intro())
print(isinstance(s, Student), isinstance(s, Person))
print(issubclass(Student, Person))
Output
Tom, 20 @ MIT
True True
True

多继承

A class may inherit from several parents. Lookup follows the MRO: depth-first, left to right, each class appearing once. Inspect it with Class.__mro__.

Python
class A:
    def who(self):
        return "A"

class B(A):
    def who(self):
        return "B"

class C(A):
    def who(self):
        return "C"

class D(B, C):
    pass

print(D().who())
print([c.__name__ for c in D.__mro__])
print(D.__mro__[1].__name__)
Output
B
['D', 'B', 'C', 'A', 'object']
B

方法重写

Redefining a parent method in the child overrides it. To keep the parent behaviour as well, call super().method() explicitly — that extends instead of replacing.

Python
class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "Woof"

class Puppy(Dog):
    def speak(self):
        return super().speak() + "!"

for a in (Animal(), Dog(), Puppy()):
    print(type(a).__name__, a.speak())
Output
Animal ...
Dog Woof
Puppy Woof!

类属性与方法

Class attributes belong to the class and are shared; instance attributes belong to one object. A double leading underscore triggers name mangling (__x becomes _Class__x) — a convention, not enforcement.

Python
class JustCounter:
    __secretCount = 0
    publicCount = 0

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1

c = JustCounter()
c.count()
c.count()

print(c.publicCount)
print(c._JustCounter__secretCount)
try:
    print(c.__secretCount)
except AttributeError as e:
    print("AttributeError:", e)
Output
2
2
AttributeError: 'JustCounter' object has no attribute '__secretCount'
The double underscore only mangles the name; it is not real access control. Use a single underscore _name to signal "internal" — that is the Pythonic convention.

Friends & Partners