Can Python classes simplify similar methods for different instance variables?

Asked 2 years ago, Updated 2 years ago, 316 views

Is there a simpler way to write code when you want to define a method that has almost the same functionality for different instance variables, such as the following?

More specifically, add_x(), add_y(), add_z() would be the same method.

Please reply.

 class test:
    def__init__(self):
        self.x = 1
        self.y = 2
        self.z = 3

    default_x(self):
        self.x + = 1

    default_y(self):
        self.y + = 1

    default_z(self):
        self.z+=1

python

2022-09-30 21:59

4 Answers

I tried writing it like this, but it's the same as using the attribute directly (for example, t.x+=1).

 from numbers import Number

class test:
    def__init__(self):
        self.x = 1
        self.y = 2
        self.z = 3

    default (self, attr):
        if attr in vars (self):
            v=getattr(self, attr)
            if isinstance(v, Number):
                setattr(self, attr, v+1)

    def__str__(self):
        return', '.join(f'{a}:{v}'for a, vinvars(self).items())

if__name__=='__main__':
    t = test()
    print(t)

    t.add('x'), t.add('y'), t.add('z')
    print(t)

# execution result
x:1, y:2, z:3
x:2, y:3, z:4


2022-09-30 21:59

Although it is not the specific requirement of your question, copying functions of almost the same function and rewriting only variable names is not beautiful, contrary to DRY principle.
To avoid this, we want to aggregate common actions into the add method.
If you have a hidden request that , you can write to DRY using functools.partialmethod added to version 3.4 or later.

The following sample code creates a __add function that can only be called within the class, and aggregates the process by calling it from the add_x function, etc.
This prevents duplication of functions without changing out-of-class code.

 from functools import partialmethod

class test:
    def__init__(self):
        self.x = 1
        self.y = 2
        self.z = 3

    # private function
    def__add(self, varname):
        setattr(self, varname, getattr(self, varname)+1)

    # Define public functions in partialmethod
    add_x = partialmethod(__add, 'x')
    add_y=partialmethod(__add, 'y')
    add_z = partialmethod(__add, 'z')

    def__str__(self):
        return', '.join(f'{a}:{v}'for a, vinvars(self).items())

t = test()
print(t)
t.add_x()
t.add_z()
print(t)

# execution result
x:1, y:2, z:3
x:2, y:2, z:4


2022-09-30 21:59

The code presented in the example is just a sample, so the solution may be different from the actual problem case, but since x, y, and z are defined as variables, I thought it was a problem that the method could not dynamically change the target.

If you stop defining variables and keep them in dict, you will be able to change the target dynamically.

 class test:
    def__init__(self):
        self.fields = {"x":1, "y":2, "z":3}

    default (self, name):
        self.fields [name] + = 1

t = test()
t.add("x")
t.add("y")
t.add("z")
print(t.fields)


2022-09-30 21:59

Is there a simpler way to write the code?

If you write a decorator that defines a common method, you can simplify the code a little.

*The code to add 1 to the field was based on the code in Metropolis's answer (or rather, it's mostly misused).

# Class decorator to add one method to the field
default_method(cls):
    from numbers import Number
    default (cls, attr):
        if attr in vars (cls):
            v=getattr(cls, attr)
            if isinstance(v, Number):
                setattr(cls, attr, v+1)
    cls.add=add
    defstr(cls):
        return', '.join(f'{a}:{v}'for a, vinvars(cls).items())
    cls.__str = str
    return cls

@add_method
class test:
    def__init__(self):
        self.x = 1
        self.y = 2
        self.z = 3

if__name__=='__main__':
    t = test()
    print(t)
    t.add("x")
    t.add("y")
    t.add("z")
    print(t)


2022-09-30 21:59

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.