Self Referencing Class Definition in python

后端 未结 6 1915
野的像风
野的像风 2020-12-01 11:00

is there any way to reference a class name from within the class declaration? an example follows:

class Plan(SiloBase):
    cost = DataField(int)
    start =         


        
相关标签:
6条回答
  • 2020-12-01 11:19

    Sine Python 3.7 and PEP 563 there's a way to do that.

    Add the import

    from __future__ import annotations
    

    and the following code will work

    from __future__ import annotations
    from typing import List
    
    class Refer(object):
        def __init__(self, x: Plan):
            self.x: Plan = x
    
    class Plan(object):
        def __init__(self):
            pass
        subPlan: Refer(Plan())
    
    0 讨论(0)
  • 2020-12-01 11:19

    No, you can't do that. Think about what would happen if you did this:

     OtherPlan = Plan
     other_plan = OtherPlan()
    

    At instantiation of other_plan, what is the name of the class?

    Anyway, this sort of thing is best done in the __new__ method, which takes a cls parameter referring to the class.

    0 讨论(0)
  • 2020-12-01 11:28

    One can do this with the following code in python3. We use cached_property to only evaluate the Player.enemyPlayer once and then return the cached result. Because our value comes from a function, it is not evaluated when the class is first loaded.

    class cached_property(object):
        # this caches the result of the function call for fn with no inputs
        # use this as a decorator on function methods that you want converted
        # into cached properties
        def __init__(self, fn):
            self._fn = fn
    
        def __set_name__(self, owner, name):
            # only works in python >= 3.6
            self.name = name
            self._cache_key = "_" + self.name
    
        def __get__(self, instance, cls=None):
            if self._cache_key in vars(self):
                return vars(self)[self._cache_key]
            else:
                result = self._fn()
                setattr(self, self._cache_key, result)
                return result
    
    
    class Player:
        @cached_property
        def enemyPlayer():
            return Player
    
    0 讨论(0)
  • 2020-12-01 11:31

    i've got a metaclass that reads this information and does some setup

    Most frameworks that use metaclasses provide a way to resolve this. For instance, Django:

    subplan = ForeignKey('self')
    

    Google App Engine:

    subplan = SelfReferenceProperty()
    

    The problem with solutions like tacking an additional property on later or using __new__ is that most ORM metaclasses expect the class properties to exist at the time when the class is created.

    0 讨论(0)
  • 2020-12-01 11:39

    I understand what is happening, the name of the class isn't in scope inside the class.

    Not exactly. The name of the class is not yet defined when defining it's contents (e.g. scope).

    0 讨论(0)
  • 2020-12-01 11:42

    Try this:

    class Plan(SiloBase):
        cost = DataField(int)
        start = DataField(System.DateTime)
        name = DataField(str)
        items = DataCollection(int)
    
    Plan.subPlan = ReferenceField(Plan)
    

    OR use __new__ like this:

    class Plan(SiloBase):
    
        def __new__(cls, *args, **kwargs):
            cls.cost = DataField(int)
            cls.start = DataField(System.DateTime)
            cls.name = DataField(str)
            cls.items = DataCollection(int)
            cls.subPlan = ReferenceField(cls)
            return object.__new__(cls, *args, **kwargs)
    
    0 讨论(0)
提交回复
热议问题