简体   繁体   中英

Polymorphism with built-in types in Python

I have a collection of variables in Python, some of which are normal Python numbers and some of which are instances of a class I've written called Property, which represents a range of possible values (eg between 0 and 4.2). I want to iterate over this collection and do something different depending on whether each item is a built-in number or a Property. Of course I could do this by explicitly checking the type, but I want to know if there's a clean, object-oriented, idiomatic way to do it in Python.

For example, one of the things I want to do depends on the signs of the collection's entries, so I want to write a function that returns the sign of its argument, regardless of whether it's passed a built-in type or a Property. I can add a __sign__ method to Property, but there's no __sign__ method for built-in numeric types, and Python won't let me add one, so that doesn't help.

Perhaps I'm just making a mistake by having a collection that mixes class instances with built-in types - but changing it would clutter my code's interface. Instead of writing

myList = [0, 2.3, 4, Property(0,2)]

I'd have to write something like

myList = [Property(0), Property(2.3), Property(4), Property(0,2)]

which I'd prefer to avoid if possible.

Here's some more information about what I'm trying to do. I'm working on a scientific problem that involves keeping track of a lot of variables, which interrelate in particular ways. A lot of these variables have known values (because they've been measured) but some are unknown and others have been measured but not accurately, so we know they must lie in some particular range. There are equations that specify the interrelationships between these variables, and ultimately I will use a numerical optimisation library to find the possible ranges of the unknown variables.

Because there are a lot of variables I want to store all the known data about them in a sensibly formatted input file. Although I want to keep this a python file for simplicity, it's important to keep its syntax as simple as possible, both for my sake and because it might have to be read or added to by non-programmers. Currently it has lots of lines that look something vaguely like this:

a.set_some_parameters(3.2, -1, Property(2.3,2.5))
a.x = 0.1
b.x = Property.unknown()
a.set_some_other_parameters(Property.positive(), -4.2, 1, 0)

The point being that (pretty much) anywhere you can enter a number, you can instead enter a Property if the value isn't precisely known. This works well as an interface, but I end up in the situation described above, where my code continually has to deal with the fact that something might be a built-in number, or it might be a Property instance.

Without knowing enough about what you're doing, I'm going to go ahead and agree with your statement

Perhaps I'm just making a mistake by having a collection that mixes class instances with built-in types

If you only need to compare the sign between built-in numbers and your Property instances, it wouldn't be such a big deal (use the cmp function and override comparison operators on your Property class), but I'm betting that's not all you want to do.

Instead, think of better ways to construct your list, if that's what you're really worried about. Here's two examples:

P = Property
myList = [P(0), P(2.3), P(4), P(0,2)]

# or...

def createPropertyList(*args):
    return [Property(x) for x in args]

myList = createPropertyList(0,2.3,4,(0,2))

From the design point of view you are doing something odd. If you have a list of things and you want to act on them they do share something!

So, you should think about what should be their common interface.

You have some different solutions:

-as you suggest you could define a new constructor for Property that takes the built-in,

-if you want your object to still be an integer you can make a subclass of integers,

-you can also define a new class that has an integer member, then you can define the methods of your new class so to define an appropriate interface for your integer. In other words you wrap your integer in a new class.

Please, do something for having the appropriate shared interface for the objects in your list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM