What does a ¨no attribute error¨ mean in python? - python

I don´t understand why I get this error (AttributeError: 'str' object has no attribute 'ascii_uppercase') when I try running my code. Iḿ guessing it could be some indenting thatś out of place?
import collections
import string
def caesar(message, key):
upper = collections.deque(string.ascii_uppercase)
lower = collections.deque(string.ascii_lowercase)
upper.rotate(key)
lower.rotate(key)
upper = ''.join(list(upper))
lower = ''.join(list(lower))
return message.translate(string.maketrans(string.ascii_uppercase, upper)).translate(string.maketrans(string.ascii_lowercase, lower))
string = "hi my name is sam"
for i in range(len(string.ascii_uppercase)):
print i, " | ", caesar(string, i)```

What it actually means is that a string object has no ascii_uppercase attribute, Python is usually pretty clear about things like that :-)
On a less jocular note, it's saying that strings do not have a method called ascii_uppercase that you can use on them. If you want a string to be upper-cased, just use myStr.upper().
If you need something more complex/nuanced than a simple upper-casing, you'll probably have to write it yourself.

Custom variable string="hi my name is sam" conflicts with import string
maybe str1="hi my name is sam"
if you want to convert to uppercase
print("hi my name is sam".upper())
or
[print(i) for i in "hi my name is sam".upper()]

Related

How to work in a function on a variable from outside a function - based on it's name as a string

How convert string to a Python object?
I have for example simple function:
def test_function(name):
str(name) + "insert(1, "test_01")
...
test_function("list1")
I want this to perform "list1.insert(1, "test_01) operation but it doesn't work. I guees there is a problem that it reads name as a string not as an object. How can I solve this out?
locals()"YourFunction"
or
globals()["YourFunction"]()
as an example:
def foo(number):
return number*10
print (globals()["foo"](10))
Output= 100
Thanks
I don't know if it's what you really want. But i think it's because of the quotation mark. See below:
def test_function(name):
print(str(name) + 'insert(1, "test_01")')
...
test_function("list1")
NOTE
By any means don't use eval, it is insecure ("eval is evil").
For more details about eval harmfulness read here.
Solution Requested
Using eval you can evaluate string that contains code and execute it.
The code here that is being evaluated, looks for the variable name in the global scope (outside the function).
The globals() dictionary contains the variables defined outside the function.
def test_function(name):
eval(f'(globals()["{name}"]).insert(1, "test_01")')
name = "list1"
list1 = []
test_function(name)
# Outside function
# eval(str(name) + '.insert(1, "test_01")')
print(list1)

How to change a string in a function when calling a function?

I'm not sure if this is possible but is there a way to change a string that a function prints while calling it from another function? I want to do something like this:
def string():
print ("This cat was scared.")
def main():
for words in string():
str.replace("cat", "dog")
# Print "The do was scared."
main()
By popular demand (well, one person's curiosity…), here's how you actually could change the string in a function before calling that function.
You should never do this in practice. There are some use cases for playing around with code objects, but this really isn't one of them. Plus, if you do anything less trivial, you should use a library like bytecode or byteplay instead of doing it manually. Also, it goes without saying that not all Python implementations use CPython-style code objects. But anyway, here goes:
import types
def string():
print ("This cat was scared.")
def main():
# A function object is a wrapper around a code object, with
# a bit of extra stuff like default values and closure cells.
# See inspect module docs for more details.
co = string.__code__
# A code object is a wrapper around a string of bytecode, with a
# whole bunch of extra stuff, including a list of constants used
# by that bytecode. Again see inspect module docs. Anyway, inside
# the bytecode for string (which you can read by typing
# dis.dis(string) in your REPL), there's going to be an
# instruction like LOAD_CONST 1 to load the string literal onto
# the stack to pass to the print function, and that works by just
# reading co.co_consts[1]. So, that's what we want to change.
consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
for c in co.co_consts)
# Unfortunately, code objects are immutable, so we have to create
# a new one, copying over everything except for co_consts, which
# we'll replace. And the initializer has a zillion parameters.
# Try help(types.CodeType) at the REPL to see the whole list.
co = types.CodeType(
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_flags, co.co_code,
consts, co.co_names, co.co_varnames, co.co_filename,
co.co_name, co.co_firstlineno, co.co_lnotab,
co.co_freevars, co.co_cellvars)
string.__code__ = co
string()
main()
If that's not hacky enough for you: I mentioned that code objects are immutable. And of course so are strings. But deep enough under the covers, they're just pointer to some C data, right? Again, only if we're using CPython, but if we are…
First, grab my superhackyinternals project off GitHub. (It's intentionally not pip-installable because you really shouldn't be using this except to experiment with your local build of the interpreter and the like.) Then:
import ctypes
import internals
def string():
print ("This cat was scared.")
def main():
for c in string.__code__.co_consts:
if isinstance(c, str):
idx = c.find('cat')
if idx != -1:
# Too much to explain here; see superhackyinternals
# and of course the C API docs and C source.
p = internals.PyUnicodeObject.from_address(id(c))
assert p.compact and p.ascii
length = p.length
addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
buf = (ctypes.c_int8 * 3).from_address(addr + idx)
buf[:3] = b'dog'
string()
main()
As a guess:
You wanted string() to return a value the caller can use, instead of just printing something to the screen. So you need a return statement instead of a print call.
You want to loop over all of the words in that returned string, not all the characters, so you need to call split() on the string.
You want to replace stuff in each word, not in the literal "cat". So, you need to call replace on word, not on the str class. Also, replace doesn't actually change the word, it returns a new one, which you have to remember.
You want to print out each of those words.
If so:
def string():
return "This cat was scared."
def main():
for word in string().split():
word = word.replace("cat", "dog")
print(word, end=' ')
print()
main()
That fixes all of your problems. However, it can be simplified, because you don't really need word.replace here. You're swapping out the entire word, so you can just do this:
def main():
for word in string().split():
if word == "cat": word = "dog"
print(word, end=' ')
print()
But, even more simply, you can just call replace on the entire string, and you don't need a loop at all:
def main():
print(string().replace("cat", "dog"))
What I think you may actually be looking for, is the ability to call your function with a default argument:
def string(animal='cat'):
print("This {} was scared.".format(animal))
>>> string()
This cat was scared.
>>> string('dog')
This dog was scared.
If you pass nothing to string, the default value is assumed. Otherwise, the string prints with the substring you explicitly passed.

Change Letters to numbers (ints) in python

This might be python 101, but I am having a hard time changing letters into a valid integer.
The put what I am trying to do simply
char >> [ ] >> int
I created a case statement to give me a number depending on certain characters, so what I tried doing was
def char_to_int(sometext):
return {
'Z':1,
'Y':17,
'X':8,
'w':4,
}.get(sometext, '')
Which converts the letter into a number, but when I try using that number into any argument that takes ints it doesn't work.
I've tried
text_number = int(sometext)
But I get the message TypeError: int() argument must be a string or a number, not 'function'
So from there I returned the type of sometext using
print(type(sometext))
And the return type is a function.
So my question is, is there a better way to convert letters into numbers, or a better way to setup my switch/def statement
Heres the full code where its call
if sometext:
for i in range ( 0, len(sometext)):
char_to_int(sometext[i])
I've managed to get it working, ultimately what I changed was the default of the definition, I now set the definition to a variable before instead of calling it in another function, and I recoded the section I was using it.
Originally my definition looked liked this
def char_to_int(sometext):
return {
...
}.get(sometext, '')
But I changed the default to 0, so now it looks like
def char_to_int(sometext):
return {
...
}.get(sometext, 0)
The old code that called the definition looked
if sometext:
for i in range ( 0, len(sometext)):
C_T_I = int(char_to_int(sometext[i]))
I changed it to this.
if sometext:
for i in range ( 0, len(sometext)):
C_T_I = char_to_int(sometext[i])
TEXTNUM = int(C_T_I)
Hopefully this clarifies the changes. Thanks for everyone's assistance.
in the python console:
>>> type({ 'Z':1, 'Y':17, 'X':8, 'w':4, }.get('X', ''))
<class 'int'>
so as cdarke suggested, you should look at how you are calling the function.

Python 3 getattr string to name why is it bad?

I have a string : `
("Bit" + str(loopCount) ))`
loopcount is just a number that I increment in a loop.
What I want to do with that is creating some qtwidget as such :
self.Bit1 = QtGui.QLineEdit(self)
self.Bit2 = QtGui.QLineEdit(self)
self.Bit3 = QtGui.QLineEdit(self)
...and so on as many as I have in LoopCount.
To do so I need to convert my string as a name. By looking on the net I have found this getattr which seems from far the easiest way to do so :
for BitNmb in range(0, self.mySpnValue):
getattr(self, ("Bit" + str(loopCount) ))
which give me this error :
AttributeError: 'Class2' object has no attribute 'Bit1'
Which is quite frustrating as I can see in the error I obtain what I want with the "Bit1" but I have not a clue why it want to be a attribut of my class.
And no way to do simply
getattr(self, ("Bit" + str(loopCount) )) = QtGui.QLineEdit(self)
error : SyntaxError: can't assign to function call
I have read many time "do not use getattr us a dictionary" ok... but why ? Using a dictionary sound like a lot of work just for doing such a simple thing ?
Thanks
Rather than create separate, numbered attributes, use a list or dictionary. In this case, a list will do just fine:
self.bits = [QtGui.QLineEdit(self) for _ in range(3)]
creates a list of 3 QLineEdit objects.
To set attributes dynamically, you'd use the setattr() function:
setattr(self, 'Bit{}'.format(loopCount), QtGui.QLineEdit(self))

'str' object is not applicable

I have the following little function written in Python:
def encode(str):
out = ""
for i in str:
ret += str(ord(i.upper()) - 64)
return ret
Basically, what I want to do is get the number of the letter in the alphabat and concatenate it to the 'out' string. With this code I get a traceback at line 4: 'str' object is not applicable.
Could someone please explain me why it throws this error and how I can fix this? (Sorry if this was already asked once, I couldn't find it, probably also because I'm pretty new to Python and programming)
Never name your variable on the pre-defined built-in name.
In your code, str is not a built-in function. It's the variable you have used as parameter in your function.
Another problem is, you have declared out variable, and using ret which will give you error. Change out = "" to ret = "".
Don't call your variable str, you're shadowing the built-in function.
Also, you need to fix the naming of out/ret.
I personally would write this function as follows:
def encode(s):
return ''.join(str(ord(c.upper()) - 64) for c in s)
(I don't really follow what the str(ord(...)) is meant to be doing, so I've just copied it from your code.)
As the others have said, do not use str as a variable.
I suspect this is what you want though:
def encode(s):
return "".join(chr(ord(c.upper()) - 64) for c in s)
This is equivalent to:
def encode(s):
out = ""
for c in s:
ret += chr(ord(c.upper()) - 64)
return ret
You were looking for the chr() function, which converts a numerical ASCII/Unicode value into a 1-character string. Running str() would convert 5 to "5".
Also on a stylistic note, it's customary to do for c in s when iterating over a string, and for i in x when iterating over a sequence of integers.

Categories

Resources