473,703 Members | 2,351 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

A little stricter type checking

I have a little proposal about type checking in python. I'll be glad
if you read and comment on it. Sorry for my bad english (I'm not a
native English speaker)

A Little Stricter Typing in Python - A Proposal

As we all know, one of the best things about python and other
scripting languages is dynamic typing (yes I know it has advantages
and disadvantages but I will not discuss them now). Dynamic typing
allows us to change types of variables on the fly, and frees us from
the redundant work of defining variables, and their types. On the
other hand in languages like C, java etc... where types are strict ve
have the guarantee that the variables will always be the same type
without any change.

For example think that you are writing a utility function for a
library. In python you just define the function name and the name of
the parameters but you can never know the variables that has been
passed from parameters will always function as you planned. If you
want to be sure, you need to explicitly check if the variable has the
correct type. On the other side for example in C you don't need to
check the types of variables since the compiler will complain if there
are incompatible types. But this approach also limits the flexibility
and destroys the advantages of dynamic typing. What we need is a way
to define types of the parameters in a flexible way. So Here it is...

We can use operators like those we use in boolean operations. For
exampla lets assume that we have a function that take one parameter
which needs to be an instance of class foo, or an instance of a
subclass of foo. In current style it will look like that:
def larry(guido):
<some checks to be sure that guido is an instance of foo or an
instance of a subclass of foo>
<Actual code>

Well always checking the types of the parameters in the start of every
function is too many redundant work. Instead we can define a syntax
that will check the type information at the beginning of function
declaration, and even before executing any code from that function.
That syntax might look like that:

def larry(guido >= foo):
<Just actual code, no checking since the interpreter handles it>

And if we have a function that have much more parameters, this kind of
a syntax will really help us to remove redundant code from our
functions. The syntax can be defined by something like:
Symbol : Definition
== : The parameter is an instance of a given class for example: d ==
dict
= : The parameter is an instance of the given class or one of its

subclasses
<= : The parameter is an instance of the given class or one of its
parent
classes

This list can be expanded to include != or even a more fantastic
operator: "in" so that we can check if the parameter has a specific
attribute before executing our function.

The best thing about this approach is that while keeping flexibility
it adds better type checking and it keeps the compatibility with old
code.

So that's all for now... All comments are welcome.
Jul 18 '05 #1
5 3003
Tongu? Yumruk wrote:
If you want to be sure, you need to explicitly check if the
variable has the correct type.
Rather, if you want to be sure then it's likely you
haven't fully understood "duck typing" (or "latent typing"
or "dynamic typing", depending on who you are.) See
http://c2.com/cgi/wiki?DuckTyping
and
http://mindview.net/WebLog/log-0052
for more details.

In short, doing explicit type checks is not the Python way.
Well always checking the types of the parameters in the start of every
function is too many redundant work. Instead we can define a syntax
that will check the type information at the beginning of function
declaration, and even before executing any code from that function.
That syntax might look like that:

def larry(guido >= foo):
<Just actual code, no checking since the interpreter handles it>
The few times I've needed explicit type checks is to
do slightly different behaviour based on an type.
For example,

def count_lines(f):
if isinstance(f, str):
f = open(f, "U")
return len(f)

Your proposal doesn't do anything for this use case.

In addition, what you're thinking of could be
done with the new "decorator" proposal. Here's
a sketch of one way to handle it. Ideally
it should propogate the arglist and support
keyword args and default parameters, but this
gives the essense.
class typecheck: .... def __init__(self, *types):
.... self.types = types
.... def __call__(self, func):
.... def f(*args):
.... for arg, basetype in zip(args, self.types):
.... if not isinstance(arg, basetype):
.... raise TypeError("inco mpatible types")
.... return func(*args)
.... return f
.... @typecheck(int, str) .... def spam(i, s):
.... return s*i
.... spam(2, "hello") 'hellohello' spam("hello", 2) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 8, in f
TypeError: incompatible types


