面向对象编程-类

面向对象编程OOP (object-oriented programming)是最有效的软件编写方法之一,面向对象是利用“类”和“对象”来创建各种模拟来实现对真实世界的描述,使用面向对象编程的原因一方面试因为它可以使程序的维护和扩展变得简单,

并且可以大大提高程序开发效率,面向对象的程序可以让人更加理解代码的逻辑。面向对象的核心特性之一:Class 类

一个类即是对一类拥有相同属性的对象的抽象,蓝图,原型。在类中定义了这些对象的都具备的属性,共同的方法。根据类来创建对象被称为实例化,这能够使用类的实例。

类的成员分为三大类:字段,方法,属性

一.创建和使用类

创建Dog类,根据Dog类创建每个实例都将存储名字和年龄,赋予每条狗蹲下(sit)和打滚(roll)能力。

class Dog(object):
    def __init__(self,name,age):  #传参数,叫构造函数也叫构造方法==初始化方法
        '''初始化属性name和age'''
        self.name = name
        self.age = age
    def sit(self):  #类的方法
        '''赋予小狗蹲下的能力'''
        print("[%s] is sitting now."%(self.name))
    def roll(self):
        '''赋予小狗打滚的能力'''
        print("[%s] rolling now!"%self.name)

my_dog = Dog('XiaoHei',3) #实例化,my_dog相当于等于__init__(self,name,age)中的self,实例化后产生的对象叫实例
your_dog = Dog("XiaoHuang",4)  #创建第二个实例
my_dog.sit()  #调用类的方法
my_dog.roll()
your_dog.sit()
print("My dog is called %s,it's %d years old"%(my_dog.name,my_dog.age))  #访问my_dog的属性name的值:my_dpg.name
#执行结果:
[XiaoHei] is sitting now.
[XiaoHei] rolling now!
[XiaoHuang] is sitting now.
My dog is called XiaoHei,it's 3 years old

1.方法__init__() 类中的函数称为方法,__init__()是一个特殊的方法(叫做初始化方法或构造方法),每当根据Dog类创建新实例时,在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突. 我们将方法__init__()定义成了包含三个形参:self,name和age,在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self呢?因为Python调用这 __init__()方法来创建 Dog 实例时, 将自动传入实参self。每个与类相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建 Dog 实例时,Python 将调用Dog类的方法 __init__() 。我们将通过实参向 Dog() 传递名字和年龄;self 会自动传递, 因此我们不需要传递它。每当我们根据 Dog 类创建实例时,都只需给最后两个形参name和age提供值。 2.self.name和self.age类似,像这样可通过实例访问的变量称为属性 3.Dog 类还定义了另外两个方法: sit和roll由于这些方法不需要额外的信息,如名字或年龄,因此它们只有一个形参 self 。后面将创建的实例能够访问这些方法。 4.我们创建了两条小狗,它们分别名为xiaohei和xiaohuang。每条小狗都是一个独立的实例,有自己的一组属性,能够执行相同的操作。

 二.给属性指定默认值或修改属性值

类中的每个属性都必须有初始值,哪怕这个值是 0 或空字符串。在有些情况下,如设置默认值时,在方法 __init__() 内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。

'''编写表示汽车的类'''
class Car(object):
    def __init__(self,name,model,year):
        '''初始化描述汽车的属性'''
        self.name = name
        self.model = model
        self.year = year
        self.odometer = 0  #给属性指定默认值
    def describe_car(self):
        '''返回汽车的信息'''
        print("%s %s %d"%(self.name,self.model,self.year))
    def odometer_read(self):
        '''打印汽车里程信息'''
        print("this car has " + str(self.odometer) + " miles on it")
my_car = Car("Audi","a4",2016)
my_car.describe_car()
my_car.odometer_read()
my_car.odometer = 100 #直接修改属性的值
my_car.odometer_read()
#执行结果:
Audi a4 2016
this car has 0 miles on it
this car has 100 miles on it

 三.类的继承

