面向对象编程是Python采用的基本编程思想,它可以将属性和代码集成在一起,定义为类,从而使程序设计更加简单、规范、有条理。本章将介绍如何在Python中使用类和对象

个人理解:就是一个人,它有手有脚有头有自己的思想,泛指人类,对象就是一个具体的人,这个人是谁,它的手和脚是什么样子的,就是将一个人类(泛指)定义成了一个人(具体)

面向对象程序设计中的基本概念

(1)对象(Object):面向对象程序设计思想可以将一组数据和与这组数据有关操作组装在一起,形成一个实体,这个实体就是对象。

(2)类(class):具有相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象。例如,如果人类是一个类,则一个具体的人就是一个对象。

(3)封装:将数据和操作捆绑在一起,定义一个新类的过程就是封装。

(4)继承:类之间的关系,在这种关系中,一个类共享了一个或多个其他类定义的结构和行为。继承描述了类之间的关系。子类可以对基类的行为进行扩展、覆盖、重定义。如果人类是一个类,则可以定义一个子类“男人”。“男人”可以继承人类的属性(例如姓名、身高、年龄等)和方法(即动作。例如,吃饭和走路),在子类中就无需重复定义了。从同一个类中继承得到的子类也具有多态性,即相同的函数名在不同子类中有不同的实现。就如同子女会从父母那里继承到人类共有的特性,而子女也具有自己的特性。

(5)方法:也称为成员函数,是指对象上的操作,作为类声明的一部分来定义。方法定义了可以对一个对象可以执行的操作。

(6)构造函数:一种成员函数,来在创建对象时初始化对象。构造函数一般与它所属的类完全同名。

(7)析构函数:析构函数与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作。

声明类

在Python中,可以使用class关键字来声明一个类,其基本语法如下:

class 类名:
    成员变量
    成员函数

同样,Python使用缩进标识类的定义代码。

class person:
    def SayHello(self):
        print("Hello~!");

可以看到,在成员函数SayHello()中有一个参数self。这也是类的成员函数(方法)与普通函数的主要区别。类的成员函数必须有一个参数self,而且位于参数列表的开头。self就代表类的实例(对象)自身,可以使用self引用类的属性和成员函数。在后面部分还会结合实际应用介绍self的使用方法。

定义类的对象

对象是类的实例。如果人类是一个类的话,那么某个具体的人就是一个对象。只有定义了具体的对象,才能使用类。

Python创建对象的方法如下:

    对象名 = 类名()

p例如,下面的代码定义了一个类Person的对象p:

    p = Person()
class Person:
    def SayHello(self):
        print("Hello!");
p = Person()
p.SayHello()

运行结果如下:

Hello!

成员变量

【例4-3】 定义一个字符串类MyString,定义成员变量str,并同时对其赋初始值。

class MyString:
    str = "MyString";
    def output(self):
        print(self.str);
s = MyString()
s.output()

构造函数

构造函数是类的一个特殊函数,它拥有一个固定的名称,即init(注意,函数名是以两个下划线开头和两个下划线结束的).当创建类的对象实例时系统会自动调用构造函数,通过构造函数对类进行初始化操作。

class MyString:
    def __init__(self):
        self.str = "MyString"
    def output(self):
        print(self.str);
s = MyString()
s. output()

即:声明对象的时候会先自动执行该函数

运行结果:MyString

class UserInfo:
    def __init__(self, name, pwd):
        self.username = name
        self._pwd = pwd
    def output(self):
        print("用户:"+self.username +"\n密码:"+ self._pwd);
u= UserInfo("admin", "123456")
u.output()

运行结果:
用户:admin
密码:123456

析构函数

Python析构函数有一个固定的名称,即_ del _ ()。通常在析构函数中释放类所占用的资源。

使用del语句可以删除一个对象。释放它所占用的资源。

class MyString:
    def __init__(self): #构造函数
        self.str = "MyString"
    def __del__(self):  #析构函数
        print("byebye~")
    def output(self):
        print(self.str);
s = MyString()
s.output()
del s  #删除对象

即在程序最后释放内存

运行结果:
MyString
byebye~

静态变量和静态方法

静态变量和静态方法是类的静态成员,它们与普通的成员变量和成员方法不同,静态类成员与具体的对象没有关系,而是只属于定义它们的类。

在类中可以定义静态变量,与普通的成员变量不同,静态类成员与具体的对象没有关系,而是只属于定义它们的类。

Python不需要显式定义静态变量,任何公有变量都可以作为静态变量使用。访问静态变量的方法如下

