Python — 面向对象编程基础

面向对象编程基础

         活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”

        我们先来看看比较正式的说法。

把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。

类和对象

      简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是

      从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切

      皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们

      把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一

      个叫做“类”的东西

 

 函数的写法

"""
标识    函数名字 ():
    有冒号就要缩进一个tab
在Python中所有的函数都有返回值,如果你没有给予return则默认返回出None,如果你给予了,则返回你给予的值
""""
def    funcName():
     .....
    return ....
  
"""
标识    类名      ()     :
    有冒号就要缩进一个tab
"""
class  className(object):
    ........
"""
1.导入库, import 库名
2. for 循环,如果计数的情况则使用
        开始  结束  不长
    range的区间是一个前闭后开.
    range(start,end,[step])
3. 格式化输出
3.1 %-->%(),%d后接整型,%f后接浮点,%s后接字符串.
3.2 {}-->format(),它可以直接传入任何类型,然后格式化输出.

4.print 控制台(terminal)打印
4.1 end 以什么方式结尾,默认以换行符"\n"
4.2 flush 刷新缓冲区.
"""
"""
类中的函数可以有自己的参数
当你想共享这个参数的时候,那么就打上"self"的印记.
"""

class A(object):
    def __init__(self,a):
        self.a = a
    def B(self,b):
        self.b = b
        print(b)
    def C(self):
        print(self.b)
        


J = A(1000)
J.B(10)
J.C()

定义类

# object 不是一个参数
"""
定义类只有两步:
1. 使用标识符class ClassName(object):
2. 重写__init__函数,但是需要记住,一定要打上一个"self"的标记
   因为后面会学到继承,当在继承的时候可能就会有函数名相撞的情况.
   或者说,类中会含有多个变量,多个函数,那么就需要使用"self"手段去区分.
3. 类的传参是在__init__函数中的.需要注意的是,如果你的参数可能被多个函数都使用,那么
   你才在__init__函数中去定义参数
"""
class Student(object):
    def __init__(self,name):
          # 多个打印用","进行分隔.
        print(name)


