关于python 类方法 这一件事

 

1.  一些__方法

class Foo(object):

    def __init__(self):
        print("init")

    def __call__(self, *args, **kwargs):
        print("call")

    def __getattr__(self, item):
        print("getattr", item)

    def __setattr__(self, key, value):
        print(key, value)

    def __str__(self):
        return "str"

    def __repr__(self):
        print("repr")

    def __add__(self, other):
        return other+1

    def __getitem__(self, item):
        print(item)

    def __setitem__(self, key, value):
        print(key, value)

    def __delitem__(self, key):
        print(key)

    def __iter__(self):          
        return iter([1, 2, 3])
     
    def __contains__(self, item):
        print(item)
        return True



obj = Foo()             # 只执行__init__
obj()                   # 调用 __call__
obj.xx                  # 调用__getattr__, 把xx当作item传给item
obj.xx = 123            # 调用__setattr__, 把xx当作key,123当作value 传给方法
print(obj)              # 调用__str__, 打印返回值
print('%s'%obj)         # 走的也是__str__
print(repr(obj))        # 调用__repr__
print('%r'%obj)         # 走的是__repr__
print(obj+7)            # 调用__add__, 把7当作other传给方法
obj['k1']               # 调用__getitem__,k1为item
obj['k1'] = 123         # 调用__setitem__, k1为key.123为value
del obj['k1']           # 调用__delitem__, k1为key
for i in obj:           # 调用__iter__, 它必须返回迭代器
    print(i)

"x" in obj              # 调用__contains__, 打印结果 x




hasattr, getattr, setattr 

hasattr 可以获得静态属性和类属性,

getattr 和一拿到静态属性和类属性, 拿到的类属性, 就是个函数时,拿的内存地址。当那不存在的属性时,会触发异常,这种情况, 可以设置默认值。

setattr 和更新属性, 不存在时自动创建属性。

class FunctionDemo(object):
    name = 'demo'

    def do_it(self):
        return "123"


obj = FunctionDemo()
print(hasattr(obj, 'name'))    # True
print(hasattr(obj, 'do_it'))   # True
print(getattr(obj, 'name'))    # demo
print(getattr(obj, 'do_it'))   # 内存地址
# print(getattr(obj, 'nn'))    找没有的属性会报错
print(getattr(obj, 'nn', 'lala'))  # 如果没没拿到, 就拿默认值
setattr(obj, "nn", 66)
print(getattr(obj, 'nn'))    # 66

 

 

 

 

2. 子类执行父类方法

class Base(object):
    def func(self):
        print("父类")


class Foo(Base):
    def func1(self):
        super(Foo, self).func()  # 按顺序执行到父类
        # 也可直接super().func(), 不加会默认加参数
        Base.func(self)          # 直接执行父类
        print("子类")


obj = Foo()
obj.func1()

# 父类
# 父类
# 子类

3. 关于super

class Base(object):
    def func(self):
        print("base")
        super(Base, self).func1()


class Bar(object):
    def func1(self):
        print("Bar")


class Foo(Base, Bar):
    pass


obj = Foo()
obj.func()
# base
# Bar

瞎鸡解析:

obj.func() 调用func,首先会在自己(Foo)里找有没有func,然后再按继承顺序从最近的Base里找func,再从Bar找。

而super 正是按这一顺序执行的,

首先func在Foo里没找到,从Base里找到了func,执行print,遇到super,super按下一顺序找到Bar, .func1执行里面的print。

而上面的第二个也是这样,先从Foo里找func1, 再从Foo的父类Base找, super按下依顺序找到Base,再.func执行里面的print。

 

下面是几个例子,说明py3的类继承的顺序,是广度优先的,而py2的经典类是深度优先的。

例一:说明super是广度优先的

class A(object):
    def func(self):                     # 9
        print('a')                      # 10


class B(A):
    def func(self):                    # 5
        super(B, self).func()          # 6
        print('b')                     # 12


class C(A):
    def func(self):                  # 7
        super(C, self).func()        # 8
        print('c')                   # 11


class D(B, C):
    def func(self):                 # 3
        super(D, self).func()       # 4
        print('d')                  # 13


d = D()                             # 1
d.func()                            # 2


# a
# c
# b
# d

 例二:

class A(object):
    def func(self):
        print('a')


class B(A):
    def func(self):
        print('b')


class C(A):
    def func(self):
        print('c')


class D(B, C):
    print('d')


print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

                                                                                        例一,例二图

例三:

B继承A,C继承E,D继承BC

例四:复杂的继承关系

 

4. __slots__

class Foo(object):
    __slots__ = ('name', )      # 只能 .出name

    def __init__(self):
        self.name = "aki"


obj = Foo()
# obj.age = 19                  # 因为 上面设置了 __slots__ = ('name', ) 所以会报错,
print(obj.name)
# print(obj.age)

5. __call__ 和__new__

__call__

""" __call__ """