class Users (object):
        online_count = 0;
        def __init__(self):# 构造函数,创建对象时Users.online_count加1
                Users.online_count+=1;
                print('我正在运行构造函数')
        def __del__(self):# 析构函数,释放对象时Users.online_count减1
                Users.online_count-= 1;
                print('我正在运行析构函数')
a = Users();
a.online_count += 1
print('a对象的值:',a.online_count);
print('users默认对象的值:',Users.online_count);

运行结果:
我正在运行构造函数
a对象的值: 2
users默认对象的值: 1
我正在运行析构函数

静态对象我理解为,每个人都有,但是都不同,比如例子里的a和users,users的online_count和a的online_count是互不影响的,你在哪个上面加并不会影响其他的,我个人理解的话users是默认对象

与静态变量相同,静态方法只属于定义它的类,而不属于任何一个具体的对象。静态方法具有如下特点:

(1)静态方法无需传入self参数,因此在静态方法中无法访问实例变量。

(2)在静态方法中不可以直接访问类的静态变量,但可以通过类名引用静态变量。

因为静态方法既无法访问实例变量,也不能直接访问类的静态变量,所以静态方法与定义它的类没有直接关系,而是起到了类似函数工具库的作用

使用装饰符@staticmethod定义静态方法

class 类名:
    @staticmethod
    def 静态方法名():
        方法体

例如:

class MyClass: #定义类
        var1 = 'String 1' 
        @staticmethod #静态方法
        def staticmd():
                print("我是静态方法")
 
MyClass.staticmd();
c=MyClass();
c.staticmd();

运行结果:
我是静态方法
我是静态方法

静态方法应该就是一个宏定义的函数,不需要类或者对象参数传入,每个对象都可以调用,可当作一个人介绍自己时候所说的“我是”,大家都这么说,也不需要带参数

类方法

类方法是Python的一个新概念。类方法具有如下特性:

(1)与静态方法一样,类方法可以使用类名调用类方法。

(2)与静态方法一样,类成员方法也无法访问实例变量,但可以访问类的静态变量。

(3)类方法需传入代表本类的cls参数。

使用装饰符@staticmethod定义类方法

class 类名:
    @classmethod
    def 类方法名(cls):
        方法体

例如:

class MyClass: #定义类
        val1 = 'String 1' #静态变量
        def __init__(self):
             self.val2 = 'Value 2'
        @ classmethod #类方法
        def classmd(cls):
                print('类:' + str(cls) + ',val1:' + cls.val1 + ',无法访问val2的值')
MyClass.classmd();
c=MyClass();
c.classmd();

运行结果:
类:<class '__main__.MyClass'>,val1:String 1,无法访问val2的值
类:<class '__main__.MyClass'>,val1:String 1,无法访问val2的值
个人理解:类方法传入的参数是类,所以他不会改变值,静态方法无法访问类的属性。

img

img

实例方法(普通方法)——————————————————————随着实例属性的改变而改变

类方法(无论是类调用还是实例调用)———————————————都是类属性的值,不随实例属性的变化而变化

静态方法————————————————————————————不可以访问类属性,故直接输出传入方法的值

参考链接:别人的博客

使用instance()函数判断对象类型

使用instance()函数可以用来检测一个给定的对象是否属于(继承于)某个类或类型,如果是则返回True;否则返回False。其使用方法如下:

isinstance(对象名, 类名或类型名)

如果对象名属于指定的类名或类型名,则instance()函数返回True,否则返回False

类的继承和多态

继承和多态是面向对象程序设计思想的重要机制。类可以继承其他类的内容,包括成员变量和成员函数。而从同一个类中继承得到的子类也具有多态性,即相同的函数名在不同子类中有不同的实现。就如同子女会从父母那里继承到人类共有的特性,而子女也具有自己的特性。

可以在定义类时指定其父类。例如,存在一个类A,定义代码如下:
class A {
  def __init__(self, propertyA):#构造函数
  self. propertyA = property #类A的成员变量
  def functionA(): # 类A的成员函
}
从类A派生一个类B,代码如下:
class B (A) {
  propertyB; # 类B的成员变量
  def functionB(): # 类B的成员函数
}

从类B中可以访问到类A中的成员变量和成员函数

一个很好的示例:

import time 
class Users:
        username =""
        def __init__(self, uname):
                self.username = uname
                print('(构造函数:'+self.username+')')
    #显示用户名
        def dispUserName(self):
                print(self.username);
class UserLogin(Users):
    def __init__(self, uname, lastLoginTime):
        Users.__init__(self, uname) #调用父类Users的构造函数
        self.lastLoginTime = lastLoginTime
    def dispLoginTime (self):
        print(" 登录时间为:" + self.lastLoginTime);
