[ python ] 初始面向对象

首先,经过以前学习的函数编写一个 人狗大战 的例子。python

分析下这个需求,人 狗 大战  三个事情。
角色:人、狗
动做:狗咬人,人打狗编程

 

先建立人和狗两个角色:bash

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    return data


kk = person('kk', 100, 5, 'male')    # 人的角色
gg = dog('gg', 100, 10, 'teddy')    # 狗的角色
人和狗两个角色

 

 

人建立完成,可是咱们还有两个动做才能开始游戏,因而使用函数在写两个动做:ide

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    return data


kk = person('', 100, 5, 'male')
gg = dog('狗狗', 100, 10, 'teddy')



def bite(g, p):
    p['hp'] -= g['aggr']
    print('%s 被咬,掉了%s 的血。' %(p['name'], g['aggr']))

bite(gg, kk)

def hit(p, g):
    g['hp'] -= p['aggr']
    print('%s 被打,掉了%s 的血。' %(g['name'], p['aggr']))

hit(kk, gg)
两个动做

 

 

上面的代码已经实现了咱们最初设计的人狗大战,可是每一个函数都是相互独立的,没有任何限制。也就是说,能够出现如下这种状况:函数

hit(gg, kk)
bite(kk, gg)

执行结果:

人 被打,掉了10 的血。
狗狗 被咬,掉了5 的血。

 

 

这样,人和狗正好相反了,应该是人打狗,狗咬人才对。所以必需要加上限制:学习

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    def hit(g):
        g['hp'] -= data['aggr']
        print('%s 被打,掉了%s 的血。' % (g['name'], data['aggr']))

    data['hit'] = hit
    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    def bite(p):
        p['hp'] -= data['aggr']
        print('%s 被咬,掉了%s 的血。' % (p['name'], data['aggr']))

    data['bite'] = bite
    return data


kk = person('', 100, 5, 'male')
gg = dog('狗狗', 100, 10, 'teddy')

kk['hit'](gg)
gg['bite'](kk)
为角色的动做加上限制

 

 

这样,咱们在代码层面就实现了限制,代码基本完美了。spa

 

回看咱们上面的代码,建立的是角色函数,也就是经过角色函数,咱们能够建立无数的人和狗大战。设计

人是人类、狗是狗类 经过这样的思想来进行编程就是面向对象的编程思想。从角色和大类入手,上帝视角

好比:
人类,是一个大类,这个大类里面有各类各样的属性,好比吃饭,睡觉,打豆豆这都是共性。
类中还有方法,方法就是一个过程,一个动做,作某件事。
好比:登山、打篮球。这些都是动做,都应该是一个方法出现;3d

 

面向过程与面向对象

面向过程的程序设计核心是过程。过程即解决问题的步骤,面向过程的设计就比如精心设计好一条流水线。

优势:极大的下降了写程序的复杂度,只须要顺着要执行的步骤,堆叠代码便可;
缺点:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。

应用场景:通常 bash 脚本都是面向过程思想写出来的,处理流程化事件。


面向对象的程序设计

面向对象的程序设计的核心是对象。

优势:解决了程序的扩展性。对某一个对象单独修改,会马上反映到整个体系中,如对游戏中一我的物参数的特征和技能修改都很容易。
缺点:可控性差,没法像面向过程的程序设计流水线式的能够很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间交互解决问题。

应用场景:需求常常变化的软件,通常需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的地方;

在python中面向对象的程序设计并非所有。

面向对象编程可使程序的维护和扩展变得更简单,而且能够大大提升程序开发效率,基于面向对象的程序可使它人更加容易理解你的代码逻辑。
虽然 面向对象很好用,可是它并无比面向过程高级,对于不一样的应用需求场景采用合适的编程思想才是最重要的。code

 

def functionName(args):
    函数体
申明函数
class Data:
    pass
申明类

 

 

类有两种做用:属性引用和实例化

属性引用(类名.属性)

class Person:
    role = 'person'
    
    def walk(self):
        print('person is walking...')

 上面代码中 role 是 Person的一个属性,walk 是 Person的方法。

 

print(Person.role)  # 查看人的role属性
print(Person.walk)  # 引用人的走路方法,注意,这里不是在调用

 

 

实例化:类名加括号就是实例化,会自动触发 __init__ 函数的运行,能够用它来为每一个实例定制本身的特征

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


p = Person('hkey')  # 实例化 Person
print(p.name)

# 执行结果:
# hkey


p = Person('hkey') 就是一个实例化的过程,实例化会自动执行 __init__()方法。

 

 

关于 self

self: 在实例化时自动将对象/实例自己传给__init__的第一个参数
class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        print(id(self))
        
        
p = Person('hkey', 20, 'male')  # 实例化 Person
print(id(p))

