为ip池做准备之 ---- __metaclass__以及eval的使用

制作ip池的时候,可能需要不定时新代理池获取的网站,通常的做法是每次添加一个新的网站,就改一下获取函数,这样更改添加方法很容易出错.我们可以设想另外一种模式,当我们要添加新的获取网站的时候,我们只要添加对应的函数就可以了,而不需要更改其他代码,这样会方便很多,这里我们借助元类来实现.


__metaclass__ 的一些理解

以下是我个人理解:

  • python中,一切皆对象,元类也是一个对象
  • 元类是可以创造类对象的一种类
  • type除了显示对象类型以外,还可以作为关键字去创建类

参考别人的资料得到的信息:

  • 类也是对象,当使用关键字class的时候python解释器就会自动的取创建一个对象,这个对象自身拥有创建对象(类实例,也就是我们说的类实例化出来的对象)的能力,它的本质仍然是一个对象,于是你可以对它进行如下操作:

    1. 你可以把它复制给一个变量
    2. 你可以copy它
    3. 你可以为它增加属性
    4. 你可以将他作为参数进行传递
  • 可以动态的在方法中创建类,但是仍然需要你自己编写整个类的方法和属性,如下列子:

def choose_class(name):
    if name == 'foo':
        class Foo(object):  # 这里就是动态的根据条件来创建类但是关于它的方法仍然需要自己填写完整才能继续
            pass
        return Foo     # 返回的是类,不是类的实例
    else:
        class Bar(object):
            pass
        return Bar

除了手动创建类以外typey可以可以创建类的,格式如下:

type(类名,父类的元祖(在有继承的情况下,可以为空),包含属性的字典(名称和值))

比如我们要创建一个名为TestFunc(object)的类,它有一个属性叫做name 值是 TestFunc, 那么我们可以按照下面的方式创建:

type(TestFunc,(object),{'name':'TestFunc'})

这样我们就使用表达式创建了一个类,这个类和上面的模式使用class创建的类是没有区别的.在这里发现可以批量性的根据自己的需要来创建类了.

__metaclass__属性

这是一个类属性,当你用这个属性创建类的时候,它就会用元类来创建类.

class TestFunc(AClass):
    __metaclass__=someting  

如果你这么做了,Python就会用元类来创建类Foo。这里面可以这样理解。首先写下class Foo(object),但是类对象Foo还没有在内存中创建。Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类。把下面这段话反复读几次。当你写如下代码时:

class TestFunc(Aclass):
    pass

Python做了如下的操作:

Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。

你可以在metaclass中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的都可以。

下面就回归到了我们开篇说的问题如何子在不修改类已经存在的方法的基础上扩展我们的类,答案是 -- 自定义元类

我们获取类中所有以newfunc开头的函数

class NewMetaclass(type):
    def __new__(cls, name, bases, attrs):
        count = 0
        attrs['__NewFunc__'] = []
        for k, v in attrs.items():
            if 'newfunc' in k:
                attrs['__NewFunc__'].append(k)
                count += 1
        attrs['__NewFuncCount__'] = count
        return type.__new__(cls, name, bases, attrs)


class NewFunc(object, metaclass=NewMetaclass):
    def newfunc_a(self):
        return 'a1'

    def new_a(self):
        return 'a2'

    def newfunc_b(self):
        return 'b1'

    def new_b(self):
        return 'b2'


test = NewFunc
count = test.__NewFuncCount__
content = test.__NewFunc__
print(count, content)

'''
运行结果如下:
2 ['newfunc_a', 'newfunc_b']
'''

这里我们解释下几个参数,这里对应着我们上面说的使用type创建类的参数:

type(类名,父类的元祖(在有继承的情况下需要写出来,其他可以为空),包含属性的字典(名称和值))

参数 含义
cls 类的实例对象
name 类的名字
bases 类所有继承的类
attrs 包含属性的字典

我们为什么要使用元类?引用Tim Peters的一句话:
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters

其实我们使用元类更多的就是为了创建API,让功能更加方便
参考文章: 深度理解python中的元类


eval() 函数的使用

eval()官方文档里面给出来的功能解释是:将字符串string对象转化为有效的表达式参与求值运算返回计算结果

语法上:eval(expression,globals=None, locals=None)
返回的是计算结果

参数的含义:

  • expression是一个参与计算的python表达式
  • globals是可选的参数,如果设置属性不为None的话,就必须是dictionary对象了
  • locals也是一个可选的对象,如果设置属性不为None的话,可以是任何map对象了

python是用命名空间来记录变量的轨迹的,命名空间是一个dictionary,键是变量名,值是变量值。

当一行代码要使用变量 x 的值时,Python 会到所有可用的名字空间去查找变量,按照如下顺序:

1)局部名字空间 - 特指当前函数或类的方法。如果函数定义了一个局部变量 x, 或一个参数 x,Python 将使用它,然后停止搜索。

2)全局名字空间 - 特指当前的模块。如果模块定义了一个名为 x 的变量,函数或类,Python 将使用它然后停止搜索。

3)内置名字空间 - 对每个模块都是全局的。作为最后的尝试,Python 将假设 x 是内置函数或变量。

python的全局名字空间存储在一个叫globals()的dict对象中;局部名字空间存储在一个叫locals()的dict对象中。我们可以用print (locals())来查看该函数体内的所有变量名和变量值。

也就是说我们给它传入一个字符串,它会取执行这个字符串所代表的函数

demo:

def change():
    print('this is change func')
funcname = '{}()'.format('change')
print(funcname)
eval(funcname)
'''
结果如下:
change()
this is change func
'''

当然这个函数使用起来也有很大的风险,这里不再详细说明给几个网址大家可以研究下:

Python eval 函数妙用

Python之eval()函数危险性浅析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容