我的课程如下:
class MyClass(object):
int = None
def __init__(self, *args, **kwargs):
for k, v in kwargs.iteritems():
setattr(self, k, v)
def get_params(self):
return {'int': random.randint(0, 10)}
@classmethod
def new(cls):
params = cls.get_params()
return cls(**params)
我希望能够做到:
>>> obj = MyClass.new()
>>> obj.int # must be defined
9
我的意思是不创建
MyClass
的新实例,但显然事情没那么简单,因为调用 MyClass.new()
会抛出 TypeError: unbound method get_params() must be called with MyClass instance as first argument (got nothing instead)
有什么办法可以实现这一点吗? 谢谢。
不,您不能也不应该从没有实例的类中调用实例方法。这将是非常糟糕。但是,您可以从实例方法调用类方法。选项有
get_param
一个类方法并修复对其的引用__init__
调用get_param
,因为它是一个实例方法此外,您可能对 AttrDict 感兴趣,因为这看起来像您正在尝试做的事情。
当将实例方法视为实例方法并将类添加为实例时,您可以使用类方法调用实例方法。 IMO,这确实是不好的做法,但它解决了你的问题。
@classmethod
def new(cls):
params = cls.get_params(cls)
return cls(**params)
您需要将
cls
从类方法传递给实例方法,如下所示,以便从类方法调用实例方法:
class Person:
def test1(self):
print("Test1")
@classmethod
def test2(cls):
cls.test1(cls) # Needed to pass "cls"
obj = Person()
obj.test2()
输出:
Test1
虽然有针对OP情况的特定答案,合理地建议不要从类中调用实例方法,但这是有效的,因为(我可以推断出)用例似乎不支持类似的解决方案。
我有一个正在寻找该解决方案的用例,但因为这是不可能的,或者是 hacky,所以我采用了这种方式。我认为这可能是最短的合法路线,但如果能得到任何修正就太好了。
class MyClass:
context = {"a": 1}
def __init__(self, details):
self.details = details
def get(self, key):
val = self.details.get(key)
if val is None:
val = self.context.get(key)
return val
my = MyClass({"a": 2})
print(my.get("a"))
print(MyClass.get("a"))
从实例运行它,但不能从类运行。
"a"
参数被分配给 self
参数,Python 抱怨没有为 key
参数留下任何参数。
2
Traceback (most recent call last):
File "myclass.py", line 17, in <module>
print(MyClass.get("a"))
TypeError: MyClass.get() missing 1 required positional argument: 'key'
需要单独的同名类方法和实例方法。
但是在同一个对象上定义两个同名的方法只能意味着后面定义的方法会覆盖前面定义的方法。一个对象肯定不会支持同名的两个不同属性。
解决方案是在不同的对象上使用两个具有相同名称的单独方法。一种是普通的类方法,一种是普通的实例方法。
为了解决这个问题,可以引入一个子类,以便子类可以在不同的对象上重新定义同名的方法。 Python OO 负责适当地调用它们。
class MyClass:
context = {"a": 1}
@classmethod
def get(cls, key):
val = cls.context.get(key)
return val
class MySubClass(MyClass):
def __init__(self, details):
self.details = details
def get(self, key):
val = self.details.get(key)
if val is None:
val = super().get(key)
return val
my = MySubClass({"a": 2})
print(my.get("a"))
print(MyClass.get("a"))
这个解决方案有效。 该类的单例行为仍然可以使用,但不是创建该类的实例,而是使用子类的实例。
这意味着定义了一个额外的类,并且意味着该方法的实现被分散,但这对于处理类和实例之间的差异似乎是必要且适当的。