面向对象(进阶)

Posted rixian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象(进阶)相关的知识,希望对你有一定的参考价值。

一.关于上篇面向对象(初识)总结:

1.面向对象是一种编程方式,此编程方式的实现是基于对对象的使用

2.类:是一个模板,模板中包装了多个"函数"供使用(可以讲多个函数中公用的变量封装到对象中)

3.对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数

4.面向对象三大特性:封装,继承和多态

(1).封装:

  归类,将函数放置到一个类中

  打包,将数据打包放到一个对象中

(2).继承:

  在子类中调用父类中的方法

  Python支持多继承

(3).多态:

  Python原生支持多态,崇尚鸭子模型,由于Python函数传参时,无序指定类型:

  def func(arg): # arg可以是多种类型,只要其中有send方法即可

    arg.send

5.编写面向对象程序:归类+提取公共值

6.self到底是谁?

  self参数是Python帮助我们自动传递

  如果执行面向对象中的方法时,前面必须有一个对象:xxx.func()

技术分享图片
class Foo:
    def f1(self):
        pass
        
    def f2(self):
        self.f1()
        
obj = Foo()
obj.f2()
示例
技术分享图片
class User:
    def __init__(self,name,pwd):
        self.name = name
        self.pwd = pwd

class Account:
    def __init__(self):
        self.user_list = []

    def login(self):
        name = input(请输入账号:)
        pwd = input(请输入密码:)
        flag = False
        for user in self.user_list:
            if name == user.name and pwd == user.pwd:
                flag = True
                break
        if flag:
            print(登录成功)
        else:
            print(登录失败)


    def register(self):
        i = 0
        while i<3:
            i+=1
            name = input(请输入用户名:)
            pwd = input(请设置密码:)
            usr = User(name,pwd)
            self.user_list.append(usr)

    def run(self):
        self.register()
        self.login()

if __name__==__main__:
    obj = Account()
    obj.run()
例题

二.类的成员

类的成员可以分为三大类:字段.方法和属性

技术分享图片

注:所有成员中,只有普通字段的内容保存到对象中,即:根据此类创建了多少对象,在内

存中就有多少个普通字段,而其他的成员,则都是保存在类中,即:无论对象的多少,在内

存中只创建一份.

技术分享图片
class User:
    def __init__(self, user, pwd, email):
        self.user = user
        self.pwd = pwd
        self.email = email

user_list = []

# obj = User(‘wahaha‘,‘123‘,‘[email protected]‘)
obj = {user:wahaha,pwd:123,email:[email protected]} # dict({‘user‘:‘wahaha‘,‘pwd‘:123,‘email‘:‘[email protected]‘})
user_list.append(obj)

# obj = User(‘wahaha‘,‘123‘,‘[email protected]‘)
obj = {user:wahaha,pwd:123,email:[email protected]}
user_list.append(obj)

# obj = User(‘wahaha‘,‘123‘,‘[email protected]‘)
obj = {user:wahaha,pwd:123,email:[email protected]}
user_list.append(obj)


for row in user_list:
    # print(row.user,row.pwd,row.email)
    print(row[user],row[pwd],row[emailr])
字典也是类
技术分享图片
class Foo:

    # 方法
    def __init__(self,name):
        # 实例变量/字段
        self.name = name

    # 方法
    def func(self):
        pass

# obj,Foo类的对象
# obj,Foo类的实例
obj = Foo(娃哈哈)
类的成员

 1.字段:

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存

中保存的位置不同

(1).普通字段属于对象

(2).静态字段属于类

技术分享图片
class Foo:
    # 类变量(静态字段)
    country = "中国"

    def __init__(self, name):
        # 实例变量(普通字段)
        self.name = name

    def func(self):
        pass

# 知识点一:
"""
# 准则:
# 实例变量(普通字段)访问时,使用对象访问,即: obj1.name
# 类变量(静态字段)访问时,使用类方法,即: Foo.country  (实在不方便时,才使用对象)

obj1 = Foo(‘朴树‘)
obj2 = Foo(‘高晓松‘)
print(obj1.name)    #直接访问普通字段
print(Foo.country) # obj1.country,直接访问静态字段
"""

