【python全栈开发】面向对象进阶

这篇具有很好参考价值的文章主要介绍了【python全栈开发】面向对象进阶。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、成员

(一)变量

实例变量:属于对象,每个对象中各自维护自己的数据。
类变量:属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。

【python全栈开发】面向对象进阶,python,开发语言
类变量和实例变量的区别示例:

class Person:

    country = "中国"

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

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        #country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量


print(Person.country)
#中国
p1 = Person("高宇星", 18)
p1.show()

类变量和实例变量+继承问题:

【python全栈开发】面向对象进阶,python,开发语言

class Base(object):
    country = "中国"


class Person(Base):

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

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        # country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量

p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是中国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#中国
print(Person.country)#中国
print(Base.country)#中国

通常来说,调用的变量不是对象变量时,就会去对应的类中找类变量,如果类变量中仍然不存在,就会向上去父类中寻找变量。
【python全栈开发】面向对象进阶,python,开发语言

class Base(object):
    country = "美国"


class Person(Base):

    country = "泰国"

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

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        # country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量

p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是泰国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#泰国
print(Person.country)#泰国
print(Base.country)#美国

当Base父类中的country变成“泰国”、Person类中的country变成“美国”时,调用P2实例对象的country时会找到类变量,答案为“美国”,只有调用Base类的变量country时,才会出现“泰国”。

(二)方法

一共有三种方法:绑定方法、类方法和静态方法

  1. 绑定方法:默认参数为self;
  2. 类方法:@classmethod、默认参数为cls;
  3. 静态方法:@staticmethod,没有默认参数。

python中比较灵活,三种方法均可以通过对象和类进行调用。

class Foo(object):
    def __init__(self, name):
        self.name = name
        
    def f1(self):
        print("绑定方法", self.name)
        
    
    @classmethod
    def f2(cls):
        print("类方法",cls)
        
    @staticmethod
    def f3():
        print("静态方法")

#绑定方法执行方式
obj = Foo("高宇星")
obj.f1()#绑定方法 高宇星
Foo.f1(obj) #非主流的执行方式 绑定方法 高宇星

#类方法执行方式
Foo.f2() #主流方式,直接通过类来实现,其中cls参数代表的就是Foo这个类
#类方法 <class '__main__.Foo'>
obj.f2() #非主流执行方式,通过对象来实现
#类方法 <class '__main__.Foo'>

#静态方法的执行方式
Foo.f3() #主流执行方式,通过类来调用
#静态方法
obj.f3() #主流执行方式,通过类来调用
#静态方法

具体应该使用哪种方法,具体还需要看涉及到哪些内容,如果需要传入对象,那就使用绑定方法,如果需要传入类,那就使用类方法,如果什么都不需要传入,就需要静态方法。

(三)属性

属性是由绑定方法+特殊装饰器组合而成的,主要的区别是:调用方法的时候需要加括号,调用属性的时候不需要加括号。

class Foo():

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

    def f1(self):
        return print(123)


    @property
    def f2(self):
        return print(123)


obj = Foo("闫曦月")
obj.f1()
#123
obj.f2
#123

在分页显示案例中,同样是在绑定方法基础上加上了@property之后,在调用start和end时可以省略掉括号。

