Python Forum
ABC Module and @property decorator, Pythonic Way?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
ABC Module and @property decorator, Pythonic Way?
#1
Greetings,

I just started learning Python about 3 months ago. I wanted to know what the consensus is when using the
@property
method and the module

from abc import ABC, abstractmethod
# abc is a builtin module, we have to import ABC and abstractmethod

class Animal(ABC): # Inherit from ABC(Abstract base class)
    @abstractmethod  # Decorator to define an abstract method
    def feed(self):
        pass
Someone pointed out to me that the
@property
decorator has a lot going on under the hood. But, if it serves the purpose of getting the value of a property, why not use it?

The same with the ABC module.

I have developed in other languages and you can use set(var) and get(var) on any property in a class. These methods are inherited right from object.

Can someone shed some light on why these should or should not be used? Do these coding standards follow the "Pythonic" way? I am not being facetious.

Any feedback would be much appreciated.
Reply
#2
I think the "Pythonic" way to get and set attributes is to use "value = instance.attribute" and "instance.attribute = value". There is no protection for attributes (no private or protected), so you may as well admit this and make shorter code.

I think properties come into play when you want getting or setting an attribute to not only get or set the value, but also execute code associated with getting or setting the attribute value. I write a lot of signal processing code. I have noisy inputs and I want to filter out any content above a certain frequency. My Python class for doing the filtering has a "frequency" attribute, but my filter code does not use this value. When the "frequency" attribute is set I want my code to use the "frequency" value and the sample rate value and additional information to compute coefficients for my IIR or FIR filter.
@property
def frequency(self):
    return self._frequency

@frequency.setter
def frequency(self, value):
    self._frequency = value
    self.compute_coeffficients()
Other examples would be when working with hardware, or networks, or databases. Anything where getting or setting a parameter value results in something more than getting or setting the value of an instance variable. Properties can also execute code when an attribute is deleted. All this can be done with get(), set() and delete() methods, but that hides the underlying "attibuteness" of the parameter. In my example, "frequency" is the interesting attribute of the filter. I don't care about the filter coefficients. Theyis only important to the software. I want to know that if I look at a bode plot the amplitude response will be -3db at "frequency". The "attributeness" is made more obvious when the setting syntax is:
filter.frequency = 60
as opposed to:
filter.set_frequency(60)
even though they end up doing the same thing.

I think the purpose of ABC is described very well in the PEP https://www.python.org/dev/peps/pep-3119/.
Reply
#3
How would someone go about using set, and get to use on properties? Also, are your
_properties
protected or private? I was told that one '-' is protected and two is private.

You were the one that responded to my other post based on this topic. You made some good points, so I decided to post another question regarding them.

The ABC acts more like an Interface than it does an abstract class. In other languages, abstract classes do not force you to implement methods. Interfaces do.

After all, a decorator is nothing more than a wrapper to the function it is worked on. Maybe there is a way to view the source of the property, take what I need and make my own
@property
. No idea at this point. I'm just focusing on the basics.

Always nice hearing from you.
Thanks
Reply
#4
should we always start our instance variables privately?

class Person:
    def __init__(self, age, height, weight):
        self.__age = age
        self.__height = height
        self.__weight = weight
We can't really hide private variables.
p1 = Person(34, 5, 165)
p1.__age #generates an error
However, if I want to get and set instance variables, without methods, I would just do this.

class Person:
    def __init__(self, age, height, weight):
        self.age = age
        self.height = height
        self.weight = weight
p1 = Person(34, 5, 165)
p1.age #works fine
No get or set methods, nice and easy.
Reply
#5
One underscore is a convention that says this should be treated as a protected attribute. Of course it is not a protected attribute. I can write object._properties and all that happens is VSCode says I shouldn't do that.

Double underscore is a different thing. Using __attribute actually changes the generated code. Double underscore uses name mangling to create an attribute that is unique to the class. These are sometimes referred to as fully private variables, but again there is no real protection here.
class MyClass():
    def __init__(self):
        self._private = 1
        self.__super_private = 2

x = MyClass()
print(x._private, x._MyClass__super_private)
Output:
1 2
This name mangling protects against somebody subclassing MyClass and accidentally overriding an attribute.
class A():
    def __init__(self):
        self.__x = 1

    def x(self):
        return self.__x

class B(A):
    def __init__(self):
        super().__init__()
        self.__x = 2
Output:
1 1 1 2
Notice that B.x() returns 1, not 2. Since x() is inherited from A, it uses A.__x, even though it is being referenced through B.

Using double underscores should be reserved for when you need the attribute to be associated with a particular class and not be inherited by subclasses, not because your C++/Java experience makes you want to control visibility. Use single underscores for that and rely on the gentlemen's agreement.
Reply
#6
I hear what you're saying. Forget about true encapsulation when using protected properties and methods. And with private, it will give you an error if you try to access it but you just showed how you can get around it.

I understand the logic. You didn't override the parent classes method, so an instance of B.x() calls the parents .x() method which references the parents __x property.

Not C++ or Java, C# :) I am all open source from now on. I hate Microsoft and Google for that matter and everything they stand for. They are getting better. MS gave us VS code. I just don't like to be forced in using something and the privacy thing.
Reply
#7
(Aug-16-2021, 09:12 PM)muzikman Wrote: No get or set methods, nice and easy.
That is the way to go in Python,and in general only when need more that simple attribute access(avoid using getters/setters) should use property.
Also one important of aspect @property decorator is that original implementation can be made backward compatible.
Example.
class Homework:
    def __init__(self, grade=0):
        self.grade = grade