#获取当前时间
now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
# 声明3个对象
myUser_1 = UserLogin('admin', now);
myUser_2 = UserLogin('lee', now);
myUser_3 = UserLogin('zhang', now);
#  分别调用父类和子类的函数
myUser_1.dispUserName();
myUser_1.dispLoginTime();
myUser_2.dispUserName();
myUser_2.dispLoginTime();
myUser_3.dispUserName();
myUser_3.dispLoginTime();

运行结果:
(构造函数:admin)
(构造函数:lee)
(构造函数:zhang)
admin
登录时间为:2020-04-06 00:58:56
lee
登录时间为:2020-04-06 00:58:56
zhang
登录时间为:2020-04-06 00:58:56

简单来讲:在声明对象的时候,运行了Userlongin的构造函数,而Userlongin的构造函数又调用了父类的构造函数,所以会有(构造函数:admin)的提示,这也证明了子类可调用父类的函数和参数.

抽象类和多态

使用面向对象程序设计思想可以通过对类的继承实现应用程序的层次化设计。类的继承关系是树状的,从一个根类中可以派生出多个子类,而子类还可以派生出其他子类,以此类推。每个子类都可以从父类中继承成员变量和成员函数,实际上相当于继承了一套程序设计框架。

Python可以实现抽象类的概念。抽象类是包含抽象方法的类,而抽象方法不包含任何实现的代码,只能在其子类中实现抽象函数的代码。例如,在绘制各种图形时,都可以指定绘图使用的颜色($Color变量),也需要包含一个绘制动作(Draw()方法)。而在绘制不同图形时,还需要指定一些特殊的属性,例如在画线时需要指定起点和终点的坐标,在画圆时需要指定圆心和半径等。可以定义一个抽象类Shape,包含所有绘图类所包含的Color变量和Draw()方法;分别定义画线类MyLine和画圆类MyCircle,具体实现Draw()方法。

定义抽象类

Python通过类库abc实现抽象类,因此在定义抽象类之前需要从类库abc导入ABCMeta类和abstractmethod类。

方法如下:

from abc import ABCMeta, abstractmethod

ABCMeta是 Metaclass for defining Abstract Base Classes的缩写,也就是抽象基类的元类。所谓元类就是创建类的类。在定义抽象类时只需要在类定义中增加如下代码:

metaclass = ABCMeta

即指定该类的元类是ABCMeta。例如:

class myabc(object):
    metaclass = ABCMeta

在抽象类里面可以定义抽象方法。定义抽象方法时需要在前面加上下面的代码:

@abstractmethod

因为抽象方法不包含任何实现的代码,所以其函数体通常使用pass。例如,在抽象类myabc中定义一个抽象方法abcmethod(),代码如下:

class myabc(object):
    metaclass = ABCMeta
    @abstractmethod
    def abcmethod (self):pass

看不懂,一般用不上,不用看

实现抽象类

不懂,可百度

多态

所谓多态,指抽象类中定义的一个方法,可以在其子类中重新实现,不同子类中的实现方法也不相同。

class Shape(object):
    __metaclass__ = ABCMeta
      def __init__(self):
   self.color= 'black' #默认使用黑色
@abstractmethod
   def draw(self):pass
class circle (Shape):#创建类Shape的子类circle
    def __init__(self, x, y, r): #定义圆心坐标和半径
        self.x = x
        self.y = y
        self.r = r
    def draw(self):
        print("Draw Circle: (%d, %d, %d)"  %(self.x, self.y, self.r))
class line (Shape):#再从类Shape中派生出画直线的类line
    def __init__(self, x1, y1, x2, y2): #定义起止坐标值
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
    def draw(self):
        print("Draw Line: (%d, %d, %d, %d)"  %(self.x1, self.y1, self.x2, self.y2))
}

定义一个类circle的对象c,然后调用draw()方法,代码如下:

c = circle(10,10, 5)

c.draw()

定义一个类line的对象l,然后调用draw()函数,代码如下:

l = line(10,10, 20, 20)

l.draw()

输出结果如下:

Draw Circle: (10, 10, 5)

Draw Line: (10, 10, 20, 20)


终于到做题环节了!!!

  1. 对任意十个数进行排序

这个太简单了!排序有很多方法,但是首先,python不像C语言,最开始要解决的是输入问题,最简单的就是一个一个输入,但是我觉得太麻烦了,所以我百度了资料:

list1 = []
list1 = input().split()

input().split()该代码就是输出,以空格分块,若input().split(',')则是以逗号分块,但是!这样输入得到的是字符型列表,我一开始是想用eval,但是会报错,然后看到了:map!

list1 =list(map(int,input().split()))

