Как определить поле класса в Python, который является экземпляром класса? - PullRequest
2 голосов
/ 23 июня 2019

Я хочу получить конкретный экземпляр класса в пространстве имен класса.В C # это будет выглядеть так:

public struct Foo
{
    public readonly static Bar = new Foo();
}

Единственная идея, которую я имею, - назначить экземпляр сразу после определения класса (monkeypatch):

class Foo:
    def __init__(self, spam):
        self.spam = spam
Foo.bar = Foo(42)

Но я хочу предоставитьэкземпляр в определении класса, например:

class Foo:
    ...
    bar = Foo(42)

и интерфейс, подобный следующему:

from foo import Foo
bar = Foo.bar

Последняя строка в определении дает синтаксическую ошибку, поскольку Foo еще не определен.Есть ли способ преодолеть это ограничение, кроме класса monkeypatching?

Ответы [ 4 ]

3 голосов
/ 29 июня 2019

Запрошенная функциональность может быть достигнута с помощью объекта пользовательского дескриптора ( doc ):

class static_property:
    def __init__(self, getter):
        self.__getter = getter

    def __get__(self, obj, objtype):
        return self.__getter(objtype)

    @staticmethod
    def __call__(getter_fn):
        return static_property(getter_fn)

class A:
    _bar = None

    def __init__(self, spam):
        self.spam = spam

    @static_property
    def bar(cls):
        if cls._bar is None:
            cls._bar = A(10)
        return cls._bar

print('A.bar={} A.bar.spam={}'.format(A.bar, A.bar.spam))

a = A(20)
print('a.bar={} a.bar.spam={} a.spam={}'.format(a.bar, a.bar.spam, a.spam))

Отпечатки:

A.bar=<__main__.A object at 0x7f0ab5e41eb8> A.bar.spam=10
a.bar=<__main__.A object at 0x7f0ab5e41eb8> a.bar.spam=10 a.spam=20
0 голосов
/ 29 июня 2019

Если вы хотите использовать метаклассы для этого, вы можете использовать следующее. Я действительно не знаю, почему вы хотите достичь этого, или метод, который я представляю, хорош, но тем не менее он работает хорошо.

class Meta(type):
    def __new__(cls, name, bases, dct):
        print(cls,name, bases, dct)
        x = super(Meta, cls).__new__(cls, name, bases, dct)
        x.bar = x(46) //create the bar for the Foo
        return x




class Foo:
    __metaclass__ = Meta
    def __init__(self, spam):
        self.spam = spam

Для этого просто создайте именованный атрибут bar для Foo при создании объекта для класса. Я думаю, что код не требует пояснений

0 голосов
/ 23 июня 2019

Вы можете сделать это с помощью внешнего метода, например: -

class Foo:
    def __init__(self,data):
        self.data = data

    def update(self,value):
        self.bar = Foo(value)
        self.show()

    def show(self):
        print(self.bar.data,"Updated Successfully")


if __name__ == "__main__":
    node = Foo(None)

    node.update(10)
    node.update(20)
    node.update("Hello World")


Вывод этого кода будет выглядеть следующим образом: -

10 Updated Successfully
20 Updated Successfully
Hello World Updated Successfully

Вы можете напрямую использовать панель(новый экземпляр) через: -

#node.bar.data
print(node.bar.data)

вывод будет последним обновленным значением, т.е.: -

Hello World
0 голосов
/ 23 июня 2019

Для работы на уровне класса вам нужен декоратор @classmethod.

class Foo:
   # Class variable
   Bar = None 

   def __init__(self, value): 
      self.val = value 
      Foo.update_Bar(self) 

   @classmethod 
   def update_Bar(cls, new_instance): 
      cls.Bar = new_instance

print(Foo.Bar is None)
foo1 = Foo(10)
print(Foo.Bar.val)
foo2 = Foo(20)
print(Foo.Bar.val)
print(foo1.Bar.val)
...