I am trying to make python module for jenni/phenny irc bot.
This is part of my code
def bp(jenni, input):
try:
text = input.group(2).encode('utf-8').split()
except:
jenni.reply("Please use correct syntax '.bp id weapons 7'. Available for weapons and food only")
if text[0].isstr() and text[1].isstr() and text[2].isdigit() and len(text) == 3 and text[1] == ('weapons' or 'food'):
url = 'http://someAPIurl/%s/%s/%s/1.xml?key=%s' % (text[0], text[1], text[2], key)
If the input is already a str why would I be getting this error?
AttributeError: 'str' object has no attribute 'isstr'
The error is exactly what it says; str has no method isstr().
If you want to make sure that it's only letter(s), use .isalpha().
Example:
>>> '0'.isalpha()
False
>>> 'a'.isalpha()
True
>>> 'aa'.isalpha()
True
Use isinstance and either basestring for Python 2.x and str or unicode for Python 3.x:
isinstance(your_string, basestring)
That is the question that you originally asked but is probably not what you meant. Your sample code suggests that you really want to know how to check to see if a string is either alphabetic or alphanumeric. For that you want to use the isalpha or isalnum string methods.
str.isalpha()
Return true if all characters in the string are
alphabetic and there is at least one character, false otherwise.
For 8-bit strings, this method is locale-dependent.
You may also want to consider refactoring your code to make it a bit easier to read and maintain. Maybe something like this:
API_URL = 'http://someAPIurl/%s/%s/%s/1.xml?key=%s'
KIND_CHOICES = ('weapon', 'food')
def bp(jenni, input):
try:
cmd, kind, index = input.group(2).encode('utf-8').split()
# Assigning to 3 variables lets you skip the len() == 3 check
# and can make the use of each argument more obvious than text[1]
except:
jenni.reply("Please use correct syntax '.bp id weapons 7'. Available for weapons and food only")
if cmd.isalpha() and kind in KIND_CHOICES and index.isdigit():
url = API_URL % (cmd, kind, index, key) # is key a global?
# ...
Try using: - text[0].isalpha()..
There is no such method isstr() for string..
And in place of text[1] == ('weapons' or 'food'), you should use in operator..
if (text[1] in ('weapons', 'food')) {
}
Related
I'm trying to add a check here that if the receiver is just a string. then convert that into list else just pass.
if type(receiver) == str:
receiver=[receiver]
error:
TypeError: 'str' object is not callable
You can check the type of an instance with the following.
if isinstance(receiver, str):
# do something if it is a string
If you just need to check rather it is not a string:
if not isinstance(receiver, str):
# do something if it is not a string
Look at this tutorial to learn more about the function.
a = '123'
print(str(a))
print(type(a))
I have a function that accepts an integer year, but I also want the user to be able to pass in the string 'ALL' and still be able to get something back.
I have this ugly piece of code right now:
if type(year) != str or (type(year) == str and year.upper() != 'ALL'):
total_results = self.filterResultsByYear(total_results, year, year2)
Results are filtered by default to the current year, and can be filtered by other years, but if the user wants to not filter, they have to pass in 'all' for the year.
The reason I wrote the above abomination is if I just have if year.upper() != 'ALL' I get a TypeError if I pass in an integer. If I put if type(year) != str and year.upper() != 'ALL' I still get the same error. The above code looks really ugly and I wanted to make it more pythonic. What tools do I have to do this?
Depending on what total_results and year2 are and how you'd like to handle them:
try:
year = int(year)
total_results = self.filterResultsByYear(total_results, year, year2)
except ValueError:
if not isinstance(year, (str, unicode)):
raise # Not string, unicode or coercible to an integer.
if year.lower() == 'all':
# Your logic here.
else:
# String but not 'all'. Exception handling.
Bye the way, to check for class equivalency one uses isinstance(object, class) or isinstance(object, (class 1, class 2, ...)).
I love using the expression
if 'MICHAEL89' in USERNAMES:
...
where USERNAMES is a list.
Is there any way to match items with case insensitivity or do I need to use a custom method? Just wondering if there is a need to write extra code for this.
username = 'MICHAEL89'
if username.upper() in (name.upper() for name in USERNAMES):
...
Alternatively:
if username.upper() in map(str.upper, USERNAMES):
...
Or, yes, you can make a custom method.
str.casefold is recommended for case-insensitive string matching. #nmichaels's solution can trivially be adapted.
Use either:
if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):
Or:
if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):
As per the docs:
Casefolding is similar to lowercasing but more aggressive because it
is intended to remove all case distinctions in a string. For example,
the German lowercase letter 'ß' is equivalent to "ss". Since it is
already lowercase, lower() would do nothing to 'ß'; casefold()
converts it to "ss".
I would make a wrapper so you can be non-invasive. Minimally, for example...:
class CaseInsensitively(object):
def __init__(self, s):
self.__s = s.lower()
def __hash__(self):
return hash(self.__s)
def __eq__(self, other):
# ensure proper comparison between instances of this class
try:
other = other.__s
except (TypeError, AttributeError):
try:
other = other.lower()
except:
pass
return self.__s == other
Now, if CaseInsensitively('MICHAEL89') in whatever: should behave as required (whether the right-hand side is a list, dict, or set). (It may require more effort to achieve similar results for string inclusion, avoid warnings in some cases involving unicode, etc).
Usually (in oop at least) you shape your object to behave the way you want. name in USERNAMES is not case insensitive, so USERNAMES needs to change:
class NameList(object):
def __init__(self, names):
self.names = names
def __contains__(self, name): # implements `in`
return name.lower() in (n.lower() for n in self.names)
def add(self, name):
self.names.append(name)
# now this works
usernames = NameList(USERNAMES)
print someone in usernames
The great thing about this is that it opens the path for many improvements, without having to change any code outside the class. For example, you could change the self.names to a set for faster lookups, or compute the (n.lower() for n in self.names) only once and store it on the class and so on ...
Here's one way:
if string1.lower() in string2.lower():
...
For this to work, both string1 and string2 objects must be of type string.
I think you have to write some extra code. For example:
if 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
...
In this case we are forming a new list with all entries in USERNAMES converted to upper case and then comparing against this new list.
Update
As #viraptor says, it is even better to use a generator instead of map. See #Nathon's answer.
You could do
matcher = re.compile('MICHAEL89', re.IGNORECASE)
filter(matcher.match, USERNAMES)
Update: played around a bit and am thinking you could get a better short-circuit type approach using
matcher = re.compile('MICHAEL89', re.IGNORECASE)
if any( ifilter( matcher.match, USERNAMES ) ):
#your code here
The ifilter function is from itertools, one of my favorite modules within Python. It's faster than a generator but only creates the next item of the list when called upon.
To have it in one line, this is what I did:
if any(([True if 'MICHAEL89' in username.upper() else False for username in USERNAMES])):
print('username exists in list')
I didn't test it time-wise though. I am not sure how fast/efficient it is.
Example from this tutorial:
list1 = ["Apple", "Lenovo", "HP", "Samsung", "ASUS"]
s = "lenovo"
s_lower = s.lower()
res = s_lower in (string.lower() for string in list1)
print(res)
My 5 (wrong) cents
'a' in "".join(['A']).lower()
UPDATE
Ouch, totally agree #jpp, I'll keep as an example of bad practice :(
I needed this for a dictionary instead of list, Jochen solution was the most elegant for that case so I modded it a bit:
class CaseInsensitiveDict(dict):
''' requests special dicts are case insensitive when using the in operator,
this implements a similar behaviour'''
def __contains__(self, name): # implements `in`
return name.casefold() in (n.casefold() for n in self.keys())
now you can convert a dictionary like so USERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT) and use if 'MICHAEL89' in USERNAMESDICT:
Thought exercise: What is the "best" way to write a Python function that takes a regex pattern or a string to match exactly:
import re
strings = [...]
def do_search(matcher):
"""
Returns strings matching matcher, which can be either a string
(for exact match) or a compiled regular expression object
(for more complex matches).
"""
if not is_a_regex_pattern(matcher):
matcher = re.compile('%s$' % re.escape(matcher))
for s in strings:
if matcher.match(s):
yield s
So, ideas for the implementation of is_a_regex_pattern()?
You can access the _sre.SRE_Pattern type via re._pattern_type:
if not isinstance(matcher, re._pattern_type):
matcher = re.compile('%s$' % re.escape(matcher))
Below is a demonstration:
>>> import re
>>> re._pattern_type
<class '_sre.SRE_Pattern'>
>>> isinstance(re.compile('abc'), re._pattern_type)
True
>>>
Or, make it quack:
try:
does_match = matcher.match(s)
except AttributeError:
does_match = re.match(matcher.s)
if does_match:
yield s
In other words, treat matcher as if it already were a compiled regular expression. And if that breaks, then treat it like a string that needs to be compiled.
This is called Duck Typing. Not everyone agrees that exceptions should be used like this for routine contingencies. This is the ask-permission versus ask-forgiveness debate. Python is more amenable to forgiveness than most languages.
Not a string:
def is_a_regex_pattern(s):
return not isinstance(s, basestring)
Is a _sre.SRE_Pattern (though that's not importable, so use a gross string match):
def is_a_regex_pattern(s):
return s.__class__.__name__ == 'SRE_Pattern'
You can re-compile a SRE_Pattern and it seems to evaluate the same.
def is_a_regex_pattern(s):
return s == re.compile(s)
You could test, if matcher has an method match:
import re
def do_search(matcher, strings):
"""
Returns strings matching matcher, which can be either a string
(for exact match) or a compiled regular expression object
(for more complex matches).
"""
if hasattr(matcher, 'match'):
test = matcher.match
else:
test = lambda s: matcher==s
for s in strings:
if test(s):
yield s
You should not use global variables, but use a second parameter.
On Python 3.7, re._pattern_type was renamed to re.Pattern
https://stackoverflow.com/a/27366172/895245 therefore broke at that point, as re._pattern_type is not defined.
While re.Pattern looks nicer and will therefore hopefully be more stable, it is not mentioned at all in the docs: https://docs.python.org/3/library/re.html#regular-expression-objects so maybe it is not a good idea to rely on it.
https://stackoverflow.com/a/46779329/895245 does make some sense. But what is someday the str class adds a .match method and it does something completely different? :-) Ah, the joys of typeless languages.
So I think I'm going with:
import re
_takes_s_or_re_type = type(re.compile(''))
def takes_s_or_re(s_or_re):
if isinstance(s_or_re, _takes_s_or_re_type):
return 0
else:
return 1
assert takes_s_or_re(re.compile('a.c')) == 0
assert takes_s_or_re('a.c') == 1
as this can only break when a public API breaks.
Tested on Python 3.8.0.
Basically I want to do this:
obj = 'str'
type ( obj ) == string
I tried:
type ( obj ) == type ( string )
and it didn't work.
Also, what about the other types? For example, I couldn't replicate NoneType.
isinstance()
In your case, isinstance("this is a string", str) will return True.
You may also want to read this: http://www.canonical.org/~kragen/isinstance/
First, avoid all type comparisons. They're very, very rarely necessary. Sometimes, they help to check parameter types in a function -- even that's rare. Wrong type data will raise an exception, and that's all you'll ever need.
All of the basic conversion functions will map as equal to the type function.
type(9) is int
type(2.5) is float
type('x') is str
type(u'x') is unicode
type(2+3j) is complex
There are a few other cases.
isinstance( 'x', basestring )
isinstance( u'u', basestring )
isinstance( 9, int )
isinstance( 2.5, float )
isinstance( (2+3j), complex )
None, BTW, never needs any of this kind of type checking. None is the only instance of NoneType. The None object is a Singleton. Just check for None
variable is None
BTW, do not use the above in general. Use ordinary exceptions and Python's own natural polymorphism.
isinstance works:
if isinstance(obj, MyClass): do_foo(obj)
but, keep in mind: if it looks like a duck, and if it sounds like a duck, it is a duck.
EDIT: For the None type, you can simply do:
if obj is None: obj = MyClass()
For other types, check out the types module:
>>> import types
>>> x = "mystring"
>>> isinstance(x, types.StringType)
True
>>> x = 5
>>> isinstance(x, types.IntType)
True
>>> x = None
>>> isinstance(x, types.NoneType)
True
P.S. Typechecking is a bad idea.
You can always use the type(x) == type(y) trick, where y is something with known type.
# check if x is a regular string
type(x) == type('')
# check if x is an integer
type(x) == type(1)
# check if x is a NoneType
type(x) == type(None)
Often there are better ways of doing that, particularly with any recent python. But if you only want to remember one thing, you can remember that.
In this case, the better ways would be:
# check if x is a regular string
type(x) == str
# check if x is either a regular string or a unicode string
type(x) in [str, unicode]
# alternatively:
isinstance(x, basestring)
# check if x is an integer
type(x) == int
# check if x is a NoneType
x is None
Note the last case: there is only one instance of NoneType in python, and that is None. You'll see NoneType a lot in exceptions (TypeError: 'NoneType' object is unsubscriptable -- happens to me all the time..) but you'll hardly ever need to refer to it in code.
Finally, as fengshaun points out, type checking in python is not always a good idea. It's more pythonic to just use the value as though it is the type you expect, and catch (or allow to propagate) exceptions that result from it.
Use isinstance(object, type). As above this is easy to use if you know the correct type, e.g.,
isinstance('dog', str) ## gives bool True
But for more esoteric objects, this can be difficult to use.
For example:
import numpy as np
a = np.array([1,2,3])
isinstance(a,np.array) ## breaks
but you can do this trick:
y = type(np.array([1]))
isinstance(a,y) ## gives bool True
So I recommend instantiating a variable (y in this case) with a type of the object you want to check (e.g., type(np.array())), then using isinstance.
You're very close! string is a module, not a type. You probably want to compare the type of obj against the type object for strings, namely str:
type(obj) == str # this works because str is already a type
Alternatively:
type(obj) == type('')
Note, in Python 2, if obj is a unicode type, then neither of the above will work. Nor will isinstance(). See John's comments to this post for how to get around this... I've been trying to remember it for about 10 minutes now, but was having a memory block!
Use str instead of string
type ( obj ) == str
Explanation
>>> a = "Hello"
>>> type(a)==str
True
>>> type(a)
<type 'str'>
>>>
It is because you have to write
s="hello"
type(s) == type("")
type accepts an instance and returns its type. In this case you have to compare two instances' types.
If you need to do preemptive checking, it is better if you check for a supported interface than the type.
The type does not really tell you much, apart of the fact that your code want an instance of a specific type, regardless of the fact that you could have another instance of a completely different type which would be perfectly fine because it implements the same interface.
For example, suppose you have this code
def firstElement(parameter):
return parameter[0]
Now, suppose you say: I want this code to accept only a tuple.
import types
def firstElement(parameter):
if type(parameter) != types.TupleType:
raise TypeError("function accepts only a tuple")
return parameter[0]
This is reducing the reusability of this routine. It won't work if you pass a list, or a string, or a numpy.array. Something better would be
def firstElement(parameter):
if not (hasattr(parameter, "__getitem__") and callable(getattr(parameter,"__getitem__"))):
raise TypeError("interface violation")
return parameter[0]
but there's no point in doing it: parameter[0] will raise an exception if the protocol is not satisfied anyway... this of course unless you want to prevent side effects or having to recover from calls that you could invoke before failing. (Stupid) example, just to make the point:
def firstElement(parameter):
if not (hasattr(parameter, "__getitem__") and callable(getattr(parameter,"__getitem__"))):
raise TypeError("interface violation")
os.system("rm file")
return parameter[0]
in this case, your code will raise an exception before running the system() call. Without interface checks, you would have removed the file, and then raised the exception.
I use type(x) == type(y)
For instance, if I want to check something is an array:
type( x ) == type( [] )
string check:
type( x ) == type( '' ) or type( x ) == type( u'' )
If you want to check against None, use is
x is None
i think this should do it
if isinstance(obj, str)
Type doesn't work on certain classes. If you're not sure of the object's type use the __class__ method, as so:
>>>obj = 'a string'
>>>obj.__class__ == str
True
Also see this article - http://www.siafoo.net/article/56
To get the type, use the __class__ member, as in unknown_thing.__class__
Talk of duck-typing is useless here because it doesn't answer a perfectly good question. In my application code I never need to know the type of something, but it's still useful to have a way to learn an object's type. Sometimes I need to get the actual class to validate a unit test. Duck typing gets in the way there because all possible objects have the same API, but only one is correct. Also, sometimes I'm maintaining somebody else's code, and I have no idea what kind of object I've been passed. This is my biggest problem with dynamically typed languages like Python. Version 1 is very easy and quick to develop. Version 2 is a pain in the buns, especially if you didn't write version 1. So sometimes, when I'm working with a function I didn't write, I need to know the type of a parameter, just so I know what methods I can call on it.
That's where the __class__ parameter comes in handy. That (as far as I can tell) is the best way (maybe the only way) to get an object's type.
You can compare classes for check level.
#!/usr/bin/env python
#coding:utf8
class A(object):
def t(self):
print 'A'
def r(self):
print 'rA',
self.t()
class B(A):
def t(self):
print 'B'
class C(A):
def t(self):
print 'C'
class D(B, C):
def t(self):
print 'D',
super(D, self).t()
class E(C, B):
pass
d = D()
d.t()
d.r()
e = E()
e.t()
e.r()
print isinstance(e, D) # False
print isinstance(e, E) # True
print isinstance(e, C) # True
print isinstance(e, B) # True
print isinstance(e, (A,)) # True
print e.__class__ >= A, #False
print e.__class__ <= C, #False
print e.__class__ < E, #False
print e.__class__ <= E #True
Because type returns an object, you can access de the name of the object using object.name
Example:
years = 5
user = {'name':'Smith', 'age':20}
print(type(a).__name__)
output: 'int'
print(type(b).__name__ )
output: 'dict'