(Wow! My first used of the @-thingy and it worked
on the first try.)
And if we have a function that have much more parameters, this kind of
a syntax will really help us to remove redundant code from our
functions. The syntax can be defined by something like:
[
== for exact test= for superclass test

<= for subclass test
!= for is neither subclass nor superclass
in for attribute testing
]
But if you look through Python code you'll see that
most of the use cases look like my emulation of
polymorphism and not your strict type checking. Here
are some examples from the stdlib

def __eq__(self, other):
if isinstance(othe r, BaseSet):
return self._data == other._data
else:
return False

if isinstance(inst ream, basestring):
instream = StringIO(instre am)

elif (not isinstance(self .delimiter, str) or
len(self.delimi ter) > 1):
errors.append(" delimiter must be one-character string")
if isinstance(long opts, str):
longopts = [longopts]
else:
longopts = list(longopts)
if isinstance(file names, basestring):
filenames = [filenames]

if isinstance(obje ct, types.TupleType ):
argspec = object[0] or argspec
docstring = object[1] or ""
else:
docstring = pydoc.getdoc(ob ject)

The only examples I found along the lines you wanted were
in pickletools.py, copy.py, sets.py, and warnings.py.
It just isn't needed that often in Python programming.
Andrew
da***@dalkescie ntific.com
Jul 18 '05 #2
Tongu? Yumruk wrote:
I have a little proposal about type checking in python.


This proposal comes up very often. I've been around in c.l.py
for only about a year now but I saw it proposed what seems like
on a monthly basis.

When I started using python I was worried about ending up with
nasty errors based on inappropriate function calls. In practice
,it turns out, in python I almost never make the kind of errors
that this type-checking would catch...

Istvan.
Jul 18 '05 #3
Andrew Dalke wrote:

[examples of isinstance() usage in the standard library]
The only examples I found along the lines you wanted were
in pickletools.py, copy.py, sets.py, and warnings.py.
It just isn't needed that often in Python programming.


There are at least three more idioms that could (sometimes) be replaced
by type-checking:

# "casting"
s = str(s)
it = iter(seq)

# check for an "interface"
try:
lower = s.lower
except AttributeError:
raise TypeError
else:
lower()

# check for an "interface" , LBYL-style
if not hasattr(foo, "bar"):
raise TypeError

These are more difficult to hunt and I'm lazy.

However, I don't think you can tell from the structure alone whether an
explicit type declaration would be a superior solution in these cases.

Should Python be extended to allow type declarations, I expect them to
appear in places where they reduce the usefulness of the code while
claiming to make it safe...

Peter

Jul 18 '05 #4
Peter Otten wrote:
There are at least three more idioms that could (sometimes) be replaced
by type-checking:
Though from what I can tell the OP wanted "real" type
checking, as found in Java and C. The original text was

] On the other hand in languages like C, java etc...
] where types are strict we have the guarantee that
] the variables will always be the same type without
] any change.
# "casting"
Wouldn't that be type conversion, and not a check?
# check for an "interface"
try:
lower = s.lower
except AttributeError:
raise TypeError
else:
lower()
Mmm, there's a problem with this checking. Consider

class Spam:
lower = 8

Though the odds are low.
# check for an "interface" , LBYL-style
if not hasattr(foo, "bar"):
raise TypeError
Aren't both of these the "look before you leap" style?
Well, except for checking for the callable.
These are more difficult to hunt and I'm lazy.

However, I don't think you can tell from the structure alone whether an
explicit type declaration would be a superior solution in these cases.
I do at times use tests like you showed, in order
to get a more meaningful error message. I don't
think they are considered type checks -- perhaps
protocol checks might be a better term?

Should Python be extended to allow type declarations, I expect them to
appear in places where they reduce the usefulness of the code while
claiming to make it safe...


As was mentioned in the @PEP (as I recall) one of the
interesting possibilities is to use type checks with
support for the adapter PEP so that inputs parameters
can get converted to the right type, rather like your
first point.

@require(PILIma ge)
def draw(image):
...

As new image data types are added, they can be passed to
draw() without need for an explicit convert step, so
long as the adapter is registered.

Andrew
da***@dalkescie ntific.com
Jul 18 '05 #5
Andrew Dalke wrote:
Peter Otten wrote:
There are at least three more idioms that could (sometimes) be replaced
by type-checking:
Though from what I can tell the OP wanted "real" type
checking, as found in Java and C. The original text was

] On the other hand in languages like C, java etc...
] where types are strict we have the guarantee that
] the variables will always be the same type without
] any change.
# "casting"


