Python反射和可调用对象

3

我有一个双重问题。

>>> class One(object):
...     pass
... 
>>> class Two(object):
...     pass
... 
>>> def digest(constr):
...     c = apply(constr)
...     print c.__class__.__name__
...     print constr.__class__.__name__
... 
>>> digest(Two)
Two
type

如何创建对象'Two'? constr()或c()都不起作用,而且似乎apply会将其转换为一种类型。

当您将一个类而不是一个实例传递到方法中时会发生什么?


我认为像apply这样的函数已经过时或不被视为现代用法的一部分。请查看我的回复中的指针。 - pyfunc
4个回答

5

类是高级对象,因此您可以像这样简单地传递它们:

def createMyClass ( myClass ):
    obj = myClass()
    return obj

class A ( object ):
    pass

>>> x = createMyClass( A )
>>> type( x )
<class '__main__.A'>

1
这与调用 x = myClass() 有何不同?也许我在这里缺少了什么。 - pyfunc
@pyfunc:当然,在这个例子中并没有什么不同;关键是你可以将类传递给函数,然后由函数进行实例化(以及任何任意的操作,比如预设一些值),最后简单地返回对象。因为显然这就是 OP 试图做的事情。 - poke

1

只是另一个例子:

def InstanceFactory(classname):
   cls = globals()[classname]
   return cls() 

class A(object):
   def start(self):
       print "a.start"

class B(object):
   def start(self):
        print "b.start"

InstanceFactory("A").start()
InstanceFactory("B").start()

如果该类属于另一个模块:
def InstanceFactory(modulename, classname):
    if '.' in modulename:
        raise ValueError, "can't handle dotted modules yet"
    mod = __import__(modulename)
    cls = getattr(mod, classname]
    return cls() 

Demas,我听说过Python中的全局变量,但从未真正掌握它。globals()在这里有什么作用? - jbcurtin
另外,你回答了我接下来的谷歌问题。如何从另一个模块导入。谢谢! - jbcurtin
@jbcurtin,去谷歌搜索一下。这是一种非常不标准的导入方式。当你只知道运行时要导入的名称时,它很有用。首先学习标准的“import”。 - aaronasterling
globals() 表示当前全局符号表的字典。 - ceth

1
如何创建对象“Two”? neither constr() nor c() work; and it seems that apply turns it into a type.
上述评论是针对以下代码的:
>>> def digest(constr):
...     c = apply(constr)
...     print c.__class__.__name__
...     print constr.__class__.__name__

apply(已弃用:请参见@pyfunc的答案)确实不会将类Two转换为类型:它已经是一个类型。

>>> class Two(object): pass
... 
>>> type(Two)
<type 'type'>

类是一等对象:它们是type的实例。如果查看下一个示例,这就有意义了。

>>> two = Two()
>>> type(two)
<class '__main__.Two'>

你可以清楚地看到类作为一种类型的功能,因为它可以从type返回。这是另一个例子。

>>> Three = type('Three', (Two, ), {'foo': 'bar'})
>>> type(Three)
<type 'type'>
>>> three = Three()
>>> type(three)
<class '__main__.Three'>

你可以看到type是可实例化的类。它的构造函数接受三个参数: 类名,一个基类元组和包含类属性的字典。它返回一个新的type即类。 至于您的最后一个问题, 引用: “当您将类而不是实例传递到方法中时会发生什么?” 你需要更具体一些。类只是type的实例,因此是一级对象。如果我将类传递给方法,就像问如果我将整数传递给方法会发生什么一样:这完全取决于方法期望什么。

“适当的变量名应该是cls” - 呃,为什么?它只是一个变量,你可以随便起名字。 - poke
Aaron,你提到的第二个问题(将一个类传递给方法)实际上只是一个愚蠢的问题,只是为了确保幕后没有发生任何事情。(.net背景 :) 你回答说这与传递int或string相同。谢谢! - jbcurtin
@poke def __init__(this, foo): this._foo = foo + 1。众所周知,变量应该根据其含义进行命名,如果无法做到这一点,则按照惯例进行命名。类似于cls的名称通常用于类。 - aaronasterling
@poke 仔细想想,可以传递一个工厂函数。已修复。 - aaronasterling

0

我很困惑。apply() 自 2.3 版本起不是已经被弃用了吗?

我们不再需要这个了。

apply(f, args, kwds)  -->  f(*args, **kwds)

其他一些函数在现代使用中已被移除或被视为过时:

  1. buffer()
  2. coerce()
  3. 和 intern()

只需使用:Classname() 来创建一个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接