Python基础(二十四): 实例方法补充

一、私有方法

  • 私有方法: 在方法名前添加两个下划线__
class Person:
    def __run(self):
        print("跑")
        
print(Person.__dict__)

# 打印: 
# {'__module__': '__main__', '_Person__run': , '__dict__': , '__weakref__': , '__doc__': None}
复制代码
  • 有打印可知: __run方法被重整为_Person__run方法
p = Person()
p._Person__run()     # 打印: 跑
复制代码
  • 如果额外添加一个_Person__run方法, 将会覆盖__run方法
class Person:
    def __run(self):
        print("跑")
    def _Person__run(self):
        print("pao")

    def run(self):
        self.__run()
        self._Person__run()

p = Person()
p.run()     

# 打印: 
# pao
# pao
复制代码

对方法进行命名时, 不要使用类似_Person__run的命名方式, 以防止覆盖私有方法

二、特殊内置方法

1、__init__

  • __init__在实例初始化的时候调用, 可以在此时设置实例属性, 同时可以传入参数
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("张三", 18)
print(p.name, p.age)        # 打印: 张三 18
复制代码

2、__str__

  • 当打印实例的时候, 会调用实例的__str__方法, 将该方法的返回值打印出来
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return "%s %s"%(self.name, self.age)
        
p1 = Person("张三", 18)
print(p1)       # 打印: 张三 18

p2 = Person("李四", 20)
print(p2)       # 打印: 李四 20
复制代码

内置函数str(实例), 也可以获取该实例__str__方法的返回值

s = str(p1)
print(s, type(s))      # 打印: 张三 18 
复制代码

3、__repr__

  • 在上面, 通过print函数打印实例时, 会调用实例的__str__方法, 而当类没有重写__str__方法时, 就会调用__repr__, 并打印返回值
  • __repr__: 返回实例的详细信息, 主要给开发人员调试使用, 我们可以重写该方法的实现
class Person:
    def __repr__(self):
        return "xxxxx"
p = Person()
print(p)        # 打印: xxxxx
复制代码
  • 同时可以使用函数repr(实例), 来获取实例__repr__的返回值
tmp = repr(p)
print(tmp)      # 打印: xxxxx
复制代码
  • 如果实现了__str__方法, 只能通过repr()函数获取__repr__的返回值
class Person:
    def __str__(self):
        return "str"
    def __repr__(self):
        return "repr"
p = Person()
print(p)        # 打印: str

tmp = repr(p)
print(tmp)      # 打印: repr
复制代码
  • 当我们不重写__repr__方法时, 可以获取到实例的详细信息
class Person:
    def __str__(self):
        return "str"
p = Person()
print(p)        # 打印: str
    
tmp = repr(p)
print(tmp)      # 打印: <__main__.Person object at 0x1034017b8>
复制代码
  • 可以使用eval()函数, 将repr()获取的实例信息, 转为一个实例
import datetime

r = datetime.datetime.now()
print(r)            # 打印: 2018-04-11 15:55:40.726878

tmp = repr(r)
print(tmp)          # 打印: datetime.datetime(2018, 4, 11, 15, 55, 40, 726878)

result = eval(tmp)
print(result)       # 打印: 2018-04-11 15:55:40.726878
复制代码

4、__call__

  • __call__: 可以使一个实例如同函数一样调用
class Person:
    def __call__(self, *args, **kwargs):
        print("xxx", args, kwargs)

p = Person()
p()                          # 打印: xxx () {}
p(123, name = "zhangsan")    # xxx (123,) {'name': 'zhangsan'}
复制代码
  • __call__方法的应用场景: 可以用作偏好函数使用
# 现有两种类型的笔(钢笔, 铅笔), 以及多种颜色(红色, 绿色, 黄色, 黑色)
# 创建不同种类, 不同颜色的笔

class PenFactory:
    def __init__(self, p_type):
        self.p_type = p_type
    def __call__(self, p_color):
        print("这是一支%s, 颜色是%s"%(self.p_type, p_color))
penF = PenFactory("钢笔")
penF("红色")        # 打印: 这是一支钢笔, 颜色是红色
penF("绿色")        # 打印: 这是一支钢笔, 颜色是绿色
penF("黄色")        # 打印: 这是一支钢笔, 颜色是黄色
penF("黑色")        # 打印: 这是一支钢笔, 颜色是黑色

pencilF = PenFactory("铅笔")
pencilF("红色")     # 打印: 这是一支铅笔, 颜色是红色
pencilF("绿色")     # 打印: 这是一支铅笔, 颜色是绿色
pencilF("黄色")     # 打印: 这是一支铅笔, 颜色是黄色
pencilF("黑色")     # 打印: 这是一支铅笔, 颜色是黑色
复制代码

5、索引操作

  • 可以如同使用字典的方式, 操作实例, 只需实现下面的方法
class Person:
    # 初始时, 创建缓存字典
    def __init__(self):
        self.cache = {}
    # 增/改
    def __setitem__(self, key, value):
        self.cache[key] = value
    # 取
    def __getitem__(self, item):
        return self.cache[item]
    # 删
    def __delitem__(self, key):
        del self.cache[key]
        
p = Person()
print(p.cache)      # 打印: {}       

p["age"] = 18       # 调用__setitem__方法
print(p.cache)      # 打印: {'age' : 18}

age = p["age"]      # 调用__getitem__方法
print(age)          # 打印: 18

del p["age"]        # 调用__delitem__方法
print(p.cache)      # 打印: {}
复制代码

6、切片操作

  • 实例的切片操作和索引操作一样, 需要实现三个方法
