Python 鸭子类型类,ABC,iheritance,新__

Python 鸭子类型类,ABC,iheritance,新__,python,class,python-2.7,abc,Python,Class,Python 2.7,Abc,我正在编写一个测试系统,其中包括使用数据源。在运行时,它将读取一组仪器,但对于后端的测试和开发,我希望它读取一个文件,或返回随机数。在未来,我知道需要创建新的数据源,其操作还未知。我正在尝试建立一个系统,这样我就可以进入一个新的部门,而不必回来支持它,所以我想成为一个Pythonic,留下尽可能少的惊喜。一个主要的要求是为源代码提供一致的API,而ABC似乎是这里显而易见的选择。源代码之间没有足够的公共性,在基类中没有任何值得继承的块 我不想要一个选择要做什么的大型源代码模块,我想要一个可以从中

我正在编写一个测试系统,其中包括使用数据源。在运行时,它将读取一组仪器,但对于后端的测试和开发,我希望它读取一个文件,或返回随机数。在未来,我知道需要创建新的数据源,其操作还未知。我正在尝试建立一个系统,这样我就可以进入一个新的部门,而不必回来支持它,所以我想成为一个Pythonic,留下尽可能少的惊喜。一个主要的要求是为源代码提供一致的API,而ABC似乎是这里显而易见的选择。源代码之间没有足够的公共性,在基类中没有任何值得继承的块

我不想要一个选择要做什么的大型源代码模块,我想要一个可以从中选择的小型独立源代码,这样就可以不用管那些可以工作的旧源代码了。问题是,我希望能够选择要与参数一起使用的源,以便可以运行相同的测试脚本并轻松切换源。我完全忘记了我是如何遇到
\uuuu new\uuuu
,但这并不明显,很少有人听说过。它起作用了。但我想做的事情是显而易见的还是像蟒蛇一样的?有没有一种我的同事更熟悉的方法?我应该指出,我现在的元编程水平略高于我的舒适水平,所以任何更复杂的事情都可能会在我头上呼啸而过

from abc import ABCMeta, abstractmethod
import random

class BaseSource:
    __metaclass__ = ABCMeta

    @abstractmethod
    def get(self):
        pass    

class ManualSrc(BaseSource):
    def get(self):
        return float(raw_input('gimme a number - '))

class RandomSrc(BaseSource):
    def get(self):
        return random.random()

class Source(BaseSource):
    """generic Source choice"""
    def __new__(BaseSource, choice):
        if choice == 0:
            return ManualSrc()
        elif choice == 1:
            return RandomSrc()
        else:
            raise ValueError('source choice parameter {} not valid'.format(choice))

if __name__ == '__main__':
    for use_src in range(4):
        print 'using source choice {}'.format(use_src)
        src = Source(use_src)
        print src.get()

这不是一个很好的答案。。。几乎是一个代码审查,所以我可能会等待不同的意见

我(个人来说……这里没有客观的确认)看到了
\uuuu new\uuuuu
通常用于在使用自己的
\uuu元类时创建
类的实例(检查S.O.和Python的元类)

在您的示例中,因为如果您添加了一个新的源代码(一个新的
WhateverSrc()
thingy),您将需要编辑
source
类的
\uuuuuuuuuuu
方法,所以使用从
BaseSource
继承的类来创建其他源代码看起来有点过分了。另外,问题是:
Source
类真的是
BaseSource
?据我所知,不是真的<代码>源代码
是源代码工厂,对吗?如果是这样的话,你可以尝试,如果你愿意的话(链接是我在第二段中提到的答案,所以我没有太多的理由去“找到”它),尽管工厂对我来说听起来非常Java风格。再一次,这里只是个人意见

我将使用一个简单的
create\u Source
方法,而不是像您那样使用
Source(BaseSource)
类:

## [ . . . ]

class RandomSrc(BaseSource):
    def get(self):
        return random.random()

def create_source(choice):
    if choice == 0:
        return ManualSrc()
    elif choice == 1:
        return RandomSrc()
    else:
        raise ValueError('source choice parameter {} not valid'.format(choice))

if __name__ == '__main__':
    for use_src in range(4):
        print 'using source choice {}'.format(use_src)
        src = create_source(use_src)
        print src.get()
如果您需要新的源代码,您可以编辑
create\u source
方法,如:

## [ . . . ]

class RandomSrc(BaseSource):
    def get(self):
        return random.random()

class WhateverSrc(BaseSource):
    def get(self):
        return "Foo Bar??"

def create_source(choice):
    if choice == 0:
        return ManualSrc()
    elif choice == 1:
        return RandomSrc()
    elif choice == 2:
        return WhateverSrc()
    else:
        raise ValueError('source choice parameter {} not valid'.format(choice))
甚至更多。。。完全忘记
@abstractmethod
,只需要获得一堆或常规的具体类。如果有人创建了一个新的
*Src
类,而该类没有实现
get
方法,那么这个人无论如何都会看到一个非常描述性的失败

import random

class ManualSrc(object):
    def get(self):
        return float(raw_input('gimme a number - '))

class RandomSrc(object):
    def get(self):
        return random.random()

