对于递归函数,我们可以这样做:
def f(i):
if i<0: return
print i
f(i-1)
f(10)
但有没有办法做以下事情?
class A:
# do something
some_func(A)
# ...
答案 0 :(得分:18)
在Python中,你不能在类体中引用类,尽管在像Ruby这样的语言中你可以这样做。
在Python中,您可以使用类装饰器,但是在初始化类后将调用它。另一种方法可能是使用元类,但这取决于你想要实现的目标。
答案 1 :(得分:8)
由于评估时间的原因,您无法使用您所描述的特定语法。给出的示例函数的作用是在函数体中调用 f(i-1)是因为在函数为函数之前不执行 f 的名称解析实际上叫。此时 f 存在于执行范围内,因为已经评估了该函数。对于类示例,在仍在评估类定义的过程中会查找对类名的引用。因此,它在本地范围内尚不存在。
或者,可以使用类似的元类来完成所需的行为:
class MetaA(type):
def __init__(cls):
some_func(cls)
class A(object):
__metaclass__=MetaA
# do something
# ...
使用此方法,您可以在评估类时对类对象执行任意操作。
答案 2 :(得分:2)
如果你想引用同一个对象,只需使用'self':
class A:
def some_func(self):
another_func(self)
如果要创建同一个类的新对象,只需执行以下操作:
class A:
def some_func(self):
foo = A()
如果您想要访问元类类对象(很可能不是您想要的),请再次执行:
class A:
def some_func(self):
another_func(A) # note that it reads A, not A()
答案 3 :(得分:1)
在类范围内没有办法做到这一点,除非首先将A定义为其他东西(然后some_func(A)会做出与你期望的完全不同的事情)
除非您正在进行某种堆栈检查以向该类添加位,否则您想要这样做似乎很奇怪。为什么不呢:
class A:
# do something
pass
some_func(A)
也就是说,在A之后运行some_func。或者,如果你想以某种方式修改类A,你可以使用类装饰器(它的语法在2.6中添加)或元类。你能澄清你的用例吗?
答案 4 :(得分:1)
不。它在函数中起作用,因为函数内容是在调用时执行的。但是类的内容是在define-time执行的,此时该类还不存在。
这通常不是问题,因为您可以在定义后将其他成员入侵到类中,因此您可以将类定义拆分为多个部分:
class A(object):
spam= 1
some_func(A)
A.eggs= 2
def _A_scramble(self):
self.spam=self.eggs= 0
A.scramble= _A_scramble
然而,想要在自己的定义中调用类上的函数是非常不寻常的。目前还不清楚你要做什么,但是你可能会更好地使用decorators(或相对较新的class decorators)。
答案 5 :(得分:1)
如果你想做一点hacky的事情
class A(object):
...
some_func(A)
如果你想做更复杂的事情,你可以使用元类。元类负责在完全创建类对象之前对其进行操作。模板将是:
class AType(type):
def __new__(meta, name, bases, dct):
cls = super(AType, meta).__new__(meta, name, bases, dct)
some_func(cls)
return cls
class A(object):
__metaclass__ = AType
...
type
是默认的元类。元类的实例是类,因此__new__
返回(在这种情况下)A
的修改实例。
有关元类的详细信息,请参阅http://docs.python.org/reference/datamodel.html#customizing-class-creation。
答案 6 :(得分:1)
请记住,在Python中,类型提示仅用于自动代码完成,因此它可帮助IDE推断类型并在运行时警告用户。在运行时,类型提示几乎从未使用过(在某些情况下除外),因此您可以执行以下操作:
from typing import Any, Optional, NewType
LinkListType = NewType("LinkList", object)
class LinkList:
value: Any
_next: LinkListType
def set_next(self, ll: LinkListType):
self._next = ll
if __name__ == '__main__':
r = LinkList()
r.value = 1
r.set_next(ll=LinkList())
print(r.value)
您可以看到IDE成功地推断出它的类型为LinkList
:
注意:由于next
可以是None
,因此在类型中暗示这一点会更好,我只是不想混淆OP。
class LinkList:
value: Any
next: Optional[LinkListType]
答案 7 :(得分:1)
也许您可以尝试致电__class__
。
现在,我正在编写一个从同一类中调用类方法的代码。
到目前为止,一切正常。
我正在使用类似以下的方法创建类方法:
@classmethod
def my_class_method(cls):
return None
然后使用以下电话进行呼叫:
x = __class__.my_class_method()
答案 8 :(得分:0)
你想要达到什么目的?可以使用元类来访问类以调整其定义,但不建议这样做。
您的代码示例可以简单地编写为:
class A(object):
pass
some_func(A)
答案 9 :(得分:0)
如果它实际上在范围内,可以引用其体内类的名称(如内部方法定义)...如果它在顶层定义,它将是什么。 (在其他情况下可能不会,因为Python的范围怪癖!)。
为了说明范围问题,请尝试实例化Foo:
class Foo(object):
class Bar(object):
def __init__(self):
self.baz = Bar.baz
baz = 15
def __init__(self):
self.bar = Foo.Bar()
(它会抱怨没有定义全球名称'Bar'。)
另外,有些东西告诉我你可能想要查看类方法:docs on the classmethod function(用作装饰器),a relevant SO question。 编辑:好的,所以这个建议可能根本不合适......只是我在阅读你的问题时首先想到的是像替代构造函数等等。如果更简单的东西适合你的需要,避开@classmethod
怪异。 : - )
答案 10 :(得分:0)
如果目标是使用类作为参数来调用函数some_func
,则答案是将some_func
声明为类装饰器。请注意,在初始化类之后,将调用类装饰器。它将作为参数修饰的类传递给它。
def some_func(cls):
# Do something
print(f"The answer is {cls.x}")
return cls # Don't forget to return the class
@some_func
class A:
x = 1
如果要将其他参数传递给some_func
,则必须从装饰器返回一个函数:
def some_other_func(prefix, suffix):
def inner(cls):
print(f"{prefix} {cls.__name__} {suffix}")
return cls
return inner
@some_other_func("Hello", " and goodbye!")
class B:
x = 2
可以构造类装饰器,这导致它们以相反的顺序被调用:
@some_func
@some_other_func("Hello", "and goodbye!")
class C:
x = 42
其结果是:
# Hello C and goodbye!
# The answer is 42
答案 11 :(得分:0)
如果我正确理解了您的问题,则可以通过将类型注释放在引号中来引用类A中的类A。这称为前向参考。
class A:
# do something
def some_func(self, a: 'A')
# ...
请参阅下面的参考文件
答案 12 :(得分:0)
这里的大部分答案似乎都过时了。来自python3.7:
from __future__ import annotations
示例:
$ cat rec.py
from __future__ import annotations
class MyList:
def __init__(self,e):
self.data = [e]
def add(self, e):
self.data.append(e)
return self
def score(self, other:MyList):
return len([e
for e in self.data
if e in other.data])
print(MyList(8).add(3).add(4).score(MyList(4).add(9).add(3)))
$ python3.7 rec.py
2
答案 13 :(得分:-1)
类中的大多数代码都在方法定义中,在这种情况下,您只需使用名称A
。