编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用 继承 。一个类 继承 另一个类时,它将自动获得另一个类的所有属性和方法;原有的 类称为 父类 ,而新类称为 子类 。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.sex = "normal"
    def talk(self):
        print("person is talking...")
class BlackPerson(Person):
    def __init__(self,name,age,strength):#先继承再重构
        super(BlackPerson,self).__init__(name,age)
        self.strength = strength
        print(self.name,self.age,self.sex)
    def talk(self):
        print("blackperson is talking")
    def walk(self):   #如果与父类方法重复,用自己的
        print("person is walking")
b = BlackPerson("zww",10,"streng")
b.talk()
b.walk()
#执行结果:
zww 10 normal
blackperson is talking
person is walking

对于BlackPerson来说,Person是它的父类,对于Person来说,BlackPerson是它的子类

super()是一个特殊的函数,帮助python将父类和子类关联起来,这里代码让python调用Person的父类的方法__init__(),让BlackPerson实例包含父类的所有属性和方法,父类也叫超类(supercass),名称super因此得名。

函数 super() 需要两个实参:子类名和对象 self 。为帮助 Python 将父类和子类关联起来,这些实参必不可少。另外,在 Python 2.7 中使用继承时,务必在定义父类时在括号内指定 object 。

 四.封装

定义:顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

在使用面向对象的封装特征时,需要:

   ·将内容封装到某处

   ·从某处调用被封装的内容