class Person:
    # 改
    def __setitem__(self, key, value):
        print(key, value)
    # 取
    def __getitem__(self, item):
        print(item)
    # 删
    def __delitem__(self, key):
        print(key)

p = Person()
p[0:4:2] = ["a", "b"]   # 打印: slice(0, 4, 2) ['a', 'b']

p[1:5:2]                # 打印: slice(1, 5, 2)

del p[2:6:4]            # 打印: slice(2, 6, 4)
复制代码
  • 上面代码中, 打印的slice, 就是切片类型, 我们可以给实例添加一个列表属性, 用来操作切片
class Person:
    # 改
    def __setitem__(self, key, value):
        print(key)
        print(key.start)    # 起点
        print(key.stop)     # 终点
        print(key.step)     # 步长
        
p = Person()
p[0:4:2] = ["a", "b"] 
# 打印: 
# slice(0, 4, 2)
# 0
# 4
# 2
复制代码
  • 实际操作如下
class Person:
    def __init__(self):
        self.cache = [0, 1, 2, 3, 4, 5, 6, 7]
    # 改
    def __setitem__(self, key, value):
        self.cache[key] = value
    # 取
    def __getitem__(self, item):
        return self.cache[item]
    # 删
    def __delitem__(self, key):
        del self.cache[key]

p = Person()
p[0:4:2] = ["a", "b"]
print(p.cache)      # 打印: ['a', 1, 'b', 3, 4, 5, 6, 7]

result = p[0:4:2]
print(result)       # 打印: ['a', 'b']

del p[0:4:2]
print(p.cache)      # 打印: [1, 3, 4, 5, 6, 7]
复制代码

7、比较操作

  • 作用: 可以自定义对象"比较大小, 相等以及真假"的规则

  • 对象之间进行比较, 需要实现几个对应的方法

比较 方法
相等 __eq__
不相等 __ne__
小于 __lt__
小于或等于 __le__
大于 __gt__
大于或等于 __ge__
  • 以相等为例, 指定对象相等时的条件
class Person:
    def __init__(self, age):
        self.age = age
    def __eq__(self, other):
        return self.age == other
p1 = Person(20)
p2 = Person(21)
print(p1 == p2)         # 打印: False
复制代码
  • 上述六个方法中, 可以分为三组相等 和 不相等, 小于 和 大于, 小于或等于 和 大于或等于, 在这三组中, 只要实现某组中的一个, 该组的另一个不需要实现也可以进行比较

  • 在这六个方法中, 都有两个参数self 和 other, 如果只实现某对中的一个方法, 那么使用两个不同的比较方式, 传入的参数会互相颠倒

class Person:
    def __init__(self, age):
        self.age = age
    def __lt__(self, other):
        print(self.age, other.age)
p1 = Person(20)
p2 = Person(21)
p1 < p2             # 打印: 20 21
p1 > p2             # 打印: 21 20
复制代码

注意: 如果是 相等 和 不相等, 在只实现一个改组方法的情况下, 传入参数不会互相颠倒

  • 正常境况下, 比较方法不会叠加, 比如实现小于 和 等于两个方法, 并不会叠加为支持小于等于方法, 如果需要, 必须实现小于等于对应的方法
class Person:
    def __init__(self, age):
        self.age = age
    def __eq__(self, other):
        return self.age == other.age
    def __lt__(self, other):
        print(self.age, other.age)

p = Person(20)
print(Person.__dict__)

# 打印信息:
{
    '__module__': '__main__', 
    '__init__': <function Person.__init__ at 0x104d227b8>, 
    '__eq__': <function Person.__eq__ at 0x104d22840>, 
    '__lt__': <function Person.__lt__ at 0x104d228c8>, 
    '__dict__': '__dict__' of 'Person' objects>, 
    '__weakref__': '__weakref__' of 'Person' objects>, 
    '__doc__': None, '__hash__': None
}
复制代码
  • 由打印信息可知, 并没有出现其他的比较方法

  • Python中提供了一个装饰器, 可以将比较方法进行叠加, 并衍生出相反的方法

import functools

@functools.total_ordering
class Person:
    def __init__(self, age):
        self.age = age
    def __eq__(self, other):
        return self.age == other.age
    def __lt__(self, other):
        print(self.age, other.age)

p = Person(20)
print(Person.__dict__)

{
    '__module__': '__main__',
    '__init__': <function Person.__init__ at 0x1038227b8>, 
    '__eq__': <function Person.__eq__ at 0x103822840>, 
    '__lt__': <function Person.__lt__ at 0x1038228c8>, 
    '__dict__': '__dict__' of 'Person' objects>,
    '__weakref__': '__weakref__' of 'Person' objects>,
    '__doc__': None, '__hash__': None, 
    '__gt__': <function _gt_from_lt at 0x101fe3a60>, 
    '__le__': <function _le_from_lt at 0x101fe3ae8>,
    '__ge__': <function _ge_from_lt at 0x101fe3b70>
}
复制代码
  • 由打印可以看出, 通过__eq____lt__, 衍生出__gt__, __le__, __ge__

8、__bool__

  • __bool__: 当实例做为条件语句时, 决定实例的真或假

  • 在Python中, 判断条件是非0即真, 非空即真, 而实例对象也可以作为判断语句

class Person:
    def __bool__(self):
        return True
p = Person()
if p:
    print("xxx")
else:
    print("ooo")
# 打印: xxx
复制代码
class Person:
    def __bool__(self):
        return False
p = Person()
if p:
    print("xxx")
else:
    print("ooo")
# 打印: ooo
复制代码

你可能感兴趣的:(Python基础(二十四): 实例方法补充)