2

I have the following class:

class C3DPoint(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    # Other methods

I want to be sure that if somebody sets v3dpoint.x = <sth> it throws an error in case vale is not string.

How can this be done?

SmallTown
  • 25
  • 7
  • There are some packages for this like [traits](https://docs.enthought.com/traits/) or [traitlets](https://traitlets.readthedocs.io). You can use [type hints](https://www.python.org/dev/peps/pep-0484/), but those are not really checked at runtime. – jdehesa Nov 08 '18 at 12:50

4 Answers4

5

Good Python design avoids explicit type-checking: "if it quacks like a duck, it's a duck...". Therefore, you should first try to perform your data validation outside your class, or not at all.

Having said this, one way to perform your check is to redefine __setattr__ as described here:

class Point():

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __setattr__(self, name, value):
        assert isinstance(value, str), "Value must be of type str"
        super().__setattr__(name, value)

p = Point('a', 'b', 'c')
p.x = 3

# AssertionError: Value must be of type str
jpp
  • 159,742
  • 34
  • 281
  • 339
  • It is usually not required to check anything ("consenting adults"). But if it is required, I'd prefer `@property` and `@x.setter` so that `p.x` can be made safe. You can also work directly with `__setattr__` for that, no? – Amadan Nov 08 '18 at 12:54
  • @Amadan, Possibly, but perhaps OP also wants to be able to set some attributes normally. This allows a binary differentiation. – jpp Nov 08 '18 at 12:59
  • 1
    I kind of disagree. Either you're trusting callers will behave, in which case a check is not needed, or you're not, in which case ideally there should not be an avenue without a check. I can't see that `p['x']` but not on `p.x` accomplishes anything. It's like having a strict bouncer at the entrance to a bar, and an open window right next to it with a sign "go right ahead" where everyone can climb in and out unimpeded. – Amadan Nov 08 '18 at 13:03
  • 1
    @Amadan, As a design issue, yes, I agree with you. It's probably a good question / issue on CodeReview. Do you have a good Q&A either on SO or CodeReview for this? I have updated my answer to address *some* concerns. – jpp Nov 08 '18 at 13:07
1

You can type your function parameters in Python, assuming you use a current version, currently not sure which PEP implemented it.

def __init__(x: int, y: int , z: int):

This however will not throw TypeErrors, since we are all consenting adults, for that you'd can do a type check.

if not (isinstance x, int):
    # throw Error
Bernhard
  • 1,253
  • 8
  • 18
0

You can do it like that:

variable_name: type = value
kb-0
  • 98
  • 5
0

Use a try/except:

try:
    int(a)
except Exception as e:
    print "That's not an int"
S. L.
  • 630
  • 8
  • 19
  • That would *not work* for floats, iirc casting to int just cuts of the decimals. Ofc that can be desired behaviour. – Bernhard Nov 08 '18 at 12:51