# 知识点一:易错点
"""
obj1 = Foo(‘朴树‘)
obj2 = Foo(‘高晓松‘)

# 练习1
# obj1.name = ‘娃哈哈‘
# print(obj1.name) # 娃哈哈
# print(obj2.name) # 高晓松

# 练习2
# obj1.country = ‘美国‘
# print(obj1.country) # 美国
# print(obj2.country) # 中国

# 练习3
# Foo.country = ‘美国‘
# print(obj1.country) # 美国
# print(obj2.country) # 美国
"""

# 知识点一: 什么时候用类变量?
# 当所有对象中有共同的字段时且要改都改要删都删时,可以将实例变量(字段)提取到类变量(静态字段)
字段的定义和使用

由上述代码可以看出[普通字段需要通过对象来访问][静态对象通过类访问],在使用上

可以看出普通字段和静态字段的归属是不同的,其在内存中的存储方式如下图:

技术分享图片

由上图可知:

·静态字段在内存中只保存一份

·普通字段在每个对象中都要保存一份

应用场景:通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静

态字段

(3).字段成员修饰符

变量:

  实例变量(普通字段)

    公有实例变量(字段)

    私有实例变量(字段)

  类变量(静态字段)

     公有类变量(静态字段)

     私有类变量(静态字段)

技术分享图片
# ######### 公有实例变量(字段) #########
"""
class Foo:

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

    def func(self):
        print(self.name)


obj = Foo(‘娃哈哈‘)
print(obj.name)
print(obj.age)
obj.func()
"""


# ######### 私有实例变量(私有字段) #########
"""
class Foo:

    def __init__(self,name):
        # 私有实例变量(私有字段)
        self.__name = name
        self.age = 123

    def func(self):
        print(self.__name)

obj = Foo(‘娃哈哈‘)
print(obj.age)
#obj.__name # 无法访问
obj.func()  # 找一个内部人:func, 让func帮助你执行内部私有 __name
"""

# ######### 类变量(静态字段) #########
"""
class Foo:
    country = "中国"

    def __init__(self):
        pass

    def func(self):
        # 内部调用
        print(self.country)
        print(Foo.country) # 推荐


# 外部调用
print(Foo.country)

obj = Foo()
obj.func()
"""

# ######### 私有类变量(私有静态字段) #########
"""
class Foo:
    __country = "中国"

    def __init__(self):
        pass

    def func(self):
        # 内部调用
        print(self.__country)
        print(Foo.__country)  # 推荐

# 外部无法调用私有类变量
# print(Foo.country)

obj = Foo()
obj.func()
"""
字段成员修饰符(公/私)

 

 思考:如何验证儿子都不知道私有字段的存在

技术分享图片
# 无法访问
class Base(object):
    __secret = "受贿"

class Foo(Base):

    def func(self):
        print(self.__secret)
        print(Foo.__secret)


obj = Foo()
obj.func()    #报错


# 可以访问:
class Base(object):
    __secret = "受贿"

    def zt(self):    # 找个第三方,帮你查
        print(Base.__secret)


class Foo(Base):

    def func(self):
        print(self.__secret)
        print(Foo.__secret)


obj = Foo()
obj.zt()    # 调用第三方
儿子都不知道

 

 2.方法:

方法包括:普通方法,静态方法,和类方法,三种方法在内存中都归属于类,区别在于

调用的方式不同

(1).普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法

   的对象赋值给self

(2).类方法:由类调用;至少一个cls参数;执行类方法时,自动将调用该方法的类复

   制给cls

(3).静态方法:由类调用;无默认参数;

技术分享图片
class Foo(object):
    def __init__(self, name):
        self.name = name

    # 实例方法
    def func(self):
        print(self.name)
        
