zoukankan      html  css  js  c++  java
  • Python——面向对象编程

    面向对象编程是一种程序设计思想,把对象作为程序的基本单元,一个对象里面包含了数据以及操作数据的方法,称为类的属性和方法。

    基础-定义、实例化、实例属性

    用class来定义对象,类名首字母大写,如果这个类没有父类,则参数使用object类(object可以省略不写);如果这个类有父类,参数就是父类的名称。可以用一个特殊的方法__init()__方法来对类的属性进行定义。第一个参数固定是self,但是在创建实例的时候self是不需要传入的,self表示实例本身。类中还可以定义方法。第一个参数也是self,后面的参数和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入。通过实例.方法的方式进行调用。

    class Person(object):
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def print_age(self):
            print('%s: %s' % (self.name, self.age))
    >>>tt = Person('taoting',23)
    >>>tt.print_age()
    tt:23

    在类定义中我们可以随时为类增加方法,而外部的代码不需要做改变。因此,面向对象的编程时非常方便进行扩展的。

    方法中带外部参数的类示例:

    注意区别:name和age参数是类固有的属性,在定义实例时就需要传入,而city是实例的方法的参数,只有调用类的方法时才传入

    class Person(object):
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def print_age(self, city):
            print('name: %s age: %s city: %s' % (self.name, self.age, city))
            
    tt = Person('taoting',23)
    tt.print_age('shanghai')
    #结果:name: taoting age: 23 city: shanghai

    类属性

    类属性是直接在class中定义的属性,归类所有,类的所有属性都能访问。

    class Person:
        count = 0
        def __init__(self, name, age):
            self.name = name
            self.age = age
            Person.count = Person.count + 1
    
    tt = Person('taoting', 23)
    print(tt.count)#1 

    访问权限

    在实例中传入的参数是可以通过实例名.参数名进行修改的。有时我们想让内部的一些属性不被外部访问,就可以在属性名称前加上两个下划线__,将属性编程一个私有变量,外部无法访问。

    class Person(object):
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
            
    tt = Person('taoting',23)
    tt.__name
    #报错:AttributeError: 'Person' object has no attribute '__name'

    那么要想在外部代码中访问内部的name和age变量怎么办呢?

    答案:在类中增加方法,在方法中返回变量值。这样就确保了外部不能随便修改变量值,但还能访问到。

    class Person(object):
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
            
        def get_name(self):
            return self.__name
        
        def get_age(self):
            return self.__age
            
    tt = Person('taoting',23)
    print(tt.get_name())
    #结果:taoting

    进一步地,还是有办法能够修改变量值:通过在类中定义方法将要修改的值传入并赋值给__开头的变量:

    class Person(object):
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
            
        def set_name(self, name):
            self.__name = name
            return self.__name
        
        def set_age(self, age):
            self.__age = age
            return self.__age
            
            
    tt = Person('taoting',23)
    
    print(tt.set_name('tt'))
    #结果:tt
    print(tt.set_name(18))
    #结果:18

    通过先设置不能外部修改,再定义供外部程序修改的方法的方式,能够在方法中对参数做检测、处理、等等。

    @property (静态属性) 还可以将一个方法变成一个属性,在调用的时候像调用一个属性一样,不需要加括号。相当于将一个方法进行了封装,调用者不会发现背后的逻辑。静态属性可以访问类属性和实例属性。我们可以在方法里面对属性进行判断,也可以将属性设置成可读可写和只可读:

    #width、height和area方法通过@property变成了类的属性。
    #width、height可以读和写,而area只读
    class Area(object):
        @property
        def width(self):
            return self._width
        @width.setter
        def width(self,value):
            self._width = value
        @property
        def height(self):
            return self._height
        @height.setter
        def height(self,value):
            self._height = value
        @property
        def area(self):
            return self._width * self._height
        
    a = Area()
    a.width = 10
    a.height = 8
    print(a.area)#80
    a.area = 100#AttributeError: can't set attribute
            
    #在可写的属性里面我们可以对传入的值进行检查
    class Area(object):
        @property
        def width(self):
            return self._width
        @width.setter
        def width(self,value):
            if value < 0:
                raise ValueError('width must be greater than 0!')
            self._width = value
        @property
        def height(self):
            return self._height
        @height.setter
        def height(self,value):
            self._height = value
        @property
        def area(self):
            return self._width * self._height
    
    a = Area()
    a.width = -5#ValueError: width must be greater than 0!

    对于实例化的对象,我们可以定义类的没有定义的属性,比如上例中,我们可以定义:a.length = 6。只对本实例化对象有效。

    那么,在类中我们可以指定实例化对象中能够定义的属性,用__slots__实现:

    class Area(object):
        __slots__ = ('name','color')
        @property
        def width(self):
            return self._width
        @width.setter
        def width(self,value):
            if value < 0:
                raise ValueError('width must be greater than 0!')
            self._width = value
        @property
        def height(self):
            return self._height
        @height.setter
        def height(self,value):
            self._height = value
        @property
        def area(self):
            return self._width * self._height
    
    a = Area()
    a.name = 'a'
    a.length = 6#AttributeError: 'Area' object has no attribute 'length'

     当为实例新建一个属性时就会报错。a.length就是调用了setattr方法,也就是a.__dict__['length'] = 6。而定义了__slots__之后,实例就没有__dict__方法了,因此会报错。那么意味着__slots__指定了实例的所有属性。

    这种方式的好处在于能够节省内存,当我们创建成千上万个实例时,如果不用__slots__,那么python会为每个实例创建一个属性字典,这样非常占用内存空间。当我们定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来创建,而不是为每个实例定义一个属性字典。

     @classmethod(类方法)可以定义只跟类相关的操作,定义不用实例化即可调用的函数。cls表示跟类绑定,是固定的参数。类方法可以访问类的数据属性和函数属性,但是不能访问实例的数据属性和函数属性。

    class Person:
        tag = 2
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        #将方法属性化,只跟类有关,不用实例化,cls就是类本身
        @classmethod
        def attr(cls):
            print(cls.tag)
    
            
    Person.attr()#这样调用就可以做一些只跟类有关的操作

    @staticmethod(静态方法),类的工具包,跟类没关系,也跟实例没关系。只是名义上属于类管理,但是不能访问类属性和实例属性。

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        @staticmethod
        def run(a,b):
            print('%s and %s are runing...' % (a,b))
            
    Person.run('tt','rr')#类可以直接调用
    p1 = Person('tt',18)#实例也可以调用
    p1.run('tt','rr')

    继承

    类的继承类似于动物-->猫的关系,猫是属于动物的,猫具有动物的特征。

    在类的继承里,子类继承父类的属性和方法。父类又称为基类、超类

    class Person(object):
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def run(self):
            print('Person is runing...')
            print('name: %s age: %s' % (self.name, self.age))
        
        def attr(self):
            print('This is a super method!')
            
    class Male(Person):
    
        def run(self):
            print('Male is runing...')
            print('name: %s age: %s' % (self.name, self.age))
    
    tt = Person('taoting', 23)
    tt.run()
    #结果:
    #Person is runing...
    #name: taoting age: 23
    ZL = Male('zhaoliang', 26)
    ZL.run()
    #结果:
    #Male is runing...
    #name: zhaoliang age: 26
    
    ZL.attr()
    #结果:This is a super method!

    从以上代码我们可以看到:

    1.子类可以直接继承父类的属性和方法

    2.当父类和子类中有相同的方法时,子类调用方法时优先在子类中搜索,所以上面子类调用run方法时,是调用的子类里面的run方法,而不是父类里面的

    实例对象之间的交互

    在面向对象的编程中,就是大量的实例对象之间的交互。

    我们创建两个类Alien和Automan,再分别实例出两个角色:alien1和automan1,来模拟两者之间的交互。

    class Alien:
        def __init__(self, name, life_value = 500):
            self.name = name
            self.life_value = life_value
            
        def attack(self, enemy):
            enemy.life_value -= 50
            
    class Automan:
        def __init__(self, name, life_value = 1000):
            self.name = name
            self.life_value = life_value
            
        def attack(self, enemy):
            enemy.life_value -= 10
    
    alien1 = Alien('怪兽')
    automan = Automan('迪迦')
    print(alien1.life_value)#500
    print(automan.life_value)#1000
    automan.attack(alien1)
    print(alien1.life_value)#450
    print(automan.life_value)#1000

    类的组合

    在一个类中我们可以实例化另外一个类,作为这个类的属性,这叫类的组合:

    class F1:
        def f1(self):
            print('F1.f1')
    
    
    class F2:
        def __init__(self):
            self.ff2 = F1()
        def f1(self):
            print('F2.f1')
            
    c1 = F2()
    c1.ff2.f1()#F1.f1
  • 相关阅读:
    C#LPT端口连接热敏打印机发送指令
    c# 普通打印机大致有三种方法(非热敏打印机及lpt1并口指令控制型)
    C#直接发送打印机命令到打印机(这里测试的是直接弹出钱箱操作)
    c#操作access,update语句不执行的解决办法
    element-ui dialog组件添加可拖拽位置 可拖拽宽高[转]
    [JavaScript] js实现简单的代码运行框【转】
    HTML5 drag & drop 拖拽与拖放简介[转]
    webpack 单独打包指定JS文件(转)
    跳转地图并定位
    基于Cesium实现逼真的水特效[转]
  • 原文地址:https://www.cnblogs.com/taotingz/p/11341173.html
Copyright © 2011-2022 走看看