class Pagination():
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num

        if current_page < 1:
            self.current_page = 1
            return

        self.current_page = current_page

    #如果加上@property,在下面调用的时候就可以不加括号了,简洁代码(小小的简洁)
    @property
    def start(self):
        return (self.current_page-1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num


user_list = ["用户-{}".format(i) for i in range(1, 3000)]
#分页现实,每页显示10条
while True:
    page = int(input("请输入页码:"))

    print(type(page))

    page_object = Pagination(page, 20)
    page_object_list = user_list[page_object.start: page_object.end]
    for item in page_object_list:
        print(item)

关于属性的编写方式由两种:

  1. 基于装饰器
class C(object):

    @property
    def nnn(self):
        pass

    @nnn.setter
    def nnn(self, value):
        pass

    @nnn.deleter
    def nnn(self):
        pass


obj = C()
#触发nnn属性
obj.nnn

#触发nnn.setter,给该属性传入参数value=123
obj.nnn = 123

#触发nnn.deleter,删除nnn属性
del obj.nnn

  1. 基于定义变量
class C(object):
    def nnn(self):
        print('666')

    def setnnn(self, value):
        print(value)

    def delnnn(self):
        print('delete')

    x = property(nnn, setnnn, delnnn, "I'm the nnn property")
    #第四个参数是注释,等同于‘’‘I'm the nnn property’‘’
obj = C()
obj.x #666
obj.x = 333 
#333
del obj.x
#delete

也可以将方法定义成属性中的变量,在执行方法时会自动触发可以使用的属性。
补充:为了避免报错,属性和实例名不能相同

以下是错误示例:报错原因是,代码以为我要调用@name.setter装饰方法。

class Foo(object):
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    @property
    def name(self):
        return '{}-{}'.format(self.name, self.age)

obj = Foo("高宇星", 24)

改进,增加一个@name.setter装饰器,增加之后不会因为属性和实例名字相同而报错,但是会因为循环调用自己,一直递归导致层次太深而报错。

下面这个例子就是很好的说明,当实例化对象时,自然会用到name这个参数,由于参数name和属性name名字相同,触发了@name.setter,print一下value后就没了,但是此时就会调用属性name,在属性name中又有self.name, 又一次触发@name.setter,循环往复,不停进行递归运算。

class Foo(object):
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    @property
    def name(self):
        return '{}-{}'.format(self.name, self.age)

    @name.setter
    def name(self, value):
        print(value)

    
obj = Foo("高宇星", 24)

如果想让属性和实例上存在一些关联,就可以按照以下方式改进。在实例变量前面加一个_,这样实例变量就变成了_name,属性名字叫name,这样就不冲突了。

class Foo(object):
    
    def __init__(self, name, age):
        self._name = name
        self.age = age
        
    @property
    def name(self):
        print('{}-{}'.format(self._name, self.age))


obj = Foo("高宇星", 24)
obj.name
#高宇星-24

二、成员修饰符

python成员的修饰指的是:公有or私有

  1. 公有: 在任何地方都可以调用成员
  2. 私有:只有类的内部才可以调用成员(成员是以两个下划线开头,则表示该成员为私有)

1、示例一:私有对象和公有对象

(实例对象)对于私有成员__name来说,只能在内部调用,但是对于共有成员age来说,内部和外部都能调用。对于类对象来说也是同样的!文章来源地址https://www.toymoban.com/news/detail-832474.html

class Foo(object):

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

    def get_data(self):
        return self.__name

    def get_age(self):
        return self.age


obj = Foo("闫曦月", 18)
print(obj.age) #18
#obj.__name  age可以调用查看,但是__name是私有的,无法在类的外部进行调用

name = obj.get_data()
#在调用get_data方法时,由于该方法前面没有双下划线,所以是可以在类的外部进行调用的,在方法里面调用私有成员,这样是可以的
print(name) #闫曦月

age = obj.get_age()
print(age)
#18

2、示例二:私有方法和公有方法

class Foo():

    def get_age(self):
        print("公有的get_age")

    def __get_data(self):
        print("私有的__get_data")

    def proxy(self):
        print("公有的proxy")
        self.__get_data()

obj = Foo() 
obj.get_age() #公有的get_age
obj.proxy() 
'''
公有的proxy
私有的__get_data
'''

3、示例三:私有属性和公有属性

class Foo():
    @property
    def __name(self):
        print("私有的属性__name")

    @property
    def proxy(self):
        self.__name
        return 1

obj = Foo()
print(obj.proxy)
'''
私有的属性__name
1
'''

4、特别提示:如果存在继承关系,那么父类中的私有成员,子类无法继承

class Base():

    def __data(self):
        print("base.__data")

    def num(self):
        print("base.num")


class Foo(Base):

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

obj = Foo()
obj.func()
'''
Traceback (most recent call last):
  File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 311, in <module>
    obj.func()
  File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 308, in func
    self.__name()
AttributeError: 'Foo' object has no attribute '_Foo__name'
'''

到了这里,关于【python全栈开发】面向对象进阶的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python面向对象编程,实现模块化开发

    面向对象编程(Object Oriented Programming,OOP)是一种编程范式,它将真实世界中的事物抽象成程序中的对象,并通过对象之间的相互作用来完成程序的逻辑。 封装 (Encapsulation) 封装是指把数据和行为结合成一个相对独立的整体,防止程序中其他部分直接访问或修改这个整体,而

    2024年02月05日
    浏览(121)
  • 🔥🔥Java开发者的Python快速进修指南:面向对象基础

    当我深入学习了面向对象编程之后,我首先感受到的是代码编写的自由度大幅提升。不同于Java中严格的结构和约束,Python在面向对象的实现中展现出更加灵活和自由的特性。它使用了一些独特的,如self和cls,这些不仅增强了代码的可读性,还提供了对类和实例的明确

    2024年02月05日
    浏览(49)
  • 🔥🔥Java开发者的Python快速进修指南:面向对象--高级篇

    首先,让我来介绍一下今天的主题。今天我们将讨论封装、反射以及单例模式。除此之外,我们不再深入其他内容。关于封装功能,Python与Java大致相同,但写法略有不同,因为Python没有修饰符。而对于反射来说,我认为它比Java简单得多,不需要频繁地获取方法和属性,而是

    2024年02月05日
    浏览(52)
  • Java开发者的Python快速进修指南:面向对象--高级篇

    首先,让我来介绍一下今天的主题。今天我们将讨论封装、反射以及单例模式。除此之外,我们不再深入其他内容。关于封装功能,Python与Java大致相同,但写法略有不同,因为Python没有修饰符。而对于反射来说,我认为它比Java简单得多,不需要频繁地获取方法和属性,而是

    2024年02月05日
    浏览(54)
  • 面向对象进阶--接口2

    JDK8开始接口中新增的方法 接口中可以定义有方法体的方法(默认、静态)。 使用默认方法的作用:解决接口升级的问题。 接口中默认方法的定义格式: public default返回值类型 方法名(参数列表){} 接口中默认方法的注意事项: 默认方法不是抽象方法,所以不强制被重写。

    2024年01月23日
    浏览(25)
  • c、c++、java、python、js对比【面向对象、过程;解释、编译语言;封装、继承、多态】

    目录 内存管理、适用 区别 C 手动内存管理:C语言没有内置的安全检查机制,容易出现内存泄漏、缓冲区溢出等安全问题。 适用于系统级编程 C++ 手动内存管理:C++需要程序员手动管理内存,包括分配和释放内存,这可能导致内存泄漏和指针错误。 适用于游戏引擎和系统级编

    2024年02月08日
    浏览(63)
  • Java面向对象进阶第一天

    是静态的意思,可以修饰成员变量,也可以修饰成员方法 静态成员变量 有static修饰,属于类,与类一起加载,内存中只有一份,可以被共享访问。 什么时候用呢?如果信息要被共享,只需要一份就用静态成员变量,比如:系统在线人数。 访问规则: 建议用类名访问:类名

    2024年01月20日
    浏览(27)
  • 黑马Java——面向对象进阶(static&继承)

    目录 1.static静态变量 练习1:定义数组工具类 练习2:定义学生工具类 2.继承  练习:继承的练习(自己设计一个继承体系) 练习 利用方法的重写设计继承结构 练习:带有继承结构的标准Javabean类 3.多态   多态的综合练习 4.包和final 4.1包 4.2final  5.权限修饰符和代码块 5.1权

    2024年01月25日
    浏览(29)
  • Java面向对象进阶第四天(常用API)

    API全称是应用程序编程接口,是Java写好的程序,程序员可以直接调用。 Object是祖宗类,它里面的方法,一切子类对象都可以使用。 public String toString() 默认是返回当前对象的地址信息。 Student s = new Student(\\\"张三\\\",\\\'女\\\', 23); System.out.println(s.toString()); 返回对象地址 System.out.printl

    2024年01月20日
    浏览(31)
  • 面向对象编程(进阶)1:关键字:this

    目录 1.1 this是什么? 1.2 什么时候使用this 1.2.1 实例方法或构造器中使用当前对象的成员 举例1: 举例2: 测试类: 1.2.2 同一个类中构造器互相调用 注意: 1.3 练习 **练习1:** 练习2: 在Java中,this不算难理解,它的作用和其词义很接近。 它在方法(准确的说是实例方法

    2023年04月13日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包