obj = Foo(..)
obj.func()
普通方法(实例方法)
技术分享图片
class Foo(object):
    def __init__(self, name):
        self.name = name

    # 静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法
    @staticmethod
    def display(a1,a2):
        return a1 + a2
Foo.display(1,3)
静态方法
技术分享图片
class Foo(object):

    # 类方法,cls是类
    @classmethod
    def show(cls,x1,x2):
        print(cls,x1,x2)

# 执行类方法
Foo.show(1,8)
类方法

 

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份

不同点:方法调用者不同,调用方法时自动传入的参数不同

(4).示例:

技术分享图片
# ######### 没必要写实例方法 #########
class Foo(object):

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

    def func(self):
        print(123)


obj = Foo(娃哈哈)
obj.func()
# ######### 有必要写实例方法 #########

class Foo(object):
    def __init__(self, name):
        self.name = name

    def func(self):
        print(self.name)


obj = Foo(娃哈哈)
obj.func()
普通方法
技术分享图片
# ######### 静态方法 #########
class Foo(object):
    def __init__(self, name):
        self.name = name

    # 实例方法
    def func(self):
        print(self.name)

    # 静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法
    @staticmethod
    def display(a1,a2):
        return a1 + a2

obj = Foo(娃哈哈)
obj.func()

ret = Foo.display(1,3)
print(ret)
静态方法
技术分享图片
总结:

  ①.编写时:

      方法上方写@staticmethod

      方法参数可有可无

  ②.调用时:

      类.方法名()

      对象.方法名()

  ③.什么时写静态方法?

      无需调用对象中已封装的值 
关于静态方法的总结
技术分享图片
# ######### 类方法 #########

class Foo(object):
    def __init__(self, name):
        self.name = name

    # 实例方法,self是对象
    def func(self):
        print(self.name)

    # 静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法
    @staticmethod
    def display(a1,a2):
        return a1 + a2

    # 类方法,cls是类
    @classmethod
    def show(cls,x1,x2):
        print(cls,x1,x2)

# 执行类方法
Foo.show(7,6)
类方法
技术分享图片
 总结:

  ①.定义时:

    方法上方写:@classmethod
    方法的参数:至少有一个cls参数
  ②.执行时:

    类名.方法名()  # 默认会将当期类传到参数中
  ③.什么时候使用?

    如果在方法中会使用到当前类,那么就可以使用类方法
关于类方法的总结

 (5).方法成员的修饰符

技术分享图片
# ######### 私有的实例方法 #########

class Foo(object):


    def __init__(self):
        pass


    def __display(self,arg):
        print(私有方法,arg)

    def func(self):
        self.__display(123)

obj = Foo()
# obj.__display(123) # 无法访问
obj.func()

# ######### 私有的静态方法 #########

class Foo(object):


    def __init__(self):
        pass

    @staticmethod
    def __display(arg):
        print(私有静态 方法,arg)

    def func(self):
        Foo.__display(123)

    @staticmethod
    def get_display():
        Foo.__display(888)

# Foo.__display(123) 报错

obj = Foo()
obj.func()

Foo.get_display()
方法成员的修饰符(公/私)

3.属性(通过方法改造出来)

如果你已经了解了Python类中的方法,那么属性就非常简单了,因为python中的属性其

实是普通方法的变种

技术分享图片
"""
class Foo(object):

    def __init__(self):
        pass

    def start(self):
        return 1

    def end(self):
        return 10

obj = Foo()
obj.start()
obj.end()
"""


class Foo(object):
    def __init__(self):
        pass

    @property
    def start(self):
        return 1

    @property
    def end(self):
        return 10

obj = Foo()
print(obj.start)
print(obj.end)
属性的定义和使用
技术分享图片
总结:

  ①.编写时:

      方法上方写:@property
      方法参数:只有一个self
  ②.调用时:无需加括号  对象.方法
  ③.应用场景:对于简单的方法,当无需传参且有返回值时,可以使用@property
