zoukankan      html  css  js  c++  java
  • [ python ] 下划线的意义和一些特殊方法

    Python用下划线

    Python用下划线为变量前缀和后缀制定特殊变量

    _xxx 不能用 'from module import *' 导入
    __xxx__ 系统定义名字
    __xxx 类中的私有变量名

    核心风格:避免用下划线作为变量名的开始

    因为下划线对解释器有特殊的意义,而且内建的标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始。
    一般来讲,变量名_xxx被看做是'私有的',在模块和类外不可以使用。当变量是私有的时候,用_xxx来表示变量是很好的习惯
    因为变量名__xxx__对python来说有特殊含义,对于普通的变量应当避免这种命名风格。

    '单下划线':开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;
    '双下划线':开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。

    实例:

    class Foo(object):
        def __init__(self, name, age):
            self._name = name # 单下划线开始的成员变量叫做保护变量,只有类对象和子类对象自己能访问到这些变量
            self.__age = age # 双下划线是私有成员,只有类的内部能调用,类对象能够访问,但是应该避免直接去访问
    
    
    f = Foo('hkey', 20)
    print(f.__dict__)   # 打印对象所有的属性和方法
    print(f._name)
    
    # 执行结果:
    # {'_Foo__age': 20, '_name': 'hkey'}
    # hkey
    

    以单下划线开头(_name)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用'from xxx import *'导入
    以双下划线开头的(__age)代表类的私有成员;
    以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如__init__()代表类的构造函数。

    类中特殊方法的使用

    __new__:类中的构造方法
    __init__: 类中的初始化方法

    class A(object):
        def __init__(self):
            print('init')
    
        def __new__(cls, *args, **kwargs):
            print('new %s' %cls)
            return object.__new__(cls, *args, **kwargs)
    
    A()
    
    # 执行结果:
    # new <class '__main__.A'>
    # init
    

    知识点:
    1. 继承自object的新式类才有 __new__
    2. __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由python解释器自动提供;
    3. __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意;
    4. __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其他初始化的动作,
    __init__不需要返回值,__new__方法一定要有返回值
    5. 若__new__没有正确返回当前cls的实例,那__init__是不会被调用的,即使是父类的实例也不行;

    __len__:如果类表现的像一个list,要获取有多少个元素,就得用 len()函数,要让len()函数工作正常,类必须提供一个
    特殊的方法 __len__(),它返回元素的个数;

    实例:

    class Student(object):
        def __init__(self, *args):
            self.names = args
    
        def __len__(self):
            return len(self.names)
    
    s = Student('xiaofei', 'hkey', 'xiaoA')
    
    print(len(s))
    
    # 执行结果:
    # 3
    

    __str__ 和 __repr__

    使用__str__和__repr__ 打印类的对象,返回的不再是一个内存地址,而是定义后字符串内容,__str__和__repr__返回的必须是字符串类型:

    class Student(object):
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return 'Student object (name: %s)' % self.name
    
    s = Student('hkey')
    print(s)
    # 用内置方法 str 和 repr 调用
    print(str(s))
    print(repr(s))
    
    # 执行结果:
    # Student object (name: hkey)
    # Student object (name: hkey)
    # print(repr(s))执行结果:
    # <__main__.Student object at 0x000001D0EB04BC18>
    

     在上面的实例中没有定义__repr__特殊方法,当使用内置方法 repr 调用的时候显示的是类的内存地址信息,这两者的区别:
    __str__:返回用户看到的字符串
    __repr__:返回程序开发者看到的字符串,也就是说__repr__()为调试使用的。

    这里有个偷懒的写法:

    class Student(object):
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return 'Student object (name: %s)' % self.name
        __repr__ = __str__
    
    s = Student('hkey')
    print(s)
    # 用内置方法 str 和 repr 调用
    print(str(s))
    print(repr(s))
    
    # 执行结果:
    # Student object (name: hkey)
    # Student object (name: hkey)
    # print(repr(s))执行结果:
    # Student object (name: hkey)
    

    在类中,定义这两个特殊方法的时候要要注意:
        当使用内置方法 str 对类对象进行调用的时候,首先会去找类中的 __str__方法,如果不存在就会找 __repr__方法,
        所以如果实现这两个特殊方法返回的结果一致时,简单方式就是写一个__repr__的特殊方法就行;

    __call__:可以直接对实例进行调用

    实例:

    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self, *args, **kwargs):
            print('My name is %s.' % self.name)
    
    s = Student('hkey')
    s()
    
    # 执行结果:
    # My name is hkey.
    

    反射及item系列的特殊方法

  • 相关阅读:
    Linux几个常用的目录结构
    Linux 安装composer
    Elasticsearch修改network后启动失败
    php7 闭包调用
    php 爬虫框架
    file_get_contents('php://input') 和POST的区别
    PHP指定日期转时间戳
    .Net 站点跨域问题及解决方法
    C# 多线程学习系列一
    Nginx学习系列四默认负载均衡轮询及Ip_hash等常用指令介绍
  • 原文地址:https://www.cnblogs.com/hukey/p/9584791.html
Copyright © 2011-2022 走看看