class BreakingSrc(object):
    pass

def create_source(choice):
    if choice == 0:
        return ManualSrc()
    elif choice == 1:
        return RandomSrc()
    elif choice == 2:
        return BreakingSrc()
    else:
        raise ValueError('source choice parameter {} not valid'.format(choice))

if __name__ == '__main__':
    for use_src in range(4):
        print 'using source choice {}'.format(use_src)
        src = create_source(use_src)
        print src.get()
这将产生:

using source choice 0
gimme a number - 1
1.0
using source choice 1
0.702223268052
using source choice 2
Traceback (most recent call last):
  File "./stack26.py", line 28, in <module>
    print src.get()
AttributeError: 'BreakingSrc' object has no attribute 'get'
编辑1

OP()在对这个答案的评论中问道,将非类的东西大写,或调用非大写的名称来实例化特定对象,哪个会更混乱

在开始之前,以下示例充分利用了内置和函数。在继续之前,你应该确保你熟悉他们的工作

对我来说(这只是我的观点,因为在Python中,大写或非大写的函数名在语法上都是可以的),使用大写字母的函数会更容易混淆。请记住,您实际上并没有返回一个类(尽管您可以,因为
class
(es)也是类型
type
的实例),您返回的是一个实例,并且返回实例的函数(根据大小写)没有错。日志模块就是这样做的,例如:

>>> import logging
>>> log = logging.getLogger('hello')
>>> vars(log)
{'name': 'hello', 'parent': <logging.RootLogger object at 0x17ce850>, 'handlers': [], 'level': 0, 'disabled': 0, 'manager': <logging.Manager object at 0x17ce910>, 'propagate': 1, 'filters': []}
>>> type(log)
<class 'logging.Logger'>
我想你刚才看到了,你认为那里发生了什么?您可能认为您正在创建一个类a的空实例,并将其
x
属性设置为
5
,因此您希望
打印输出
a.x是5
,对吗

错。下面是正在发生的事情(完全正确的Python):

因此
a
实际上是
类B
的一个实例,由于Python提供了“屏蔽”getter和setter的能力,我正在创建一个完全不直观的可怕的混乱。在与Python打交道时,您会听到很多次,事实上您可以做一些事情并不意味着您应该做。我个人总是引用本叔叔的话:权力越大,责任越大(好吧……或者,我觉得引用本叔叔的话越酷,胡说!!?:-D

这就是说,你可能想在中创建一个用户,我相信有很多知识渊博的人能够比我更好地回答这类问题

哦,在我之前提到过,
class
也是一个例子。等等,Wooot??是的。函数也是实例!!。看看这个:

>>> class C(object):
...     pass
... 
>>> vars(C)
dict_proxy({'__dict__': <attribute '__dict__' of 'C' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None})
>>> type(C)
<type 'type'>
>>> def get_me_a_c_class():
...     return C
... 
>>> my_class = get_me_a_c_class()
>>> my_instance = my_class()
>>> type(my_instance)
<class '__main__.C'>
>>> type(get_me_a_c_class)
<type 'function'>
>>> vars(get_me_a_c_class)
{}
>>> get_me_a_c_class.random_attribute = 5
>>> print "Did I just put an attribute to a FUNCTION??: %s" % get_me_a_c_class.random_attribute
Did I just put an attribute to a FUNCTION??: 5
>>C类(对象):
...     通过
... 
>>>vars(C)
dict_代理({“dict_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>类型(C)
>>>def get_me_a_c_class():
...     返回C
... 
>>>my_class=get_me_a_c_class()
>>>my_实例=my_类()
>>>类型(我的_实例)
>>>键入(获取我的课程)
>>>VAR(给我上一节课)
{}
>>>get\u me\u a\u c\u class.random\u属性=5
>>>打印“我是否刚将属性添加到函数中??%s”%get\u me\u a\u c\u class.random\u属性
我是不是刚给函数添加了一个属性??:5
在我处理Python的几年中,我发现它严重依赖程序员的常识。当我开始犹豫是否相信
 a = A()
 a.x = 5
 print "a.x is %s" % a.x
class B(object):
    def __init__(self):
        self.x = 10
    @property
    def x(self):
        return "I ain't returning x but something weird, and x is %s... FYI"\
                % self._x
    @x.setter
    def x(self, x):
        self._x = int(self._x if hasattr(self, '_x') else 0 + 2 * x)

def A():
    return B()
>>> class C(object):
...     pass
... 
>>> vars(C)
dict_proxy({'__dict__': <attribute '__dict__' of 'C' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None})
>>> type(C)
<type 'type'>
>>> def get_me_a_c_class():
...     return C
... 
>>> my_class = get_me_a_c_class()
>>> my_instance = my_class()
>>> type(my_instance)
<class '__main__.C'>
>>> type(get_me_a_c_class)
<type 'function'>
>>> vars(get_me_a_c_class)
{}
>>> get_me_a_c_class.random_attribute = 5
>>> print "Did I just put an attribute to a FUNCTION??: %s" % get_me_a_c_class.random_attribute
Did I just put an attribute to a FUNCTION??: 5