我也不知道为啥这么用,记住就行,本来我要用list存放变量,但是list和list冲突,所以改成list1

补充split( ):

语法:str.split(str = ' ',num)[n]
  其中str:分隔符,默认是空格
   num:分割次数,会得到num+1个子串
   [n]:选取第n个(从0开始)

map:

简单来说,
map()它接收一个函数 f 和一个 可迭代对象(这里理解成 list),并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。
例如,对于list [1, 2, 3, 4, 5, 6, 7, 8, 9]

如果希望把list的每个元素都作平方,就可以用map()函数:

因此,我们只需要传入函数f(x)=x*x,就可以利用map()函数完成这个计算:

def f(x):
    return x*x
print(list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
输出结果:
[1, 4, 9, 10, 25, 36, 49, 64, 81]

最后的总代码:

list1=[]
list1=list(map(int,input('请输入十个数进行排序').split()))#list1 用来存放十个数
list1.sort()
print(list1,end=' ')

排序方法有很多,这里我选择直接调用排序函数.

运行结果
请输入十个数进行排序1 5 10 3 96 1 894 89 65 1000
[1, 1, 3, 5, 10, 65, 89, 96, 894, 1000]

然后送上几个排序:

快速排序:

# quicksort
import random
def quicksort(seq):
    if len(seq) < 2:
        return seq
    else:
        base = seq[0]
        left = [elem for elem in seq[1:] if elem < base]
        right = [elem for elem in seq[1:] if elem > base]
        return quicksort(left) + [base] + quicksort(right)
seq = [9, 8, 7, 6, 5, 4, 3]
random.shuffle(seq)
# seq:[6, 4, 9, 3, 8, 5, 7]
print(quicksort(seq))
# 输出:[3, 4, 5, 6, 7, 8, 9]

冒泡排序:

def bouble_sort(sequence):
    seq = sequence[:]
    length = len(seq) - 1
    i = j = 0
    flag = 1
    while i < length:
        j = 0
        while j < length - i:
            if seq[j] > seq[j + 1]:
                seq[j], seq[j + 1] = seq[j + 1], seq[j]
                flag = 0
            j += 1
        if flag:
            break
        i += 1
    return seq

选择排序

def find_minimal_index(seq):
    min_elem = seq[0]
    count = 0
    min_elem_index = count
    for elem in seq[1:]:
        count += 1
        if elem < min_elem:
            elem, min_elem = min_elem, elem
            min_elem_index = count
    return min_elem_index


def select_sort(sequence):
    # 选择排序
    seq = sequence[:]
    length = len(seq)
    for i in range(length):
        index = find_minimal_index(seq[i:])
        seq[index + i], seq[i] = seq[i], seq[index + i]
    return seq
  1. 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。

先看代码:

s =input('请输入字符串:')
dic={'字母':0,'数字':0,'空格':0,'其他':0}
for i in s:
    if i >'a' and i<'z' or i>'A' and i<'Z' :
        dic['字母'] +=1
    elif i in '0123456789':
        dic['数字'] +=1
    elif i ==' ':
        dic['空格'] +=1
    else:
        dic['其他'] +=1
         
print('统计字符串:',s)
print(dic)

利用s储存字符串,然后利用字典储存字符串的每种字符出现的次数, for i in s:就是从字符串中每个字符单独取出来对比,其实还有别的 方法:

一、isdigit()

S.isdigit()返回的是布尔值:True False
S中至少有一个字符且如果S中的所有字符都是数字,那么返回结果就是True;否则,就返回False

二、isalpha()

S.isalpha()返回的是布尔值:True False
S中至少有一个字符且如果S中的所有字符都是字母,那么返回结果就是True;否则,就返回False

三、isalnum()

S.isalnum()返回的是布尔值:True False
S中至少有一个字符且如果S中的所有字符都是字母数字,那么返回结果就是True;否则,就返回False

四、isspace()

S.isspace()返回的是布尔值:True False
S中至少有一个字符且如果S中的所有字符都是空格,那么返回结果就是True;否则,就返回False

该方法参考代码:

tmpStr = input('请输入字符串:')
alphaNum=0
numbers=0
spaceNum=0
otherNum=0
for i in tmpStr:
    if i.isalpha():
        alphaNum +=1
    elif i.isnumeric():
        numbers +=1
    elif i.isspace():
        spaceNum +=1
    else:
        otherNum +=1
print('字母=%d'%alphaNum)
print('数字=%d'%numbers)
print('空格=%d'%spaceNum)
print('其他=%d'%otherNum)

该弄完的都弄完了,没人看就算了.

最后有一个东西是今天要弄的:关于类中self的用法