#coding:utf-8
#Author:zhiwenwei
class Student(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

obj1 = Student('XiaoMing',18)  #将XiaoMing和18分别封装到name和age属性中
obj2 = Student('zww',24)       #将zww和24分别封装到name和age属性中
print(obj1.name,obj1.age)      #直接调用封装的内容:对象.属性名

 五.静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

#coding:utf-8
#Author:zhiwenwei
class Dog(object):
    def __init__(self,name):
        self.name = name
    @staticmethod  #把eat变为静态方法
    def eat(self):
        print("%s is eating"%self.name)
d = Dog("XiaoHei")
d.eat()

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

D:\软件\python\python.exe C:/python/day7/静态方法-staticmethod.py
Traceback (most recent call last):
  File "C:/python/day7/静态方法-staticmethod.py", line 11, in <module>
    d.eat()
TypeError: eat() missing 1 required positional argument: 'self'

Process finished with exit code 1

想让上面的代码可以正常工作有两种办法

1. 调用时主动传递实例本身给eat方法,即d.eat(d) 

2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

class Dog(object):
    def __init__(self,name):
        self.name = name
    @staticmethod  #把eat变为静态方法
    def eat():
        print(" is eating")
d = Dog("XiaoHei")
d.eat()

 六.类方法

类方法通过@classmethod装饰器实现,类方法和普通方法区别是,类方法只能访问类变量,不能访问实例变量

#coding:utf-8
#Author:zhiwenwei
class Dog(object):
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
d = Dog("XiaoHei")
d.eat()

执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法不能访问实例变量

D:\软件\python\python.exe C:/python/day7/类方法-classmethod.py
Traceback (most recent call last):
  File "C:/python/day7/类方法-classmethod.py", line 11, in <module>
    d.eat()
  File "C:/python/day7/类方法-classmethod.py", line 9, in eat
    print("%s is eating" % self.name)
AttributeError: type object 'Dog' has no attribute 'name'

此时可以定义一个类变量也叫name,看下执行结果

class Dog(object):
    name = "我是类变量"
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
d = Dog("XiaoHei")
d.eat()
#执行结果
我是类变量 is eating

 七.属性方法

属性方法通过@property把一个方法变成一个静态属性

#coding:utf-8
#Author:zhiwenwei
class Dog(object):
    def __init__(self,name):
        self.name = name
    @property
    def eat(self):
        print("%s is eating" %self.name)
d = Dog("xiaohei")
d.eat()

执行会报错说TypeError: 'NoneType' object is not callable,因为eat已经变成一个静态属性了,不是方法,想调用不需要加(),直接d.eat即可

class Dog(object):
    def __init__(self,name):
        self.name = name
    @property
    def eat(self):
        print("%s is eating" %self.name)
d = Dog("xiaohei")
d.eat
#执行结果
xiaohei is eating

 八.类的特殊成员方法

__doc__表示类的描述信息,一般是三重号内的注释信息 __module__表示当前操作的对象在哪个模块 __class__表示当前操作的对象的类是什么 __init__构造方法,通过类创建对象时,自动触发执行 __del__析构方法,当对象在内存中释放时,自动触发执行 __dict__ 类的字典属性、名称空间 __base__ 类的第一个父类 实例:

class Student:
    '''在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间'''
    count = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
        Student.count +=1
class Teacher(Student):
    def __init__(self,name,age,lesson):
        super(Teacher,self).__init__(name,age)
        self.lesson = lesson
        # print("My name is %s.I am %s years old I am your %s teacher"%(self.name,self.age,self.lesson))
    def t_info(self):
        print("My name is %s.I am %s years old I am your %s teacher" % (self.name, self.age, self.lesson))

student1 = Student("Kevin",24)
student2 = Student("Jay",28)
teacher1 = Teacher("alex",24,"English")
teacher1.t_info()
print("__doc__:",Student.__doc__)
print("__module__:",student1.__module__)
print("__class__:",student2.__class__)
print("__dict__:",student2.__dict__)
print("__bash__:",Teacher.__base__)

执行结果:

My name is alex.I am 24 years old I am your English teacher __doc__: 在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间 __module__: __main__ __class__: <class '__main__.Student'> __dict__: {'age': 28, 'name': 'Jay'} __bash__: <class '__main__.Student'>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏lulianqi

支持各种特殊字符的 CSV 解析类 (.net 实现)(C#读写CSV文件)

csv(Comma Separated Values)逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本...

22520
来自专栏从零开始学自动化测试

python笔记2-冒泡排序

前言 面试的时候经常有面试官喜欢问如何进行冒泡排序?这个问题相信能难倒一批英雄好汉,本篇就详细讲解如何用python进行冒泡排序。 一、基本原理 1.概念: 冒...

38660
来自专栏take time, save time

初级程序员面试不靠谱指南(三)

二、指针的好基友的& 1.&的意义。说&是指针的好基友其实不恰当,因为&这个符号在C/C++不止有一种含义,但是因为其经常会和指针一起出现在被问的问题列表上,所...

34090
来自专栏微信公众号:Java团长

Java习惯用法总结

在Java编程中,有些知识 并不能仅通过语言规范或者标准API文档就能学到的。在本文中,我会尽量收集一些最常用的习惯用法,特别是很难猜到的用法。

9710
来自专栏python3

python 面向对象之类方法

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

7520
来自专栏JetpropelledSnake

Python入门之面向对象编程(二)python类的详解

本文通过创建几个类来覆盖python中类的基础知识,主要有如下几个类 Animal :各种属性、方法以及属性的修改 Dog :将方法转化为属性并操作的方法 Ca...

32290
来自专栏java学习

面试题11(谈谈final、finally、finalize的区别)

考点:考察求职者对这3个java关键字的理解和区分 出现频率:★★★★ 【面试题解析】带有 final修饰符的类是不可派生的。在Java核心APⅠ中,有许多应用...

34090
来自专栏C/C++基础

C++11 变参模板

版权声明:感谢您对博文的关注!校招与社招,有需要内推腾讯的可以QQ(1589276509)or 微信(louislvlv)联系我哈,期待您的加入。 ...

45220
来自专栏编程

Python变量与数据类型

1 Python中数据类型 1、整数 Python可以处理任意大小的整数,当然包括负整数,在Python程序中,整数的表示方法和数学上的写法一模一样,例如:,,...

31160
来自专栏转载gongluck的CSDN博客

python笔记:#008#变量的命名

变量的命名 目标 标识符和关键字 变量的命名规则 0.1 标识符和关键字 1.1 标识符 标示符就是程序员定义的 变量名、函数名 名字 需要有 见名知义 的...

38340

扫码关注云+社区

领取腾讯云代金券