Wouldn't that be type conversion, and not a check?


In a way it is both. Consider

def f(s):
s = str(s)

versus

interface Stringifiable:
def __str__(self) -> str:
pass

def f(Stringifiable s):
s = str(s)

In the latter form the compiler can guarantee not that the call succeeds,
but that the interface is there at least, while in the former both steps
(check and creation/conversion) are blurred in the single str() call.
Don't let yourself detract from that by the fact that in Python str() hardly
ever fails.
# check for an "interface"
try:
lower = s.lower
except AttributeError:
raise TypeError
else:
lower()


Mmm, there's a problem with this checking. Consider

class Spam:
lower = 8


Of course it is not a full replacement of a type declaration, but often used
to achieve similar goals. I guess that it would be immediately dismissed by
people experienced only in statically typed languages and most likely
replaced with something like

def f(str s):
s = s.lower()
....

thus (sometimes) unnecessarily excluding every object with a string-like
"duck-type", i. e. a sufficient subset of the str interface for the above
function to work.
Though the odds are low.
# check for an "interface" , LBYL-style
if not hasattr(foo, "bar"):
raise TypeError
Aren't both of these the "look before you leap" style?
Well, except for checking for the callable.


I thought that "look before you leap" is doing something twice, once to see
if it is possible and then for real. Let's concentrate on attribute access
for the sake of the example:

# good style, IMHO
try:
lower = s.lower
except AttributeError:
# handle failure
# use lower, don't access s.lower anymore.

# LBYL, bad IMHO
try:
s.lower
except AttributeError
# handle failure
# use lower, accessing it via attribute access again, e. g.
lower = s.lower # an unexpected failure lurks here

# LBYL, too, but not as easily discernable
# and therefore seen more often in the wild
if hasattr(s, "lower"):
lower = s.lower # an unexpected failure lurks here
else:
# handle failure

And now, just for fun, a class that exposes the difference:
class DestructiveRead (object): .... def __init__(self):
.... self.lower = 42
.... def __getattribute_ _(self, name):
.... result = object.__getatt ribute__(self, name)
.... delattr(self, name)
.... return result
.... print DestructiveRead ().lower # just doit 42
d = DestructiveRead ()
if hasattr(d, "lower"): # try to play it safe
.... print d.lower
....
Traceback (most recent call last):
File "<stdin>", line 2, in ?
File "<stdin>", line 5, in __getattribute_ _
AttributeError: 'DestructiveRea d' object has no attribute 'lower'

This would of course be pointless if there weren't (sometimes subtle)
real-word variants of the above.
These are more difficult to hunt and I'm lazy.

However, I don't think you can tell from the structure alone whether an
explicit type declaration would be a superior solution in these cases.


I do at times use tests like you showed, in order
to get a more meaningful error message. I don't
think they are considered type checks -- perhaps
protocol checks might be a better term?


Maybe - I think I'm a bit fuzzy about the terms type, interface and
protocol. In a way I tried to make that fuzziness explicit in my previous
post: In a staticically typed language you may be tempted to ensure the
availability of a certain protocol by specifying a type that does fulfill
it, either because templates are not available or too tedious, and you
cannot make an interface (abstract base class) for every single method, no?

In a dynamically typed language the same conceptual restrictions may be
spread over various constructs in the code (not only isinstance()), and the
translation from one system into the other is far from straightforward .
Should Python be extended to allow type declarations, I expect them to
appear in places where they reduce the usefulness of the code while
claiming to make it safe...


As was mentioned in the @PEP (as I recall) one of the
interesting possibilities is to use type checks with
support for the adapter PEP so that inputs parameters
can get converted to the right type, rather like your
first point.

@require(PILIma ge)
def draw(image):
...


why not rely on PILImage's __init__() or __new__() for that:

def draw(image):
image = PILImage(image)

Since the introduction of __new__() this can be almost a noop if the image
is already a PILImage instance.
As new image data types are added, they can be passed to
draw() without need for an explicit convert step, so
long as the adapter is registered.