Student(10

      在Python中可以使用class关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对

     象的动态特征描述出来,代码如下所示。

# 在Python2中这个object一定要写,但是在Python3中可写可不写(默认就继承了object).
# 
class Student(object):
    # __init__是一个特殊方法用于在创建对象时进行初始化操作
    # 通过这个方法我们可以为学生对象绑定name和age两个属性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self, course_name):
        print('%s正在学习%s.' % (self.name, course_name))

    # PEP 8要求标识符的名字用全小写多个单词用下划线连接
    # 但是很多程序员和公司更倾向于使用驼峰命名法(驼峰标识)
    def watch_av(self):
        if self.age < 18:
            print('%s只能观看《熊出没》.' % self.name)
        else:
            print('%s正在观看岛国爱情动作片.' % self.name
# 实例
student = Student()

   说明:写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息

# 学类会有些累.
class Student(object):
    """
    第二步初始化,初始化自己.
    当你的类有一些公用变量的时候,你就可以初始化
    初始化中经常放入公有的变量.
    """
    def __init__(self,name):
        """
        在类中,一切的变量和函数都要印记(self)
        """
        self.name = name
    def def1(self,num):
        self.num = num
        print(self.num)
        print(self.name)
    def def2(self):
        print(self.num)
        print(self.name)

        
if __name__ == "__main__":
    # 实例,类名带括号“Student()”,直接运行初始化函数
    student = Student('杜苗苗')
    student.def1(100)
    student.def2()

创建和使用对象

 当我们定义好一个类之后,可以通过下面的方式来创建对象并给对象发消息

def main():
    # 创建学生对象并指定姓名和年龄
    stu1 = Student('骆昊', 38)
    # 给对象发study消息
    stu1.study('Python程序设计')
    # 给对象发watch_av消息
    stu1.watch_av()
    stu2 = Student('王大锤', 15)
    stu2.study('思想品德')
    stu2.watch_av()


if __name__ == '__main__':
    main()

 

访问可见性问题

       对于上面的代码,有C++、Java、C#等编程经验的程序员可能会问,我们给Student对象绑定的nameage

       属性到底具有怎样的 访问权限(也称为可见性)。因为在很多面向对象编程语言中,我们通常会将对象的

       属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通

       常都是公开的(public),因为公开的方法就是对象能够接受的消息。在Python中,属性和方法的访问权限

       只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头,

      下面的代码可以验证这一点。

# 私有变量,变量名前面加"__"
# 如果非要使用私有变量,那么可以使用dir(class())去查看它真正的名字.
# 私有变量/函数,在类内部可以直接调用.
# 如果你想体现一个变量/函数特别重要你可以使用"_"
class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    # AttributeError: 'Test' object has no attribute '__bar'
    test.__bar()
    # AttributeError: 'Test' object has no attribute '__foo'
    print(test.__foo)


if __name__ == "__main__":
    main()

          但是,Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个

         名字来“妨碍”对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可

         以验证这一点。之所以这样设定,可以用这样一句名言加以解释,就是“We are all consenting adults here”。

         因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    test._Test__bar()
    print(test._Test__foo)


if __name__ == "__main__":
    main()

          在实际开发中,我们并不建议将属性设置为私有的,因为这会导致子类无法访问(后面会讲到)。

           所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保

           护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,

           单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻,关

          于这一点可以看看我的《Python - 那些年我们踩过的那些坑》文章中的讲解。

面向对象的支柱

          面向对象有三大支柱:封装、继承和多态。后面两个概念在下一个章节中进行详细的说明,这里

          我们先说一下什么是封装。我自己对封装的理解是“隐藏一切可以隐藏的实现细节,只向外界暴露

        (提供)简单的编程接口”。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在

          我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是

          说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细

          节(方法的内部视图)。

练习

练习1:定义一个类描述数字时钟

class Clock(object):
    """数字时钟"""

    def __init__(self, hour=0, minute=0, second=0):
        """初始化方法

        :param hour: 时
        :param minute: 分
        :param second: 秒
        """
        self._hour = hour
        self._minute = minute
        self._second = second

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def __str__(self):
        """显示时间"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    clock = Clock(23, 59, 58)
    while True:
        print(clock)
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

练习2:定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法。

from math import sqrt


class Point(object):

    def __init__(self, x=0, y=0):
        """初始化方法
        
        :param x: 横坐标
        :param y: 纵坐标
        """
        self.x = x
        self.y = y

    def move_to(self, x, y):
        """移动到指定位置
        
        :param x: 新的横坐标
        "param y: 新的纵坐标
        """
        self.x = x
        self.y = y

    def move_by(self, dx, dy):
        """移动指定的增量
        
        :param dx: 横坐标的增量
        "param dy: 纵坐标的增量
        """
        self.x += dx
        self.y += dy

    def distance_to(self, other):
        """计算与另一个点的距离
        
        :param other: 另一个点
        """
        dx = self.x - other.x
        dy = self.y - other.y
        return sqrt(dx ** 2 + dy ** 2)

    def __str__(self):
        return '(%s, %s)' % (str(self.x), str(self.y))


def main():
    p1 = Point(3, 5)
    p2 = Point()
    print(p1)
    print(p2)
    p2.move_by(-1, 2)
    print(p2)
    print(p1.distance_to(p2))


if __name__ == '__main__':
    main()

       说明:本章中的插图来自于Grady Booch等著作的《面向对象分析与设计》一书,该书是讲解面向对象

                 编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识

案例1

# 输入两个数字,打印这两个数的
# 差,和、乘、除、整除、取余、平方
class YUantingting(object):
    def __init__(self,a,b):
        print(a+b,a-b,a*b)

YUantingting(1,2)

案例2

"""
if 条件:
    执行体
elif 条件:
    执行体
else:
    如果if不走.则走else
"""

# object 不是一个参数

# class 
# 输入一个年龄,如果年龄大于18小于20可观看4级
# 如果年龄大于20小于50-->岛国
# 如果大于50岁,别看啦,扛不住的》 

class Joker(object):
    def __init__(self,age):
        if 18<= age <=20:
            print('4级')
        elif 20< age <= 50:
            print('岛国')
        else:
            print('扛不住')

Joker(18)

案例3

"""
定义3个函数,第一个函数:年龄判断 <18 ,18<40,40>
          第二个函数:性别判断: 男,女,未知
          第三个函数:打印 (年轻,中年,老年)和性别
"""
class Name(object):
    def __init__(self,age,gener):
        self.age = age
        self.gener = gener
    def Age(self):
        if self.age <= 18:
            print('年轻')
        elif 18< self.age <= 40:
            print('中年')
        else:
            print('老年')
    def Gener(self):
        if self.gener == '':
            print('您 ! 是! 男~')
        elif self.gener == "":
            print('您 ! 是! 女~')
        else:
            print('您好~')


Joker = Name(18,'')
Joker.Age()
Joker.Gener()

案例4

# 1.判断一个数字是不是素数.
# 2.数字时钟..(写闹钟,可以设定一个时间,打印闹钟响了)


"""
for xxx:
    ....
else:
    ....
当for循环能够顺利执行完毕,也就是说没有brek,则走else
否则else不走


for i in range(10):
    print(i)
else:
    print('hahah')
"""


class Name(object):
    """
    判断一个数字是否是素数
    """
    def __init__(self,num):
        """
        Argus:
        -----
            num: int类型的数字
        """
        self.num = num
    def Check(self):
        """
        检查self.num是不是素数
        """
        for i in range(2,self.num):
            if self.num % i == 0:
                print('不是素数')
                break
        else:
            print('是素数')
name = Name(11)
name.Check()

 

 

 

posted on 2019-08-06 19:29  liyuan~  阅读(220)  评论(0编辑  收藏  举报

导航