# 执行结果:
# 2074449353472
# 2074449353472

经过上面的代码,咱们能够查看到 self 和 对象 p 内存空间地址是一致的,印证了上面这句话。

如何查看一个类有哪些属性和方法,可使用__dict__方法

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


print(Person.__dict__)
p = Person('hkey', 20, 'male')  # 实例化 Person
print(p.__dict__)

 

 

对象的相关知识

对象是关于类而实际存在的一个例子,即实例
对象/实例只有一种做用:属性引用

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

p = Person('hkey', 20, 'male')  # 这一步就是实例化一个对象p



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


p = Person('hkey', 20, 'male')  # 实例化 Person

print('name:', p.name)
print('age:', p.age)
print('sex:', p.sex)
print('walk:', p.walk)    # 在类中,方法也是对象。

# 执行结果:

# name: hkey
# age: 20
# sex: male
# walk: <bound method Person.walk of <__main__.Person object at 0x0000024A4E819400>>
对象的使用

 

 

这里,咱们把以前人狗大战的例子经过面向对象来重写下:

class Person(object):
    def __init__(self, name, hp, aggr, job):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.job = job

    def hit(self, gg):
        gg.hp -= self.aggr
        print('\033[31;1m%s被打,掉了%s的血。\033[0m' % (gg.name, self.aggr))


class Dog(object):
    def __init__(self, name, hp, aggr, kind):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.kind = kind

    def bite(self, p):
        p.hp -= self.aggr
        print('\033[31;1m%s被咬,掉了%s的血。\033[0m' % (p.name, self.aggr))


p = Person('kk', 100, 2, 'it')
teddy = Dog('teddy', 100, 3, 'teddy')

p.hit(teddy)
print(teddy.hp)

teddy.bite(p)
print(p.hp)
人狗大战

 

 

能够分析下上面的代码。
1. 咱们建立两个类,一我的类,一个狗类
2. 经过实例化,咱们建立了两个对象, p 和 teddy
3. 经过p.hit 调用人类的方法时,参数为狗类的对象,这里就是用到了对象的交互。
4. 经过teddy.bite 调用狗类的方法时,参数为人类的对象, 这里就是用到了对象的交互。

 

因此说,面向对象程序一旦开始就由对象之间的交互解决问题。

 

实例化:
    对象 = 类名(参数是__init__方法的参数)

实例 = 对象 彻底没区别

对象查看属性:
    对象.属性名
    
对象调用方法:
    对象.方法名(参数)

 

练习:正方形的周长和面积

class Squ:
    def __init__(self, length):
        self.length = length

    def per(self):
        return self.length * 4

    def area(self):
        return self.length ** 2


cfx = Squ(20)
print(cfx.per())
print(cfx.area())
正方形的周长和面积

 

 

类命名空间与对象、实例的命名空间

建立一个类就会建立一个类的名称空间用来存储类中定义的全部名字,这些名字称为类的属性

而类有两种属性:静态属性和动态属性

  •     静态属性就是直接在类中定义的变量
  •     动态属性就是定义在类中的方法

 

class Person:
    language = 'Chinese'
    
    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job

hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

 

 

上面的代码中有一个类,实例化出两个对象 hkey 和 jay, 以下图:

 

1. 对象是经过类实例化出来的;
2. 对象和类是单向联系,也就是说,经过对象可以找到类,可是经过类是没法寻找到对象的;
3. 对象共享类中的属性和方法,可是两者之间是相互独立的内存空间

 

class Person:
    language = 'Chinese'

    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job


hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

print(Person.language)    # 经过类调用静态属性
print(hkey.language)    # 经过对象 hkey 调用静态属性
print(jay.language)        # 经过对象 jay 调用静态属性

# 执行结果:
# Chinese
# Chinese
# Chinese

 

 

1. 经过类名调用静态属性,由于静态属性就在类的命名空间中,直接就能够取出使用;
2. 经过对象调用静态属性,首先对象会先在本身的命名空间中寻找 language 属性,若是没有会在类中去寻找 language 类中有则返回
3. 当对象自定义和类中静态属性同样的名称时,对象再次调用时,由于本身命名空间中已经存在,则直接返回。

class Person:
    language = 'Chinese'

    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job


hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

print(Person.language)
hkey.language = 'English'
print(hkey.language)
print(jay.language)

# 执行结果:
# Chinese
# English
# Chinese

 

 

因此,在使用类中静态属性的时候,最好使用 类名.静态属性 调用

 

类中静态属性使用的经典例子:

要求:建立一个类,每次实例化一个对象就记录下来。

class Count:
    count = 0
    def __init__(self):
        Count.count += 1
a = Count()
b = Count()
print(a.count)
记录每次实例化
相关文章
相关标签/搜索