首页 > 编程语言 > 详细

Python说文解字_详解元类

时间:2019-05-30 21:02:24      阅读:113      评论:0      收藏:0      [点我收藏+]

1、深入理解一切接对象:

  1.1 什么是类和对象?

    首先明白元类之前要明白什么叫做类。类是面向对象object oriented programming的重要概念。在面向对象中类和对象是最基本的两个概念。正如中国的道家所言,一生二,二生三,三生万物。类和对象正如这个阴阳的二元世界观,相辅相成存在的。

    类英文class、对象英文instance。类是描述如何创建一个对象的代码段,用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法。

    因此我们有这样的概念。

    类是对象的载体,对象又分属性和方法两个方面。

    属性是对象的名词部分、方法是对象的动词部分。

  1.2 一切接对象?

    类是来自元初的,也就是在Py中类也是对象,也可以具有属性和方法两个方面。

  1.3 这是一个哲学概念。

    面向对象的最基本的问题是建立在哲学的思考上面的(当然我们用道家的思想来解释,老外可能也不是这么想的 ),因此我们有这样一个图示:  

       技术分享图片

     是不是面向对象的底层是哲学的观点。元类是不可再分的类,也就是类的加工厂,我们平时所建立的类其实是人家已经给你建立好的“工厂”、“模板”拿来可以直接用。当然我们也可以自定义一个“工厂”、“模板”,属于定制性的类。当然自定义一个类也好,使用人家Python给你现成的模板也罢。只要一个类一旦下生,就具备了属性和方法两个功能(人生下来就会吃饭和喘气),而且生下来的这个类本身也被大自然或者上帝看做是一个对象。

    我们知道类的继承,在Python中type函数可以表示一个对象的属性,而且还可以创建一个类,也叫做类的加工厂。我们自定义一个类,让他们分别继承在父类(object)和元类(type),用dir命令来看看他们所具有的的属性和方法。

class Users1(object):
    pass

class Users2(type):
    pass

print(dir(Users1))
# [__class__, __delattr__, __dict__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __gt__, __hash__, __init__, __init_subclass__, __le__, __lt__, __module__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__, __weakref__]
print(dir(Users2))
# [__abstractmethods__, __base__, __bases__, __basicsize__, __call__, __class__, __delattr__, __dict__, __dictoffset__, __dir__, __doc__, __eq__, __flags__, __format__, __ge__, __getattribute__, __gt__, __hash__, __init__, __init_subclass__, __instancecheck__, __itemsize__, __le__, __lt__, __module__, __mro__, __name__, __ne__, __new__, __prepare__, __qualname__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasscheck__, __subclasses__, __subclasshook__, __text_signature__, __weakrefoffset__, mro]

 

  我们发现从元类继承过来的这个类,不光具有父类继承的一些属性和方法,而且还增加了好多方法。在我们实际使用的过程中,我们大多数是在父类这个层面上面来使用的。其中关于元类的很多属性和方法都被隐藏了。

print(Users1.__base__)
print(Users2.__base__)
# <class object>
# <class type>
print(Users1.__bases__)
print(Users2.__bases__)
# (<class object>,)
# (<class type>,)

 

  我们分别打印里面的属性,就可以看到其实User1也有这属性和方法,但是都被隐藏了。

 

2.property动态属性:

   第一个问题:为什么要有动态属性?

  提出动态属性,肯定就有静态属性这么一说。静态属性是在写类的时候通过构造函数或者类属性都之前定义好的。比如说。

  例子1:构造函数定义好一些属性,平时就不太用更改了。

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

if __name__ == __main__:
    p = Person(thomas,18)
    print(p.age)

 

   例子2:类属性定义。

class Person:
    human = white human
    def __init__(self,name,age):
        self.name = name
        self.age = age

if __name__ == __main__:
    p = Person(thomas,18)
    print(p.human)

  这两个都叫做静态属性。

  第二个问题:为什么要分动态属性和静态属性?

  其实这是一种规范而已。举个例子:比如说我们有一个人的类的属性。大类来说分:“白种人”、“黄种人”、“黑人”等等,这些属性都是显而易见基本上都不会变化的属性,他们大多数都是用于分类而用的,在编程中类似于这类的属性归入静态属性的范畴(类的特性就是归类,要学会类必须要学会归类);另外,我们在人的这个类中,姓名、年龄、身高等等,每个人的个体变化都不一样,都是纷繁复杂的变化,我们把这类属性归入动态属性。

  第三:写一个比较规范的,用构造函数改写的人的属性(动态属性和静态属性,用property装饰器的方式)

