《简明Python教程》之面向对象编程

类与对象是面向对象编程的两个主要方面。一个类(Class)能够创建一种新的类型(Type),其中对象(Object)就是类的实例(Instance)。
字段与方法通称类的属性(Attribute)。
字段有两种类型——它们属于某一类的各个实例或对象,或是从属于某一类本身。它们被分别称作实例变量(Instance Variables)与类变量(Class Variables)。

self

假设你有一个 MyClass 的类,这个类下有一个实例 myobject。当你调用一个这个对象的方法,如 myobject.method(arg1, arg2) 时,Python 将会自动将其转换成 MyClass.method(myobject, arg1, arg2)——这就是 self 的全部特殊之处所在。
这同时意味着,如果你有一个没有参数的功能,你依旧必须拥有一个参数——self。

方法

class Person:
    def say_hi(self):
        print('Hello, how are you?')

p = Person()
p.say_hi()
 # 前面两行同样可以写作
 # Person().say_hi()

输出:

Hello, how are you?

init 方法

__init__ 方法会在类的对象被实例化(Instantiated)时立即运行。这一方法可以对任何你想进行操作的目标对象进行初始化(Initialization)操作。

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

    def say_hi(self):
        print('Hello, my name is', self.name)

p = Person('Swaroop')
p.say_hi()
 # 前面两行同时也能写作
 # Person('Swaroop').say_hi()

输出:

Hello, my name is Swaroop

类变量与对象变量

字段(Filed)有两种类型——类变量与对象变量,它们根据究竟是类还是对象拥有这些变量来进行分类。

类变量(Class Variable)是共享的(Shared)——它们可以被属于该类的所有实例访问。该类变量只拥有一个副本,当任何一个对象对类变量作出改变时,发生的变动将在其它所有实例中都会得到体现。

对象变量(Object variable)由类的每一个独立的对象或实例所拥有。在这种情况下,每个对象都拥有属于它自己的字段的副本,也就是说,它们不会被共享,也不会以任何方式与其它不同实例中的相同名称的字段产生关联。

# coding=UTF-8

class Robot:
    """表示有一个带有名字的机器人。"""

    # 一个类变量,用来计数机器人的数量
    population = 0

    def __init__(self, name):
        """初始化数据"""
        self.name = name
        print("(Initializing {})".format(self.name))

        # 当有人被创建时,机器人
        # 将会增加人口数量
        Robot.population += 1

    def die(self):
        """我挂了。"""
        print("{} is being destroyed!".format(self.name))

        Robot.population -= 1

        if Robot.population == 0:
            print("{} was the last one.".format(self.name))
        else:
            print("There are still {:d} robots working.".format(
                Robot.population))

    def say_hi(self):
        """来自机器人的诚挚问候

        没问题,你做得到。"""
        print("Greetings, my masters call me {}.".format(self.name))

    @classmethod
    def how_many(cls):
        """打印出当前的人口数量"""
        print("We have {:d} robots.".format(cls.population))

输出:

(Initializing R2-D2)
Greetings, my masters call me R2-D2.
We have 1 robots.
(Initializing C-3PO)
Greetings, my masters call me C-3PO.
We have 2 robots.

Robots can do some work here.

Robots have finished their work. So let's destroy them.
R2-D2 is being destroyed!
There are still 1 robots working.
C-3PO is being destroyed!
C-3PO was the last one.
We have 0 robots.

population属于 Robot 类,因此它是一个类变量。
name 变量属于一个对象(通过使用 self 分配),因此它是一个对象变量。

通过 Robot.population 而非 self.population 引用 population 类变量
对于 name 对象变量采用 self.name 标记法加以称呼

注意当一个对象变量与一个类变量名称相同时,类变量将会被隐藏

除了 Robot.popluation,我们还可以使用 self.class.population,因为每个对象都通过 self.__class__ 属性来引用它的类。

how_many 实际上是一个属于类而非属于对象的方法。这就意味着我们可以将它定义为一个 classmethod(类方法) 或是一个 staticmethod(静态方法),这取决于我们是否知道我们需不需要知道我们属于哪个类。由于我们已经引用了一个类变量,因此我们使用 classmethod(类方法)

我们使用装饰器(Decorator)将 how_many 方法标记为类方法。

你可以将装饰器想象为调用一个包装器(Wrapper)函数的快捷方式,因此启用 @classmethod 装饰器等价于调用:

how_many = classmethod(how_many)

只能使用 self 来引用同一对象的变量与方法。这被称作属性引用(Attribute Reference)。

类和方法的 文档字符串(DocStrings) :
Robot.__doc__ 访问类的 文档字符串
Robot.say_hi.__doc__ 访问方法的文档字符串

所有的类成员都是公开的,且 Python 中所有的方法都是虚拟的(Vireual)。
但有一个例外:如果你使用数据成员并在其名字中使用双下划线作为前缀,形成诸如 __privatervar 这样的形式,Python 会使用名称调整(Name-mangling)来使其有效地成为一个私有变量

你需要遵循这样的约定:任何在类或对象之中使用的变量其命名应以下划线开头,其它所有非此格式的名称都将是公开的,并可以为其它任何类或对象所使用。请记得这只是一个约定,Python 并不强制如此(除了双下划线前缀这点)

继承

面向对象编程的一大优点是对代码的重用(Reuse),重用的一种实现方法就是通过继承(Inheritance)机制。继承最好是想象成在类之间实现类型与子类型(Type and Subtype)关系的工具。

class SchoolMember:
#代表任何学校里的成员。
def init(self, name, age):
self.name = name
self.age = age
print(‘(Initialized SchoolMember: {})’.format(self.name))

def tell(self):
    #告诉我有关我的细节。
    print('Name:"{}" Age:"{}"'.format(self.name, self.age), end=" ")

class Teacher(SchoolMember):
#代表一位老师。
def init(self, name, age, salary):
SchoolMember.init(self, name, age)
self.salary = salary
print(‘(Initialized Teacher: {})’.format(self.name))

def tell(self):
    SchoolMember.tell(self)
    print('Salary: "{:d}"'.format(self.salary))

class Student(SchoolMember):
#代表一位学生。
def init(self, name, age, marks):
SchoolMember.init(self, name, age)
self.marks = marks
print(‘(Initialized Student: {})’.format(self.name))

def tell(self):
    SchoolMember.tell(self)
    print('Marks: "{:d}"'.format(self.marks))

t = Teacher(‘Mrs. Shrividya’, 40, 30000)
s = Student(‘Swaroop’, 25, 75)

# 打印一行空白行
print()

members = [t, s]
for member in members:
# 对全体师生工作
member.tell()出

$ python oop_subclass.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)

Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"25" Marks: "75"

如果没有在子类中定义一个 init 方法,Python 不会自动调用基类的构造函数,必须显示调用。
如果没有在子类中定义一个 init 方法,Python 将会自动调用基类的构造函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值