面向对象 | 初识

一、面向对象编程

类 : 具有相同属性和技能的一类事物

对象 就是对一个类的具体的描述

实例化:类——>对象的过程

 

使用面向对象的好处:

  1. 使得代码之间的角色关系更加明确
  2. 增强了代码的可扩展性
  3. 规范了对象的属性和技能

结构上面向对象可以分为两部分:属性和方法

  属性又叫静态属性、静态字段、静态变量

  方法又叫动态属性、函数

class A:
    name = 'hello'          #静态属性、静态字段、静态变量
    def fun(self):          #动态属性、方法、函数
        pass

新建一个类,类名的首字母最好是大写的,规范一点,否则Pycharm有波浪号

1. 类属性

类的属性有两种方式查看

  dir(类名):查出的是一个名字列表

  类名.__dict__:查出的是一个字典,key为属性名,value为属性值

class Person:
    静态变量 = 123

print(Person.__dict__) #内置的双下划线方法 

执行输出:
{'__doc__': None, '静态变量': 123, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Person' objects>,     '__dict__': <attribute '__dict__' of 'Person' objects>}

从结果中,可以找到 '静态变量': 123

特殊的类属性

类名.__name__       # 类的名字(字符串)
类名.__doc__        # 类的文档字符串
类名.__base__       # 类的第一个父类(在讲继承时会讲)
类名.__bases__       # 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__       # 类的字典属性
类名.__module__      # 类定义所在的模块
类名.__class__      # 实例对应的类(仅新式类中)

2. 引用静态变量

类名.__dict__['静态变量名']    可以查看,但是不能删改
类名.静态变量名               直接就可以访问,可以删改
del 类名.静态变量名           删除一个静态变量

3. 引用动态变量

类名.方法名         查看这个方法的内存地址
类名.方法名(实参)       调用了这个方法,必须传一个实参,这个实参传给了self
class Person:
    静态变量 = 123         #静态属性,静态变量
    role = 'person'
    def f1(self):             #默认带一个参数self,方法,动态属性
        print(1234567)

#引用动态变量
Person.f1()         # 执行报错:TypeError: f1() missing 1 required positional argument: 'self' # 提示缺少一个参数self

随便传一个参数,再次执行
Person.f1(1) 

只要是类的方法,必须要传selfself的名字,是约定俗成

二、面象对象  VS  函数(方法)

产生一个实例(对象)的过程:对象 = 类名()

 实例化对象的过程有几步:

  1. 实例化对象在内存中产生一个对象空间(内存地址)。
  2. 自动执行 __init__方法,将对象空间传给了self参数。
  3. 在 __init__方法中,给对象空间封装一些静态属性。

1. __init__方法

初始化方法,功能就是给对象self封装属性

class Person:
    role = 'person' #静态属性
    def __init__(self,name,sex,hp,ad):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.ad = ad

summer = Person('summer','M',1,5)
print(summer.__dict__)

广义上的属性,是指对象的属性

2. 类里面的方法

  在类里面的def 一般叫方法。没有顺序之分,一般把init放到第一个.

class Person:
    role = 'person' #静态属性
    def __init__(self,name,sex,hp,ad):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.ad = ad

    def attack(self):
        print('{}发起了一次攻击'.format(self.name))


summer = Person('ss','M',1,5)
# 执行类方法,下面2种方法效果等同
Person.attack(summer)               # attack是和Person关联起来的,所以外部可以直接调用attack方法
summer.attack()


'''
执行输出:
ss发起了一次攻击
ss发起了一次攻击
'''

方法的调用 :

  1.类名.方法名(对象名)              方法中的self参数就指向这个对象

  2.对象名.方法名()                  这样写相当于方法中的self参数直接指向这个对象,推荐使用

 

、类名、对象的使用

1. 从类名的角度研究类

① 查看类中所有的属性和方法__dict__。虽然__dict__也能查看类中某一个属性,但是通常用来查看类中的所有属性和方法,不做其他用途

② 增删改查类中的属性:用万能的点(类中没有该属性就增,有该属性就改)

③ 操作类中的方法:一般不通过类名(一般通过对象名

 

类名操作静态属性

(1)查看类中的所有内容:类名.__dict__方式

class Human:
    mind = '有思想'              # 第一部分:静态属性 属性 静态变量 静态字段
    dic = {}
    l1 = []

    def work(self):                 # 第二部分:方法 函数 动态属性
        print('人类会工作')

print(Human.__dict__)
print(Human.__dict__['mind'])
Human.__dict__['mind'] = '无脑'           # 报错

通过.__dict__这种方式只能查询,不能增删改.第一种方式只用户查询全部内容(一般不用单独属性查询).

(2)通过万能的点 可以增删改查类中的单个属性

class Human:
    mind = '有思想'

    def work(self):  # 第二部分:方法 函数 动态属性
        print('人类会工作')

Human.walk = '直立行走'       #
del Human.mind               #
Human.mind = '无脑'          #
print(Human.mind)           #

对以上两种做一个总结:

  • 如果想查询类中的所有内容,通过__dict__方法;
  • 如果只是操作单个属性则用万能的点的方式。

类名操作动态方法

  除了两个特殊方法:静态方法,类方法之外,一般不会通过类名操作一个类中的方法。

class Human:
    mind = '有思想'              # 第一部分:静态属性 属性 静态变量 静态字段

    def work(self):                 # 第二部分:方法 函数 动态属性
        print('人类会工作')

    def tools(self):
        print('人类会使用工具')

Human.work(111)
Human.tools(111)

# 下面可以做,但不用。
Human.__dict__['work'](111)

2. 从对象的角度研究类

实例化一个对象总共发生了三件事:

  • 在内存中开辟了一个对象空间。
  • 自动执行类的__init__方法,并将这个对象空间(内存地址)传给__init__方法的第一个位置参数self。
  • 在__init__ 方法中通过self给对象空间添加属性。

对象操作对象空间

  • 对象查看对象空间的所有属性__dict__
  • 对象操作对象的某个属性,增删改查,用万用的点(对象中没有该属性就增,有该属性就减)
  • 对象操作类空间的属性,只能查
  • 对象操作类空间的方法:万能的点

(1)对象查询对象中所有属性    对象.__dict__

class Human:
    mind = '有思想'
    language = '实用语言'

    def __init__(self,name,sex,age,hobby):
        # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby

obj = Human('barry','',18,'运动')
print(obj.__dict__)              # {'n': 'barry', 'h': '运动', 's': '男', 'a': 18}

(2)对象操作对象中的单个属性  万能的点 .

class Human:

    mind = '有思想'
    language = '实用语言'
    def __init__(self,name,sex,age,hobby):
        # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby

obj = Human('barry','',18,'运动')
obj.job = 'IT'                #
del obj.n                    #
obj.s = ''                  #
print(obj.s)                 #

(3)对象查看类中的属性

class Human:

    mind = '有思想'
    language = '实用语言'
    def __init__(self,name,sex,age,hobby):
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby

obj = Human('barry','',18,'运动')
print(obj.mind)                         # 有思想
print(obj.language)                     # 实用语言

(4)对象操作类中的方法

class Human:
    mind = '有思想'
    language = '实用语言'

    def __init__(self,name,sex,age,hobby):
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby

    def work(self):
        print(self)
        print('人类会工作')

    def tools(self):
        print('人类会使用工具')

obj = Human('barry','',18,'运动')
obj.work()
obj.tools()

'''
执行输出:
<__main__.Human object at 0x000001576C1808C8>
人类会工作
人类会使用工具
'''

一个类可以实例化多个对象

class Human:
    mind = '有思想'
    language = '实用语言'

    def __init__(self,name,sex,age,hobby):
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby

    def work(self):
        print(self)
        print('人类会工作')

    def tools(self):
        print('人类会使用工具')

obj1= Human('李易峰','',20,'拍戏')
obj2= Human('赵丽颖','',18,'唱歌')
print(obj1,obj2)
print(obj1.__dict__)
print(obj2.__dict__)

'''
执行输出:
<__main__.Human object at 0x00000223534C0D88> <__main__.Human object at 0x00000223534C68C8>
{'n': '李易峰', 's': '男', 'a': 20, 'h': '拍戏'}
{'n': '赵丽颖', 's': '女', 'a': 18, 'h': '唱歌'}
'''

练习:在终端输出如下信息

小明,10岁,男,上山去砍柴
小明,10岁,男,开车去东北
小明,10岁,男,最爱大保健
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去东北
老李,90岁,男,最爱大保健
老张…

class Person(object):
    def __init__(self, name, age, sex='', hobby=('上山去砍柴', '开车去东北', '最爱大保健')):
        self.name = name
        self.age = age
        self.sex = sex
        self.hobby = hobby
 
    def info(self):
        for i in self.hobby:
            print('{},{}岁,{},{}'.format(self.name, self.age, self.sex, i))
 
 
ming = Person('小明', 10)
li = Person('老李', 90)
ming.info()
li.info()

扩展题:使用面向对象的方式编码三级菜单

将之前的代码复制粘贴过来,切割成面向对象方式

# -*- coding: utf-8 -*-
class AreaMenu(object):
    def __init__(self):
        self.zone = {
            '山东': {
                '青岛': ['四方', '黄岛', '崂山', '李沧', '城阳'],
                '济南': ['历城', '槐荫', '高新', '长青', '章丘'],
                '烟台': ['龙口', '莱山', '牟平', '蓬莱', '招远']
            },
            '江苏': {
                '苏州': ['沧浪', '相城', '平江', '吴中', '昆山'],
                '南京': ['白下', '秦淮', '浦口', '栖霞', '江宁'],
                '无锡': ['崇安', '南长', '北塘', '锡山', '江阴']
            },
            '浙江': {
                '杭州': ['西湖', '江干', '下城', '上城', '滨江'],
                '宁波': ['海曙', '江东', '江北', '镇海', '余姚'],
                '温州': ['鹿城', '龙湾', '乐清', '瑞安', '永嘉']
            }
        }
        self.province = list(self.zone.keys())
        self.run()

    def run(self):  # 省列表
        while True:
            print(''.center(20, '*'))

            for i in self.province:  # 打印省列表
                print('{}\t{}'.format(self.province.index(i) + 1, i))

            province_input = input('请输入省编号,或输入q/Q退出:').strip()

            if province_input.isdigit():
                province_input = int(province_input)

                if 0 < province_input <= len(self.province):
                    province_id = province_input - 1  # 省编号,由于显示加1,获取的时候,需要减1
                    city = list(self.zone[self.province[province_id]].keys())  # 城市列表
                    self.city(province_id, city)  # 进入市区列表

                else:
                    print("\033[41;1m省编号 {} 不存在!\033[0m".format(province_input))

            elif province_input.upper() == 'Q':
                break

            else:
                print("\033[41;1m输入省编号非法!\033[0m")

    def city(self, province_id, city):  # 市区列表
        if province_id == '' or city == '':
            return 'province_id 和 city 参数不能为空'

        while True:
            print(''.center(20, '*'))
            for j in city:
                print('{}\t{}'.format(city.index(j) + 1, j))

            city_input = input("请输入市编号,或输入b(back)返回上级菜单,或输入q(quit)退出:").strip()

            if city_input.isdigit():
                city_input = int(city_input)
                if 0 < city_input <= len(city):
                    city_id = city_input - 1  # 市编号,由于显示加1,获取的时候,需要减1
                    county = self.zone[self.province[province_id]][city[city_id]]  # 县列表
                    self.county(county)  # 进入县列表

                else:
                    print("\033[41;1m市编号 {} 不存在!\033[0m".format(city_input))
            elif city_input.upper() == 'B':
                break
            elif city_input.upper() == 'Q':
                exit()  # 由于在多层while循环里面,直接exit退出即可

            else:
                print("\033[41;1m输入市编号非法!\033[0m")

    def county(self, county):  # 县列表
        if county == '':
            return 'county 参数不能为空'

        while True:
            print(''.center(20, '*'))
            for k in county:
                print('{}\t{}'.format(county.index(k) + 1, k))
            # 到县这一级,不能输入编号了,直接提示返回菜单或者退出
            county_input = input("输入b(back)返回上级菜单,或输入q(quit)退出:").strip()
            if county_input == 'b':
                # 终止此层while循环,跳转到上一层While
                break
            elif county_input == 'q':
                # 结束程序
                exit()
            else:
                print("\033[41;1m已经到底线了,请返回或者退出!\033[0m")


if __name__ == '__main__':
    AreaMenu()

 执行输出:

猜你喜欢

转载自www.cnblogs.com/Summer-skr--blog/p/11801360.html