关于属性的总结
技术分享图片
# 以前写法
# data_list = []
#
# for i in range(1, 901):
#     data_list.append(‘alex-%s‘ % i)
#
# while True:
#     # 1. 要查看的页面
#     page = int(input(‘请输入要查看的页码:‘))
#
#     # 2. 每页显示 10 条
#     per_page_num = 10
#
#     start = (page-1) * per_page_num
#     end = page * per_page_num
#
#     page_data_list = data_list[start:end]
#     for item in page_data_list:
#         print(item)


class Pagenation(object):
    """
    处理分页相关的代码
    """

    def __init__(self,page,per_page_num=10):
        """
        初始化
        :param page: 当前要查看的页面
        :param per_page_num: 每页默认要显示的数据行数
        """
        self.page = page
        self.per_page_num = per_page_num

    @property
    def start(self):
        """
        计算索引的起始位置
        :return:
        """
        return (self.page-1) * self.per_page_num

    @property
    def end(self):
        """
        计算索引的结束位置
        :return:
        """
        return self.page * self.per_page_num



data_list = []

for i in range(1, 901):
    data_list.append(alex-%s % i)

while True:
    # 1. 要查看的页面
    page = int(input(请输入要查看的页码:))

    obj = Pagenation(page)
    page_data_list = data_list[obj.start:obj.end]
    for item in page_data_list:
        print(item)
示例:
技术分享图片
# 以前写法
# data_list = []
#
# for i in range(1, 901):
#     data_list.append(‘alex-%s‘ % i)
#
# while True:
#     # 1. 要查看的页面
#     page = int(input(‘请输入要查看的页码:‘))
#
#     # 2. 每页显示 10 条
#     per_page_num = 10
#
#     start = (page-1) * per_page_num
#     end = page * per_page_num
#
#     page_data_list = data_list[start:end]
#     for item in page_data_list:
#         print(item)


class Pagenation(object):
    """
    处理分页相关的代码
    """

    def __init__(self,data_list,page,per_page_num=10):
        """
        初始化
        :param data_list: 所有的数据
        :param page: 当前要查看的页面
        :param per_page_num: 每页默认要显示的数据行数
        """
        self.data_list = data_list
        self.page = page
        self.per_page_num = per_page_num

    @property
    def start(self):
        """
        计算索引的起始位置
        :return:
        """
        return (self.page-1) * self.per_page_num

    @property
    def end(self):
        """
        计算索引的结束位置
        :return:
        """
        return self.page * self.per_page_num

    def show(self):
        result = self.data_list[self.start:self.end]
        for row in result:
            print(row)


data_list = []

for i in range(1, 901):
    data_list.append(alex-%s % i)

while True:
    # 1. 要查看的页面
    page = int(input(请输入要查看的页码:))
    obj = Pagenation(data_list,page)
    obj.show()
示例的第二种写法

三.嵌套

技术分享图片
# 面向对象:
"""
创建三个帮会且三个帮会的结构内容等都是一致.
"""

class Gang(object):
    def __init__(self, name, address):
        self.name = name
        self.address = address

    def speech(self):
        print(搬砖)

obj1 = Gang(赛利亚我养你, 山东一区)
obj2 = Gang(赛利亚我爱你, 上海一区)
obj3 = Gang(赛利亚我想你, 北京一区)
class Members(object):
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.__salary = salary
        self.gang = None

t1 = Members(鬼剑, 19, 188888)
t2 = Members(格斗, 18, 60)
t3 = Members(神枪,16, 900000)
# ############## 成员分配大区
t1.gang = obj1
t2.gang = obj1
t3.gang = obj2
# ###########################
# 查看t1成员,所在的帮会名称/地址
print(t1.gang.name)
print(t1.gang.address)
print(t1.name)
print(t1.age)
t1.gang.speech()
嵌套

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

22

以上是关于面向对象(进阶)的主要内容,如果未能解决你的问题,请参考以下文章

java学习---面向对象进阶

python-前方高能-面向对象-进阶3

python-面向对象进阶

进阶面向对象

python学习笔记-面向对象进阶&异常处理

python学习笔记-面向对象进阶&异常处理