0

I have two python classes

class A:
"""
This is a class retaining some constants
"""
    C=1

class B:
     VAR = None
     def __init__(self):
         b.VAR = A
     def f(self, v=VAR ):
         print(v.C)

clb = B()
clb .f()

AttributeError: 'NoneType' object has no attribute 'C'

So what I am trying to do is populate the B::VAR class variable in the B::init() with the reference of class A, and after that in the B::f() to have access to A::C by using default argument v (that retains VAR). I intend to use v as a default value for the code inside B::f() and if needed to change it when calling the function. Is my scenario possible?

Thank you,

CostinC
  • 21
  • 1
  • 4
  • Please go through the [intro tour](https://stackoverflow.com/tour), the [help center](https://stackoverflow.com/help) and [how to ask a good question](https://stackoverflow.com/help/how-to-ask) to see how this site works and to help you improve your current and future questions, which can help you get better answers. – Prune Apr 18 '21 at 19:12
  • First of all, you need to post a clear question: in this post, you seem to use notation from another language, which has different meaning in Python. Second, it appears that you're unclear on the scoping rules -- I think you're trying to use A.C as if it were a global variable, rather than a class attribute. Third, you don't seem to have picked up the basics of Python classes yet -- the syntax needed within class and instance methods. Please repeat the class tutorials and clarify your question. At the moment, you've moved too far ahead of your current skills to form a solid question here. – Prune Apr 18 '21 at 19:16
  • 2
    For me the issue is clear, it's about how python create default arguments, something that mindblow a lot of beginner unable to understand what happen. Sure, by knowing the issue, the question might be more clear, but for me, this is a "Ok tier" quality. – Dorian Turba Apr 18 '21 at 19:17
  • Does this answer your question? [How to pass a default argument value of an instance member to a method?](https://stackoverflow.com/q/8131942/6045800) – Tomerikoo Apr 18 '21 at 19:38

2 Answers2

0

Yes, this is possible:

class A:
    """
    This is a class retaining some constants
    """
    C = 1


class B:
    VAR = None

    def __init__(self):
        self.VAR = A

    def f(self, v=None):
        if v is None:
            v = self.VAR
        print(v.C)


clb = B()
clb.f()

You issue is that the default arguments v=VAR is an old reference to the B.VAR which is None, not the updated value of the object clb.VAR.

memory diagram

This diagram show that the old version of f() have a default value for v that point to None, because this is computed at the definition of the method, when the class B is defined, before any creation of clb: B object, where VAR is a class attribute. My suggestion is to set v at runtime using the VAR of the object throught self, which is changed in the __init__ to A.

Dorian Turba
  • 3,260
  • 3
  • 23
  • 67
0
class A:
    C = 1


class B:
    VAR = None

    def __init__(self):
        B.VAR = A

    @classmethod
    def f(cls):
        print(cls.VAR.C)


clb = B()
clb.f()

This is another way to do it. However, I'm wondering what it is you're actually trying to do, because this seems really strange

Simon Pratt
  • 165
  • 1
  • 3
  • 10
  • This should works too, but you loose the difference between objects : all object's f() will print the same output. But if this is the expected behavior, this is simplier. – Dorian Turba Apr 18 '21 at 19:24
  • Thanks Simon. In my real life scenario, class A is a "container" for constants that reffer to URIs of a website I have many classes like A for few sites. I select which site i need the constants for via a factory function. This function returns a reference to one of these "container" classes. I use B as a base class for others, with the intend of having each site treated separatelly since they offer completely diferent resources. So in real life instead of B.VAR=A i have B.CONSTANTS = get_constants("siteN") As for B::f(), most of the time i use an URI and sometimes I need an other. – CostinC Apr 18 '21 at 19:45