class Foo(object):

    def __init__(self, a):                  # 初始化
        print(a)
        print("pk")

    def __call__(self, *args, **kwargs):   # 可调用
        print(args, kwargs)


obj = Foo(123)                             # 实例化  可以传参数被init使用
obj(12, 34, 344, a=678)                    # 可以传参数变成一个函数


# 123
# pk
# (12, 34, 344) {'a': 678}

__new__

"""__new__"""


class Foo(object):
    def __init__(self):
        print("init")

    def __new__(cls, *args, **kwargs):         # cls 为一个类, 最先执行__new__,构造一个实例传给__init__
        print("new")
        return super(Foo, cls).__new__(cls)    # 没有这句只执行__new__,
        # return object.__new__(cls, *args, **kwargs)


Foo()
# new
# init
注意: __new__返回已经实例化的对象或不返回,不会执行__init__
obj = 123


class Foo(object):
    def __init__(self):
        print("init")

    def __new__(cls, *args, **kwargs):         # cls 为一个类, 最先执行__new__,构造一个实例传给__init__
        print("new")
        return obj                             # 不会执行__init__, 没return 更不会执行


Foo()
# new

关于__new__和 __init__

  • __new__是一个静态方法,而__init__是个实例方法。
  • __new__方法会返回一个创建的实例, __init__不需要返回
  • 只有__new__返回cls, __init__才能被调用
  • 创建新实例时调用__new__,初始化一个实例用__init__

6. 创建类的两种方法

# 第一种
class Foo(object):
    a = 123

    def func(self):
        return 123

# 第二种
Foo = type('Foo', (object,), {'a': 123, 'func': lambda self: 123})
#     Foo继承object,


obj = Foo()
print(obj.func())
print(obj.a)

7. 私有方法

class Foo(object):

    def __init__(self, name, age):
        self.name = name
        self.__age = age      # 私有方法不能随意调用

    def func(self):
        print(self.__age)    # 可以调用


obj = Foo("XX", 33)
obj.func()                 # 可以打印__age
# print(obj.__age)
print(obj._Foo__age)       # 硬拿也可以拿到

# 如果再来个类继承这个Foo, 继承的子类也是不能调用私有方法的

8.  __enter__, __exit__(所谓的上下文with)

class Foo(object):

    def __init__(self):
        print("init")

    def __enter__(self):
        print('进来')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('出来')


obj = Foo()
with obj:     # 自动触发__enter__
    print('中间')

# 执行前自动触发__enter__,执行自己,再执行__exit__

# init
# 进来
# 中间
# 出来

 

上下文:

class A(object):
    def __init__(self):
        self.state = False

    def __enter__(self):
        self.state = True
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.state = False


obj = A()
print(obj.state)
with obj:
    print(obj.state)
print(obj.state)

# 注意,_enter_方法必须返回一个对象,可以是自身,也可以是其他的对象。
# False
# True
# False

 注意,_enter_方法必须返回一个对象,可以是自身,也可以是其他的对象。

exc_type : 异常类型

exc_val : 异常值

exc_tb : 异常回溯追踪

也可以用contextlib实现上下文

from contextlib import contextmanager


@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()

Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。

9. 约束类

class Foo(object):
    def send(self):
        raise NotImplementedError('子类没有实现这个方法')


class Demo(Foo):
    def send(self):
        print("子类要有这个方法,要不就报错")


obj = Demo()
obj.send()            # 实例化时不会报错,只在.send时才会报错
import abc


class Base(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def send(self):
        pass

    def func(self):
        print('func')


class Foo(Base):
    def send(self):
        print("o")


obj = Foo()       # Foo 如果没send, 实例化时就会报错
obj.send()

10. 类的集合

一个类的属性是另一个类的对象

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


python = Course('python')


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


py = Classes('小葵花大班', python)     # python 是上面的实例化,即是对象
print(py.course.name)
# python

11. 单例模式

class A(object):
    _instance = None

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

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
            return cls._instance
        else:
            return cls._instance


aki = A('aki')
desky = A('desky')
print(aki)
print(desky)
print(aki.name)
print(desky.name)
# <__main__.A object at 0x000001AF6E370550>
# <__main__.A object at 0x000001AF6E370550>
# desky
# desky

单例模式, 一个类始终只有一个实例,第一次来的时候创建一个实例, 再来的时候用之前第一次创建的实例。

12 mateclass

python中,一切都是对象,比如一个数字、一个字符串、一个函数。对象是类(class)的是实例,类(class)也是对象,是type的实例。type对象本身又是type类的实例,因此我们称type为metaclass(中文元类)。

通俗地说就是说,python3中,所有的类都是新式类,都继承自object,而object又都继承自type,所有的class是object的实例,而object是type的实例。

>>> age = 24
>>> age.__class__
<type 'int'>

>>> name = 'bob'
>>> name.__class__
<type 'str'>


>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>

还可以自定制matclass

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list):
    __metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值