class Person:
    def __init__(self,race,national):
        self.race = race
        self.national = national

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,value):
        self._name = value

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self,value):
        self._age = value

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self,value):
        self._height = value

if __name__ == __main__:
    p = Person(yellow,China)
    # 打印静态属性
    print(p.race,p.national)

    # 赋值动态属性
    p.name = "Thomas"
    p.age = 38
    p.height = 183

    # 打印动态属性
    print(p.name)
    print(p.height)
    print(p.age)

# yellow China
# Thomas
# 183
# 38

 

  一个重要的注意:!

    @property
    def name(self):
        return self.name

    @name.setter
    def name(self,value):
        self.name = value
RecursionError: maximum recursion depth exceeded

  ·发现没有,如果我们将装饰器函数中的下划线去掉了。会出现了最大递归深度的报错。

  重点:在用动态属性property的时候(其实大多数时候也带注意),方法名和里面属性名一致的时候,类属性的下划线不能少,否则会报错。原因在于,如果不加下划线出现self.属性名时会调用类的getattr方法不断调用会陷入死循环。

 

3.__getattr__,__getattribute__

  #getattr是在查找不到属性的时候调用

  #getattribute是查没查到着都会调用这个属性

  第一个问题:为什么要有__getattr__和__getattribute__?

    在实际的工作中,我们如果选择一些属性的时候,误选了或者本身这个属性没有的话会报错(当然大家都是),为了完善整个类中属性的调用,给这些属性加上一些特别的提示,不用报错停止,而是返回一些提示。这就用到了这两种方法。

  第一个:关于getattr的方法

  例子1:打印一个不存在的属性

class Person:
    def __init__(self,race,national):
        self.race = race
        self.national = national

if __name__ == __main__:
    p = Person(yellow,China)
    # 打印不存在的属性
    print(p.company)
# AttributeError: Person object has no attribute company

  发现会报一个属性的错误。

  例子2:我们完善一下这个属性的调用

class Person:
    def __init__(self,race,national):
        self.race = race
        self.national = national

    def __getattr__(self, item):
        print("no this attribution")

if __name__ == __main__:
    p = Person(yellow,China)
    # 打印不存在的属性
    print(p.company)
# no this attribution
# None

  发现是打印这个属性不存在的内容,并返回一个空值。

  第二个:发现__getattr__后面的参数存在一个item的传参?这是什么?

  这是一个关于字典的传参。因此我们在__getattr__后还可以加入一些限定条件,我们就用这个传参item为例子。

  例子1:

class Person:
    def __init__(self,race,national,info={}):
        self.race = race
        self.national = national
        self.info = info

    def __getattr__(self, item):
        return self.info[item]


if __name__ == __main__:
    p = Person(yellow,China,{"company":"CCTV"})
    # 打印不存在的属性
    print(p.company)

  我们限定了字典的键内容,可以实现直接访问值的方式。

  第三:关于__getattribute__这个是比较全的,

class Person:
    def __init__(self,race,national,info={}):
        self.race = race
        self.national = national
        self.info = info

    def __getattr__(self, item):
        return self.info[item]

    def __getattribute__(self, item):
        print("yes")

if __name__ == __main__:
    p = Person(yellow,China,{"company":"CCTV"})
    # 打印不存在的属性
    print(p.company)
yes
None

  也就是找没找的到都会打印。

 

4. __get__、__set__、__delete__属性查找过程:

  我们通过get,set来所属于的属性是否和我们预先设计的一样。这两个函数其实就是起到了静态语言的一种作用。

  例子1:我们判断给类的属性输入30这个值是否是一个int类型的。如果不是返回是错误一句话;

import numbers


class IsInt:
    def __get__(self, instance, owner):
        return self.value
    def __set__(self, instance, value):
        if not isinstance(value,numbers.Integral):
            print("value is not Int")
        else:
            self.value = value
    def __delete__(self, instance):
        pass


class Person:
    age = IsInt()

if __name__ == __main__:
    p = Person()
    p.age = 30
    print(p.age)
# 30
    p.age = abc
    print(p.age)
# value is not Int

 

Python说文解字_详解元类

原文:https://www.cnblogs.com/noah0532/p/10951898.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!