I had a quick look at the PEP 246 - Object Adaptation, and I'm not sure yet
whether the pythonic way to write e. g.

class EggsSpamAndHam (Spam,KnightsWh oSayNi):
def ham(self): print "ham!"
def __conform__(sel f,protocol):
if protocol is Ham:
# implements Ham's ham, but does not have a word
return self
if protocol is KnightsWhoSayNi :
# we are no longer the Knights who say Ni!
raise adaptForceFailE xception
if protocol is Eggs:
# Knows how to create the eggs!
return Eggs()

would rather be along these lines:

class Eggs:
def asEggs(self):
return self

class EggsSpamAndHam( Spam): # no need to inherit form KnightsWhoSayNi
def ham(self): print "ham!"
def asEggs(self):
return Eggs()

That and a class-independent adaptation registry should achieve the same
functionality with much simpler code. The real limits to protocol
complexity are human understanding rather than technical feasibility.

Of course I may change my mind as soon as I see a compelling real world
example...
Peter


Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
2834
by: sashan | last post by:
I'm a Python newbie. I have been using c++ for 5 years and before that I was programming in Pascal. The one thing that annoys me about python is dynamic typing because I find myself making typographical errors of the sort that would under C++ be picked up by the compiler at compiler time. With Python I have to wait for the error to appear at runtime in order for me to correct it. I find this inefficient. Any advice about how to get around...
12
2059
by: Aaron Watters | last post by:
I'm doing a heart/lung bypass procedure on a largish Python program at the moment and it prompted the thought that the methodology I'm using would be absolutely impossible with a more "type safe" environment like C++, C#, java, ML etcetera. Basically I'm ripping apart the organs and sewing them back together, testing all the while and the majority of the program at the moment makes no sense in a type safe world... Nevertheless, since...
3
2353
by: George Sakkis | last post by:
Explicit type checking is not typically seen in Python code, and usually that's not a big problem; most typing errors are likely to raise a TypeError or AttributeError sooner than later. There are cases, though, where typing errors are not caught (at least not early) because different classes happen to have methods with the same name; that's really subtle with the special methods like __eq__, __hash__, etc. that are common to all (or at...
6
14315
by: Web Developer | last post by:
Hi, I come across the term "type checking" very often in my readings on C++, and have never heard it in Java. Besides the simplistic answer that it checks the "type", what more does it mean? WD
13
2188
by: Spartanicus | last post by:
I've been thinking about using a custom "stricter" local HTML 4.01 Strict DTD for the purpose of local validation. That way I wouldn't have to change my doctype, my documents would still adhere to the public 4.01 Strict DTD, but I'd have the added advantage that I get warnings for example for unclosed paragraph tags when validating locally by mapping my local validator (ARV) to that local custom DTD. Any disadvantages in doing that, and...
3
1517
by: Mazin07 | last post by:
I have a script that makes multiple requests to several sites. However, each request takes a little while. How can I get the PHP script to output data to let the user know that it's checking? For example, I have echo "Checking..."; at the beginning, before I do any hocus-pocus, but it doesn't show up until the script is done. How do I get it to send some data at a time?
20
2085
by: Xiaoshen Li | last post by:
Hi, I am reading the book "Concepts of programming languages" by R. W. Sebesta. He said: "One of the most important reasons why C is both liked and disliked is its lack of complete type checking. For example, functions can be written for which parameters are not type checked. Those who like C appreciate the flexibility; those who do not like it find it too insecure."
8
3331
by: Ashish | last post by:
Hi all, I have interface declared like public IBaseInterface { } then a generic collection like
54
2982
by: ash | last post by:
i am writing this program (for exercise1-9 in k&r-2nd edition) which removes extra spaces in string example- "test string" will be "test string" #include<stdio.h> #include<string.h> #include<conio.h> main() { char str,st;
0
8758
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, weíll explore What is ONU, What Is Router, ONU & Routerís main usage, and What is the difference between ONU and Router. Letís take a closer look ! Part I. Meaning of...
0
9121
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9017
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8962
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
5922
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4687
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3123
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2450
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2069
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.