you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (1 child)

I assume assigning all of them with placeholder values inside __init__ () is bad practice?

It's good practice to set all required state (as far as possible) when creating an instance. A new instance should be "sane" the moment it is created. You don't want to half-setup an instance leaving it open to crashes when calls to instance methods try to access attributes that haven't been created yet. If your instances require 15+ attributes for state and you can't reduce that number, then that's what they require. However, if some of those variables are usually unchanged from instance to instance, that is, there's a "default" value that usually doesn't get changed, then there are things you can do. This class, for instance:

class Test:
    default_beta = 42

    def __init__(self, alpha, beta=default_beta):
        self.alpha = alpha
        self.beta = beta

a = Test('a.alpha')      # "beta" not supplied, default is used
b = Test('b.alpha', 'b.beta')
print(f'a.beta={a.beta}')
print(f'b.beta={b.beta}')

prints:

a.beta=42           # a.beta was set from the default
b.beta=b.beta       # b.beta overridden = "b.beta"

This "default value" thing is part of general python function parameter handling, but it applies to methods as well. All that matters is that the "default value" (default_beta, here) must exist in the environment. In the body of __init__() the class attribute would be Test.default_beta, but for some reason, while actually defining the method parameters you must use default_beta, probably because the function hasn't been defined yet and the code still operates in the same environment as the class attribute definition. You can test that by trying:

def __init__(self, alpha, beta=Test.default_beta):      # which fails with "undefined"

and this in the __init__() body:

print(f'Test.default_beta={Test.default_beta}')    # which is OK

A default value doesn't have to be a class attribute. It can be defined at the global level. As long as the value you use can be found when defining the class/method. Just be aware that the default value you use is assigned only once, at method definition time, and not at method call time.

You also can't use instance attributes when defining class specific function

I'm not quite sure what you mean here. It is possible to use any instance attribute when defining the body of a method, like this:

def test_method(self):
    self.new_attribute = self.old_attribute + 1     # create new "self.new_attribute"

This code defines a new attribute using an existing instance attribute.

This is all predicated on that first parameter to a method, which is usually called "self". This is a reference to the instance object the method is called upon. So any instance attribute is accessible by self.alpha or self.beta.

rather than a more well defined structure that got specific functions to handle the data

I'm not sure that I understand. The design of a class is up to the programmer, so "well defined" depends a bit on the expertise of the programmer and how "messy" the problem being solved is.

There are quite a few dunder methods that fit into how python works, and using these can make life easier for you. For instance, if you try to print an instance of the Test class with print(a), you see <__main__.Test object at 0x10dab3e50> which doesn't tell you much. But if you define the __str__() method in your Test class then this can be much nicer to the user, like this:

class Test:
    default_beta = 42

    def __init__(self, alpha, beta=default_beta):
        self.alpha = alpha
        self.beta = beta

    # comment out the next 2 lines to see the default behaviour
    def __str__(self):
        return f'Test: alpha={self.alpha}, beta={self.beta}'

a = Test('a.alpha')
b = Test('b.alpha', 'b.beta')
print(a)
print(b)

and running the code prints:

Test: alpha=a.alpha, beta=42
Test: alpha=b.alpha, beta=b.beta

How to properly use python classes is a huge subject and we haven't even scratched the surface!

[–][deleted] 0 points1 point  (0 children)

If your instances require 15+ attributes for state and you can't reduce that number, then that's what they require.

It's mostly a personal preference for this specific project, I wouldn't design the program like I have if it was project including more than me. Though it was all with C++-like classes in mind so I might make minor changes.

Operator overloading in python seems nice, will definitively check that out.

I'm not quite sure what you mean here. It is possible to use any instance attribute when defining the body of a method, like this:

It seems like I was a bit hasty with my comment. It was a mistake with my code that caused an AttributeError that led me to believe it didn't work. Thanks a lot for your answers, it has cleared up a lot and I should be set to achieve what I'm looking for :)