Usage:
>>> kent = Homework()
>>> # Set
>>> kent.grade = 90
>>> # Get
>>> kent.grade
90
# Set
>>> kent.grade = 110
# Get
>>> kent.grade
110
Let say that setting 110 as score is not ideal as 100 is max score.
class Homework:
    def __init__(self, grade=0):
        self._grade = grade

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self, value):
        if not (0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100')
        self._grade = value
Usage:
>>> kent = Homework()
>>> kent.grade = 90
>>> kent.grade
90
>>> kent.grade = 110
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "<module3>", line 12, in grade
ValueError: Grade must be between 0 and 100
So in this case we have not broke original implementation,only added a feature to avoid score over 100.

Quote:should we always start our instance variables privately?
No and is not private,the usage of double underscore in Python is really meant to avoid name mangling.
When __doble can/should be used is via inheritance if in some rarer cases when need to avoid name mangling.
Example:
class A:
    # Singe just info that should not be changed
    _info = 'Do not change'
    def __init__(self):
        self.__key = 50

    def __foo(self):
        print('hello')

class B(A):
    def __init__(self):
        super().__init__()
        # Does not override A.__key
        self.__key = 100

    # Does not override A.__foo_method()
    def __foo(self):
        print('world')
Usage:
>>> obj = B()
>>> obj._A__key
50
>>> obj._B__key
100
so self.__key has same name in A and B,but get name mangling to different names for each class.
The same with method:
>>> obj._A__foo()
hello
>>> obj._B__foo()
world

>>> # Class variable/attribute is shared with all classes
>>> obj._info
'Do not change'
A couple of links.
Python's Class Development Toolkit
Putting Abstract Base Classes to work
Reply
#8
ok. A few things I need to ask.

So, you agree with using the
@property
and
 @func.setter
?

I haven't seen this shortcut comparison operation before. I am assuming that this
if not (0 <= value <= 100):
shortcut is equal to
if not (0 <= value and value <= 100):
? Someone should develop a 'between' comparison operator just like in SQL.

Your code:
class B(A):
    def __init__(self):
        super().__init__()
        # Does not override A.__key
        self.__key = 100
 
    # Does not override A.__foo_method()
    def __foo(self):
        print('world')
You cannot override because the parent class's methods and properties are private, correct?


>>> obj = B()
>>> obj._A__key
50
>>> obj._B__key
100
This is a way to get the values of the parents private properties and methods?

obj.key # returns 100
So, name mangling basically converts your class name into
_myclass__
. I need to read up more on name mangling. I have read about it at geeksforgeeks but need more clarification.

>>> obj._A__foo() #Access the A foo function. , even though it is private.
hello
>>> obj._B__foo() #does the same things as obj.foo() ?
world
 
>>> # Class variable/attribute is shared with all classes # Yes, I understand class variables.
>>> obj._info
'Do not change'
Basically, when you use something like
 obj._A__foo() 
You are telling Python not to name mangle this or is this the way you name mangle?

I am going to check out your links right now.

Thank you very much for your tutorial.
Reply
#9
I prefer the property() function over the decorators.
attribute = property(getMethod, setMethod, delMethod)
The reason is that defining an attribute this way requires a that I have methods, and it is easier to bind to a method than a property.
class A():
    def __init__(self):
        self.x = 0
        self.y = 0

    def get_x(self):
        return self.get_x

    def set_x(self, value):
        self._x = value

    x = property(get_x, set_x)

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

obj = A()
root = tk.Tk()
tk.button(root, text='X=1', command=lambda: obj.set_x(1)).pack() # Ok.  Calls setter
tk.button(root, text='Y=1', command=lambda: obj.y=1).pack()  # <--- Bad!  Assignment not allowed
root.mainloop()
Reply
#10
I need to understand more about name mangling.

is the purpose for the
__property_name
. Is it for name mangling? So, that derived classes can't mess with them because
__property_name 
will be changed to
_classname__property_name
?

after I instantiate a class, if I use the
dir(myinstance)
, will that show me the new values of the dunder methods and properties?

The Pythonic way isn't about hiding things. I just watched a video that the other person suggested I watched. It was really good.

can you explain name mangling for me and the purpose? I have read about it but I think the confusion lies with other languages I've used. If you could give me an example of it and why or why not it is used?

Are you employed as a Python programmer? How long have you been doing it and any other languages?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  the order of running code in a decorator function akbarza 2 515 Nov-10-2023, 08:09 AM
Last Post: akbarza
  Curious about decorator syntax rjdegraff42 14 2,070 May-03-2023, 01:21 PM
Last Post: rjdegraff42
  Subclass initialized property used in parent class method. Is it bad coding practice? saavedra29 5 1,752 Feb-07-2022, 07:29 PM
Last Post: saavedra29
  @property vs __set__ / __get__ and __setattr__ / __getattr__ okhajut 1 3,309 Jun-15-2021, 03:48 PM
Last Post: snippsat
  Can property getters and setters have additional arguments? pjfarley3 2 3,027 Oct-30-2020, 12:17 AM
Last Post: pjfarley3
  decorator adamfairhall 0 1,549 Aug-18-2020, 08:38 AM
Last Post: adamfairhall
  Property price calculation oli_action 4 3,135 Jul-15-2020, 04:27 PM
Last Post: sridhar
  Use of @property decorator ruy 16 6,493 Jun-09-2020, 05:29 PM
Last Post: buran
  which is "better" (or more Pythonic)? Skaperen 2 2,035 Feb-01-2020, 03:10 PM
Last Post: Skaperen
  which is "better" (or more Pythonic)? Skaperen 7 3,210 Feb-01-2020, 03:51 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020